这是我将使用多维数组在C#中操纵像素的方式:
[StructLayout(LayoutKind.Sequential)]
public struct PixelColor
{
public byte Blue;
public byte Green;
public byte Red;
public byte Alpha;
}
public PixelColor[,] GetPixels(BitmapSource source)
{
if(source.Format!=PixelFormats.Bgra32)
source = new FormatConvertedBitmap(source, PixelFormats.Bgra32, null, 0);
int width = source.PixelWidth;
int height = source.PixelHeight;
PixelColor[,] result = new PixelColor[width, height];
source.CopyPixels(result, width * 4, 0);
return result;
}
用法:
var pixels = GetPixels(image);
if(pixels[7, 3].Red > 4)
{
...
}
如果要更新像素,除了创建WriteableBitmap
并使用它之外,非常相似的代码也可以工作:
public void PutPixels(WriteableBitmap bitmap, PixelColor[,] pixels, int x, int y)
{
int width = pixels.GetLength(0);
int height = pixels.GetLength(1);
bitmap.WritePixels(new Int32Rect(0, 0, width, height), pixels, width*4, x, y);
}
因此:
var pixels = new PixelColor[4, 3];
pixels[2,2] = new PixelColor { Red=128, Blue=0, Green=255, Alpha=255 };
PutPixels(bitmap, pixels, 7, 7);
请注意,如果位图以其他格式到达,则此代码会将其转换为Bgra32。这通常很快,但是在某些情况下可能是性能瓶颈,在这种情况下,将修改此技术以更紧密地匹配基础输入格式。
更新资料
由于BitmapSource.CopyPixels
不接受二维数组,因此有必要在一维和二维之间转换数组。以下扩展方法可以解决问题:
public static class BitmapSourceHelper
{
#if UNSAFE
public unsafe static void CopyPixels(this BitmapSource source, PixelColor[,] pixels, int stride, int offset)
{
fixed(PixelColor* buffer = &pixels[0, 0])
source.CopyPixels(
new Int32Rect(0, 0, source.PixelWidth, source.PixelHeight),
(IntPtr)(buffer + offset),
pixels.GetLength(0) * pixels.GetLength(1) * sizeof(PixelColor),
stride);
}
#else
public static void CopyPixels(this BitmapSource source, PixelColor[,] pixels, int stride, int offset)
{
var height = source.PixelHeight;
var width = source.PixelWidth;
var pixelBytes = new byte[height * width * 4];
source.CopyPixels(pixelBytes, stride, 0);
int y0 = offset / width;
int x0 = offset - width * y0;
for(int y=0; y<height; y++)
for(int x=0; x<width; x++)
pixels[x+x0, y+y0] = new PixelColor
{
Blue = pixelBytes[(y*width + x) * 4 + 0],
Green = pixelBytes[(y*width + x) * 4 + 1],
Red = pixelBytes[(y*width + x) * 4 + 2],
Alpha = pixelBytes[(y*width + x) * 4 + 3],
};
}
#endif
}
这里有两种实现:第一种是快速的,但是使用不安全的代码将IntPtr放入数组(必须使用/ unsafe选项进行编译)。第二个比较慢,但是不需要不安全的代码。我在代码中使用了不安全的版本。
WritePixels接受二维数组,因此不需要扩展方法。
0
我有一个WPF BitmapImage,它是从.JPG文件加载的,如下所示:
我想查询特定点的颜色。例如,像素(65,32)处的RGB值是多少?
我该怎么办?我正在采用这种方法:
尽管我承认有一些猴子见,但猴子确实会继续使用此代码。无论如何,是否有一种直接的方法来处理此字节数组以转换为RGB值?