【问题标题】:ColorBlend issue - black stripe at the endColorBlend 问题 - 最后出现黑色条纹
【发布时间】:2015-09-02 16:22:13
【问题描述】:

我想创建一个具有 7 步颜色和自定义大小的线性渐变 - 从黑色、蓝色、青色、绿色、黄色、红色到白色。我的问题是最终的位图右侧有一条黑色条纹。有谁知道这是怎么回事?

    public static List<Color> interpolateColorScheme(int size)
    {
        // create result list with for interpolated colors
        List<Color> colorList = new List<Color>();
        // use Bitmap and Graphics from bitmap
        using (Bitmap bmp = new Bitmap(size, 200))
        using (Graphics G = Graphics.FromImage(bmp))
        {
            // create empty rectangle canvas
            Rectangle rect = new Rectangle(Point.Empty, bmp.Size);
            // use LinearGradientBrush class for gradient computation
            LinearGradientBrush brush = new LinearGradientBrush
                                    (rect, Color.Empty, Color.Empty, 0, false);
            // setup ColorBlend object
            ColorBlend colorBlend = new ColorBlend();
            colorBlend.Positions = new float[7];
            colorBlend.Positions[0] = 0;
            colorBlend.Positions[1] = 1 / 6f;
            colorBlend.Positions[2] = 2 / 6f;
            colorBlend.Positions[3] = 3 / 6f;
            colorBlend.Positions[4] = 4 / 6f;
            colorBlend.Positions[5] = 5 / 6f;
            colorBlend.Positions[6] = 1;
            // blend colors and copy them to result color list
            colorBlend.Colors = new Color[7];
            colorBlend.Colors[0] = Color.Black;
            colorBlend.Colors[1] = Color.Blue;
            colorBlend.Colors[2] = Color.Cyan;
            colorBlend.Colors[3] = Color.Green;
            colorBlend.Colors[4] = Color.Yellow;
            colorBlend.Colors[5] = Color.Red;
            colorBlend.Colors[6] = Color.White;
            brush.InterpolationColors = colorBlend;
            G.FillRectangle(brush, rect);
            bmp.Save("gradient_debug_image_sarcus.png", ImageFormat.Png);
            for (int i = 0; i < size; i++) colorList.Add(bmp.GetPixel(i, 0));
            brush.Dispose();
        }

        // return interpolated colors
        return colorList;
    }

这是我的渐变:

【问题讨论】:

  • 一个可能愚蠢的解决方法是尝试 brush.WrapMode = WrapMode.TileFlipX ,但我假设您正在寻找一些关于为什么原始代码没有按照所有外观应该做的事情的见解。
  • 即使有证明图像,我也测试了您的代码,右侧没有黑线 (imgur.com/fI2uaQ5)。您发布的代码与用于生成图像的代码相比是否有任何更改? (我改变的只是保存路径和new Bitmap(size, 200) > new Bitmap(size, 10)
  • @BerndLinde 这绝对不应该有所作为,但是......你在将其更改为 10 之前尝试了 200 吗?
  • @JerryFederspiel 我做到了,结果相同,没有黑线。我降低了高度以更准确地反映样张图像
  • 如您所见,位图生成并保存在此函数中。实际上,我将图像与 new Bitmap(size, 10) 放在一起并忘记了它。不过不管怎样,位图的高度真的和这个该死的黑条有关系吗?

标签: c# gradient heatmap


【解决方案1】:

我拿了你的代码并尝试了从 2 到 ushort.MaxValue 的所有尺寸,生成渐变并从右边缘扫描以确定有多少黑色像素。

对于许多尺寸,没有黑色像素。但是,对于某些连续运行的大小,随着大小的增加,黑色像素的数量也会增加。在测试范围内大约有 2140 次这样的运行。这意味着渐变绘制中存在舍入误差。

之前遇到过此错误 (http://www.pcreview.co.uk/threads/error-on-lineargradientbrush.2165794/)。链接推荐的两种解决方案是

  1. 绘制比你需要的更大的渐变或
  2. 使用 WrapMode.TileFlipX。

该链接出错的是舍入误差并非始终只有 1 个像素;在大图像尺寸下,它可以大到 127 像素(在我测试的范围内)。绘制比您需要的更大的渐变需要您知道(或估计)使渐变需要多大。您可以尝试按(size + Math.Ceiling(size / 512.0)) / size 进行缩放,这是我测试过的图像尺寸范围的误差上限。

如果您正在寻找更简单的解决方案,指定brush.WrapMode = WrapMode.TileFlipX 将导致画笔正常绘制到渐变的(不正确的)边缘,然后反向重复渐变直到指定矩形的实际边缘。由于与矩形的大小相比,舍入误差很小,因此看起来渐变的最终颜色已扩展到矩形的边缘。从视觉上看,它看起来不错,但如果您需要非常精确的结果,它可能不适合。

【讨论】:

  • 是的!这就是解决方案,我做了进一步的测试,也发现这可能是库函数的舍入错误。无论如何,我为我的问题找到了不同的解决方案。我需要为 0-65535 范围内的不同值创建热图,并且该范围可能不同 - 这意味着,我需要调整渐变大小以匹配新范围。所以我的旧想法是每次获得新数据集时都为新范围内插颜色。现在我发现最好只插入最大范围 - 在本例中为 65535 个值 - 然后每次将其调整到所需范围。有用!无论如何,感谢您的帮助!
猜你喜欢
  • 2011-12-24
  • 2021-07-21
  • 1970-01-01
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
  • 2019-06-01
  • 2015-12-08
  • 2014-08-10
相关资源
最近更新 更多