Заменить градиент цвета в прозрачном изображении - PullRequest
0 голосов
/ 13 июля 2010

У меня есть небольшая функция, которая будет перекрашивать пиксели в растровом изображении от заданного цвета к новому заданному цвету.

Проблемы с кодом следующие:

1)функция дает результаты, которые переопределяют белые пиксели, которые не следует учитывать, поскольку у меня есть порог ... (если я не определил этот расчет неправильно)

2) Когда заданы определенные цвета, например, результаты LimeGreen wierd видны визображение, возвращаемое из функции (полагаю, это связано с переполнением типа байта в случае сложения или вычитания)

Базовое изображение, которое я использую, можно найти здесь:

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 as 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;
    }        

Что дает ....

Возможно ли то, что я пытаюсь сделать?

Надежно ли это?

В моем коде только ошибка?

Есть ли лучший способ добиться этого? "re-mapable техника "на растровых изображениях с использованием градиентов?

Спасибо за ваше время.

Ответы [ 2 ]

0 голосов
/ 14 июля 2010

Я решил, что, хотя это может быть возможно, если я изучу различные материалы, касающиеся цветовых пространств и поддерживающих их теорий. Похоже, что это займет немного больше, чем некоторое быстрое вычисление порога и нормализация к remapColor.

Я собираюсь предложить, чтобы вместо выполнения этого типа модификации растрового растрового изображения графика была изменена в векторном виде.

Процесс должен выглядеть примерно так:

Графика создается в любом наборе изображений, в котором работает дизайнер.

Они сохраняются в векторном формате, например SVG это позволит настраиваемым путям именоваться, обходиться и изменяться программно (и, если нужно, больше, чем цвет) с помощью механизма визуализации SVG (http://svg.codeplex.com/)

С помощью этого решения мы можем либо вывести SVG напрямую в браузер, если он поддерживается, и внести изменения непосредственно на клиенте, либо использовать сервер и вывести в виде PNG, когда это необходимо.

Я чувствую, что эта договоренность предоставит нам большую гибкость и более надежное решение, чем то, что я первоначально собирался взломать вместе.

Спасибо, ребята, что уделили время!

0 голосов
/ 13 июля 2010

Похоже, ваш пороговый тест неверен. Возьми линию:

remapColor.R - r <= rthreshold

Если текущий пиксель белый, то r будет 255, и тест всегда будет верным, независимо от того, какие remapColor.R и rthreshold.

Я думаю Math.Abs(remapColor.R - r) может сработать.

И вы, вероятно, правы, что ваши байтовые значения выходят за пределы. Исправление порогового теста может остановить это. В противном случае, попробуйте установить границы, чтобы увидеть, где это происходит.

...