Hier ist, wie ich Pixel in C# multidimensionalen Arrays manipulieren würde:
[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;
}
Nutzung:
var pixels = GetPixels(image);
if(pixels[7, 3].Red > 4)
...
Wenn Sie Pixel zu aktualisieren, sehr ähnlich Code funktioniert, außer Sie eine WritableBitmap
schaffen und verwenden Sie dieses:
public void PutPixels(WritableBitmap 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);
}
so:
var pixels = new PixelColor[4, 3];
pixel[2,2] = new PixelColor { Red=128, Blue=0, Green=255, Alpha=255 };
PutPixels(bitmap, pixels, 7, 7);
Beachten Sie, dass dieser Code Bitmaps in Bgra32 konvertiert, wenn sie in einem anderen Format eintreffen. Dies ist im Allgemeinen schnell, kann jedoch in einigen Fällen zu einem Leistungsengpass führen. In diesem Fall würde diese Technik so geändert, dass sie dem zugrunde liegenden Eingabeformat besser entspricht.
aktualisieren
BitmapSource.CopyPixels
Da kein zweidimensionales Array akzeptieren es notwendig ist, um das Array zwischen eindimensionalen und zweidimensionalen zu konvertieren. Die folgende Erweiterungsmethode sollte es tun:
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
}
Es gibt zwei Implementierungen hier: Die ersten schnell ist, aber verwendet unsicheren Code ein IntPtr zu einem Array zu bekommen (muss mit/unsicheren Option kompilieren). Der zweite ist langsamer, erfordert aber keinen unsicheren Code. Ich verwende die unsichere Version in meinem Code.
WritePixels akzeptiert zweidimensionale Arrays, daher ist keine Erweiterungsmethode erforderlich.
Für welchen Zweck NStride? Und warum fügst du 7 hinzu und dividierst durch 8 in nStride Berechnung? – Jviaches
@Jviaches Add 7 und dividiere durch 8, um richtig genug Bytes zu runden (f.i. 10 Bits werden 2 Bytes benötigen.) – erikH