【问题标题】:Replace Color Gradient In Transparent Image替换透明图像中的颜色渐变
【发布时间】:2010-07-13 17:28:55
【问题描述】:

我有一个小功能,可以将位图中的像素从给定颜色重新着色为新的给定颜色。

我对代码的问题如下:

1) 该函数给出的结果是重新映射白色像素,因为我有一个阈值,所以不应该考虑......(除非我定义了这个计算错误)

2) 当给出某些颜色时,例如从函数返回的图像中可以看到 LimeGreen 奇怪的结果(我相信这是由于加法或减法情况下字节类型的溢出)

我使用的基础镜像可以在这里找到:

http://www.freeimagehosting.net/uploads/c8745a9de1.png

我得到的结果可以在这里找到:

freeimagehosting.net/uploads/fa48e5a0eb.png (调用 Color.Magenta 作为 remapColor,Color.Red 作为 newColor,似乎影响了白色像素并且渐变的末端没有正确着色)

freeimagehosting.net/uploads/8faec6a569.png (调用 Color.Magenta 作为 remapColor,Color.Yellow 作为 newColor,似乎影响了白色像素并且渐变的末端没有正确着色)

freeimagehosting.net/uploads/2efd4c04aa.png(调用 Color.Magenta 作为 remapColor,Color.Blue 作为 newColor,好像渐变没有正确着色)

freeimagehosting.net/uploads/defdf04e16.png(调用 Color.Magenta 作为 remapColor,Color.Teal 作为 newColor,似乎影响了白色像素并且没有正确计算渐变)

我对这段代码的功能如下:根据建议更新

public unsafe static Bitmap RecolorImage(Bitmap original, Color remapColor, Color newColor)
    {
        Bitmap result = new Bitmap(original.Width, original.Height);

        //lock the original bitmap in memory
        BitmapData originalData = original.LockBits(
           new Rectangle(0, 0, original.Width, original.Height),
           ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

        //lock the new bitmap in memory
        BitmapData newData = result.LockBits(
           new Rectangle(0, 0, original.Width, original.Height),
           ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

        //set the number of bytes per pixel
        int pixelSize = 4;

        int rthreshold = 128;
        int gthreshold = 128;
        int bthreshold = 128;

        for (int y = 0; y < original.Height; y++)
        {
            //get the data from the original image
            byte* oRow = (byte*)originalData.Scan0 + (y * originalData.Stride);

            //get the data from the new image
            byte* nRow = (byte*)newData.Scan0 + (y * newData.Stride);

            for (int x = 0; x < original.Width; x++)
            {
                //examine the rgb values
                byte r = (byte)((oRow[x * pixelSize]));
                byte g = (byte)((oRow[x * pixelSize + 1]));
                byte b = (byte)((oRow[x * pixelSize + 2]));
                byte a = (byte)((oRow[x * pixelSize + 3]));

                if (a > 0 && 
                    Math.Abs(remapColor.R - r) <= rthreshold &&
                    Math.Abs(remapColor.B - b) <= bthreshold &&
                    Math.Abs(remapColor.G - g) <= gthreshold 
                    )
                {
                    if (newColor.R == 0)
                    {
                        r = 0;
                    }
                    else
                    {
                        if (newColor.R > remapColor.R)
                            r = (byte)(r - newColor.R);
                        else
                            r = (byte)(r + newColor.R);
                    }

                    if (newColor.G == 0)
                    {
                        g = 0;
                    }
                    else
                    {
                        if (newColor.G > remapColor.G)
                            g = (byte)(g - newColor.G);
                        else
                            g = (byte)(g + newColor.G);
                    }

                    if (newColor.B == 0)
                    {
                        b = 0;
                    }
                    else
                    {
                        if (newColor.B > remapColor.B)
                            b = (byte)(b - newColor.B);
                        else
                            b = (byte)(b + newColor.B);
                    }
                }


                //set the new image's pixel remaped pixel color
                nRow[x * pixelSize] = b; //B
                nRow[x * pixelSize + 1] = g; //G
                nRow[x * pixelSize + 2] = r; //R
                nRow[x * pixelSize + 3] = a; //A
            }
        }

        original.UnlockBits(originalData);
        result.UnlockBits(newData);


        return result;
    }        

什么给了....

我正在尝试做的事情可能吗?

可靠吗?

我的代码中只是有一个错误吗?

有没有更好的方法来使用渐变在位图上实现这种“可重新映射的技术”?

感谢您的宝贵时间。

【问题讨论】:

    标签: c# bitmap bitmapdata bitmapimage


    【解决方案1】:

    您的阈值测试似乎不正确。走线:

    remapColor.R - r <= rthreshold
    

    如果当前像素为白色,则r 将为 255,无论remapColor.Rrthreshold 是什么,测试始终为真。

    我认为Math.Abs(remapColor.R - r) 可能有用。

    而且您的字节值超出范围可能是正确的。修复阈值测试可能会阻止这种情况发生。否则,请尝试设置一些边界检查以查看它发生的位置。

    【讨论】:

    • 嘿,谢谢你的建议,但它似乎没有按预期工作。这是进行建议更改后的代码输出。 freeimagehosting.net/uploads/d5ea228622.png 调用 Color.Magenta 作为 remapColor 和 Color.Red 作为 newColor 我是不是走错了路?
    【解决方案2】:

    我已经决定,尽管如果我研究有关色彩空间的各种材料及其支持理论,这可能是可能的。这似乎比一些快速的阈值计算和对 remapColor 的规范化需要更多的时间。

    我将建议不要对光栅位图图像执行这种类型的修改,而是以矢量形式修改图形。

    流程应该是这样的:

    图形是在设计师正在使用的任何成像套件中创建的。

    它们被保存为矢量格式,例如SVG 这将允许使用 SVG 渲染引擎 (http://svg.codeplex.com/) 以编程方式命名、遍历和更改可自定义的路径(如果需要,还可以更改颜色)

    使用此解决方案,如果支持,我们可以将 SVG 直接输出到浏览器并直接在客户端上进行修改,或者使用服务器并在需要时输出为 PNG。

    我觉得这种安排将为我们提供比我最初打算一起破解的更灵活和更强大的解决方案。

    感谢大家的宝贵时间!

    【讨论】:

    • 我还可以在位图调色板中修改一组已知颜色,这会影响整个图像,并且会比在位图中设置每个像素更快!我们实际上最终使用了普通的 XAML。 Illustrator 可以使用插件导出 XAML,因此我们可以在使用插件保存后即时编辑图形!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-14
    • 2012-03-15
    • 2012-09-30
    相关资源
    最近更新 更多