Search code examples
c#bitmappixelformat

Convert from one PixelFormat to an other WPF


I know this sounds trivial, but I currently have stuck.

I have images in various formats as input. Gray16,Gray8,Indexed8 and so on. What do I need is to covert them to RGB24 format, so far I've done this

public WriteableBitmap ConvertToRgb(WriteableBitmap source)
        {
            <-- create the new bitmap of the same width/height as the source with specific RGB24 format-->
            var newBitmap = new WriteableBitmap(source.PixelWidth, source.PixelHeight, source.DpiX, source.DpiY, PixelFormats.Rgb24, source.Palette);
            
            <-- create my pixel array -->
            byte[] pixels = new byte[
                        source.PixelHeight * source.PixelWidth *
                            source.Format.BitsPerPixel / 8];
            <-- copy my original pixels into the array) --> 
            source.CopyPixels(pixels, source.PixelWidth * source.Format.BitsPerPixel / 8, 0);
            <-- write the pixels into the new image --> 
            newBitmap.WritePixels(
                 new Int32Rect(0, 0, newBitmap.PixelWidth, newBitmap.PixelHeight),
                 pixels,
                 newBitmap.PixelWidth * newBitmap.Format.BitsPerPixel/8,
                 0);

            return newBitmap;
        }

This method throws an exception "Buffer size is not sufficient"

I guess it has to do something with one of my WritePixels parameters. But I have no idea what is the right size of the buffer. I couldn't find much documentation. Any help would be nice.

The method I'm using to convert is not definitive, if you know a better way of converting please let me know.


Solution

  • So after many attempts I found the answer.

      public WriteableBitmap ConvertToRgb(WriteableBitmap source)
            {
                var newBitmap = new WriteableBitmap(source.PixelWidth, source.PixelHeight, source.DpiX, source.DpiY, PixelFormats.Rgb24, null);
    
                byte[] pixels = new byte[
                            source.PixelHeight * source.PixelWidth *
                                source.Format.BitsPerPixel / 8];
    
                source.CopyPixels(pixels, source.PixelWidth * source.Format.BitsPerPixel / 8, 0);
    
                byte[] newPixels = new byte[newBitmap.PixelWidth * newBitmap.PixelHeight * newBitmap.Format.BitsPerPixel / 8];
    
                var pixelCounter = 0;
                var colorArray = source.Palette != null ? source.Palette.Colors.ToArray() : BitmapPalettes.Gray256.Colors.ToArray();
    
                foreach (var pixel in pixels)
                {
                    newPixels[pixelCounter] = colorArray[pixel].R;
                    pixelCounter++;
                    newPixels[pixelCounter] = colorArray[pixel].G;
                    pixelCounter++;
                    newPixels[pixelCounter] = colorArray[pixel].B;
                    pixelCounter++;
                }
    
                newBitmap.WritePixels(
                     new Int32Rect(0, 0, newBitmap.PixelWidth, newBitmap.PixelHeight),
                     newPixels,
                     newBitmap.PixelWidth * newBitmap.Format.BitsPerPixel / 8,
                     0);
    
                return newBitmap;
            }
    

    Basically the problem was somwhere in the Stride I guess and the newPixel array dimensions. This is a fully working converting function.