C# 从一种像素格式转换为另一种WPF

C# 从一种像素格式转换为另一种WPF,c#,bitmap,pixelformat,C#,Bitmap,Pixelformat,我知道这听起来很琐碎,但我现在已经卡住了 我有各种格式的图像作为输入。灰色16、灰色8、索引8等等。我需要的是将它们转换为RGB24格式,到目前为止我已经完成了这项工作 public WriteableBitmap ConvertToRgb(WriteableBitmap source) { <-- create the new bitmap of the same width/height as the source with specific R

我知道这听起来很琐碎,但我现在已经卡住了

我有各种格式的图像作为输入。灰色16、灰色8、索引8等等。我需要的是将它们转换为RGB24格式,到目前为止我已经完成了这项工作

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;
        }
public WriteableBitmap转换器GB(WriteableBitmap源)
{
var newBitmap=new WriteableBitmap(source.PixelWidth、source.PixelHeight、source.DpiX、source.DpiY、PixelFormats.Rgb24、source.palete);
字节[]像素=新字节[
source.PixelHeight*source.PixelWidth*
source.Format.BitsPerPixel/8];
source.CopyPixels(像素,source.PixelWidth*source.Format.BitsPerPixel/8,0);
newBitmap.WritePixels(
新的Int32Rect(0,0,newBitmap.PixelWidth,newBitmap.PixelHeight),
像素,
newBitmap.PixelWidth*newBitmap.Format.BitsPerPixel/8,
0);
返回newBitmap;
}
此方法引发异常“缓冲区大小不足”

我想这和我的WritePixels参数有关。但我不知道缓冲区的正确大小。我找不到太多的文档。任何帮助都很好


我用于转换的方法不是确定的,如果您知道更好的转换方法,请告诉我。

首先:RGB图像的默认格式是(与直觉相反)BGR24或BGRA32,用于ARGB。这是因为系统()

第二:使用这种方法时,根本不会转换像素格式。您只需获取所有像素,将它们转换为字节数组,并将这些字节用于新的像素格式-这将以完全不同的方式解释字节。因此,如果源图像位于BGRA中,并转换为RGB24,则第一个源像素的蓝色分量将被解释为第一个目标像素的红色分量,依此类推-第一个源alpha字节将被解释为第二个像素的第一个红色字节(不完全正确,但更容易理解。正确的映射是a>b,r>g,g>r,r>b2…因为颜色如何映射到与其命名方式正好相反的字节)。这也是缓冲区大小不匹配的原因,因为不同的像素格式需要不同的字节数

WriteableBitmap的CopyPixels和WritePixels完全不知道底层的PixelFormat,并完全忽略它。只有在源和目标具有完全相同的PixelFormat和调色板,或者您手动重新计算和重新排列缓冲区中的所有字节时,这才有效

您要查找的内容更简单:它被称为。这是一个位图源,特别用于更改图像的像素格式。下面这行应该可以将所有内容转换为正确的RGBA32图像(仅对RGB使用Bgr24)


所以经过多次尝试,我找到了答案

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

基本上,问题在于步幅和新像素阵列的尺寸。这是一个完全可以工作的转换功能。

如果您不需要/不想自己做图像的低级工作,有几个选项可以处理几乎所有的图像处理任务。我将尝试,主要是我将使用Gray16、Gray8和索引8格式作为我的源。我必须将它们转换为RGB,因为以后我必须重叠图像。
  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;
        }