public static void Write <TImage>(ImageBinWriter state, TImage image) where TImage : IPixelRowProvider { // we only support RGB and RGBA, no palette indexing // TODO: support for palette indexing if (state == null) { throw new ArgumentNullException(nameof(state)); } if (image == null) { throw new ArgumentNullException(nameof(image)); } image.ThrowIfCancelled(); int bytesPerPixel = image.Components == 4 ? 4 : 3; int bitDepth = bytesPerPixel * 8; int pad = (-image.Width * bytesPerPixel) & bytesPerPixel; int compressionHeaders = image.Components == 4 ? 17 : 0; int extraPad = compressionHeaders * sizeof(int); // extra bytes for compression headers int dataSize = (image.Width * bytesPerPixel + pad) * image.Height; int dibHeaderLen = 40 + extraPad; int fileSize = 14 + dibHeaderLen + dataSize; int dataOffset = 14 + dibHeaderLen; int compression = image.Components == 4 ? 3 : 0; // 3 == bitfields | 0 == no compression Span <long> header = stackalloc long[] { // BMP header: 'B', 'M', fileSize, 0, 0, dataOffset, // DIB header: dibHeaderLen, image.Width, image.Height, 1, bitDepth, compression, dataSize, 0, 0, 0, 0, // Data needed for 32bit bitmaps: 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, // RGBA masks 0x206E6957, // little-endian (value equal to string "Win ") 0, 0, 0, 0, 0, 0, 0, 0, 0, // colorspace endpoints (unused) 0, 0, 0 // RGB gamma (unused) }; int alphaDir = image.Components == 4 ? 1 : 0; string format = "11 4 22 44 44 22 444444 " + // base header "4444 4 444444444 444"; // compression header int headerCount = 17 + compressionHeaders; ImageWriteHelpers.OutFile( state, image, true, -1, true, alphaDir, pad, format, header.Slice(0, headerCount)); } }
public static void Write <TImage>(ImageBinWriter state, TImage image, bool useRLE) where TImage : IPixelRowProvider { if (state == null) { throw new ArgumentNullException(nameof(state)); } if (image == null) { throw new ArgumentNullException(nameof(image)); } int width = image.Width; int height = image.Height; int comp = image.Components; if ((height < 0) || (width < 0)) { throw new ArgumentException("Invalid image dimensions.", nameof(state)); } image.ThrowIfCancelled(); int hasAlpha = (comp == 2 || comp == 4) ? 1 : 0; int colorbytes = hasAlpha != 0 ? comp - 1 : comp; int format = colorbytes < 2 ? 3 : 2; if (!useRLE) { Span <long> headerValues = stackalloc long[] { 0, 0, format, 0, 0, 0, 0, 0, width, height, (colorbytes + hasAlpha) * 8, hasAlpha * 8 }; ImageWriteHelpers.OutFile( state, image, true, -1, false, hasAlpha, 0, "111 221 2222 11", headerValues); } else { Span <long> headerValues = stackalloc long[] { 0, 0, format + 8, 0, 0, 0, 0, 0, width, height, (colorbytes + hasAlpha) * 8, hasAlpha * 8 }; ImageWriteHelpers.WriteFormat(state, "111 221 2222 11", headerValues); Span <byte> rowScratch = new byte[width * comp].AsSpan(); Span <byte> outBuffer = stackalloc byte[4]; for (int y = height; y-- > 0;) { image.GetByteRow(y, rowScratch); int len; for (int x = 0; x < width; x += len) { Span <byte> begin = rowScratch[(x * comp)..];