Программно заменить прозрачные области на изображении белой заливкой? - PullRequest
2 голосов
/ 24 марта 2011

У меня есть изображение PNG, над которым я работаю через API System.Drawing в .NET. Он имеет большие прозрачные области, и я хотел бы заменить прозрачные области белой заливкой, чтобы на изображении не было прозрачных областей. Достаточно просто в программе для редактирования изображений ... но до сих пор я не добился успеха в C #.

Может кто-нибудь дать мне несколько советов?

Ответы [ 4 ]

3 голосов
/ 25 марта 2011

Мой пример:

    public void FillPngWhite(Bitmap bmp)
    {
        if (bmp.PixelFormat != PixelFormat.Format32bppArgb)
            throw new ApplicationException("Not supported PNG image!");

        // Lock the bitmap's bits.  
        Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
        BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);

        // Get the address of the first line.
        IntPtr ptr = bmpData.Scan0;

        // Declare an array to hold the bytes of the bitmap.
        int bytes  = Math.Abs(bmpData.Stride) * bmp.Height;
        byte[] rgbaValues = new byte[bytes];

        // Copy the RGB values into the array.
        System.Runtime.InteropServices.Marshal.Copy(ptr, rgbaValues, 0, bytes);

        // array consists of values RGBARGBARGBA

        for (int counter = 0; counter < rgbaValues.Length; counter += 4)
        {
            double t = rgbaValues[counter + 3]/255.0; // transparency of pixel between 0 .. 1 , easier to do math with this
            double rt = 1 - t; // inverted value of transparency

            // C = C * t + W * (1-t) // alpha transparency for your case C-color, W-white (255)
            // same for each color
            rgbaValues[counter] = (byte) (rgbaValues[counter]*t + 255*rt); // R color
            rgbaValues[counter + 1] = (byte)(rgbaValues[counter + 1] * t + 255 * rt); // G color
            rgbaValues[counter + 2] = (byte)(rgbaValues[counter + 2] * t + 255 * rt); // B color

            rgbaValues[counter + 3] = 255; // A = 255 => no transparency 
        }
        // Copy the RGB values back to the bitmap
        System.Runtime.InteropServices.Marshal.Copy(rgbaValues, 0, ptr, bytes);

        // Unlock the bits.
        bmp.UnlockBits(bmpData);
    }

Это другая причина:

Я использую LockBits вместо GetPixel и SetPixel.Это намного быстрее, но немного сложнее для понимания.Это немного измененный пример из: MSDN

Я принимаю во внимание реальное значение aplha, как я сказал в комментарии к вашему вопросу.Это сделает черный с прозрачностью 50% (128) похожим на серый вместо черного.Причина этого в том, чтобы «заменить альфу белым в графическом редакторе». Я представляю себе создание нового слоя под вашим изображением, заполненного белым, а затем сглаживание обоих слоев вместе.Этот пример будет иметь тот же эффект.

2 голосов
/ 24 марта 2011

Я не уверен, как определить прозрачный пиксель. Я знаю, что если Alpha равен 0, он полностью прозрачен, а если 255 - непрозрачен. Я не уверен, стоит ли вам проверять альфа == 0 или альфа! = 255; если вы можете попробовать и дать мне отзыв, который был бы полезен.

С MSDN

Альфа-компонент определяет прозрачность цвета: 0 полностью прозрачный, а 255 полностью непрозрачный. Аналогично, значение 255 представляет непрозрачный цвет. A значение от 1 через 254 представляет собой полупрозрачный цвет. Цвет становится более непрозрачным при приближении А 255.

    void  Foo(Bitmap image)
    {
        for (int y = 0; y < image.Height; ++y)
        {
            for (int x = 0; x < image.Width; ++x)
            {
                // not very sure about the condition.                   
                if (image.GetPixel(x, y).A != 255)
                {
                    image.SetPixel(x,y,Color.White);
                }
            }
        }

    }
0 голосов
/ 25 марта 2011

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

0 голосов
/ 24 марта 2011

Получив дескриптор растрового объекта, просто сделайте что-то вроде:

Bitmap yourImage = HOWEVER YOU LOAD YOUR IMAGE;
int width = YOUR IMAGE WIDTH;
int height = YOUR IMAGE HEIGHT;

Color c;
Color white = new Color(255,255,255,255)
for(int w = 0; w < width; w++)
for(int h = 0; h < height; h++)
{
    c = yourImage.GetPixel(w,h);
    yourImage.SetPixel(w,h, ((((short)(c.A)) & 0x00FF) <= 0)? white:c); //replace 0 here with some higher tolerance if needed
}
...