public static void VerifyPixelSizeMatchesImageDimensionsWithPitch(ushort bitCount, int width, int height, int pixelsWithPitchSize) { if (pixelsWithPitchSize < ImageHeader.CalculatePitch(bitCount, width) * System.Math.Abs(height)) { throw new System.Exception("The size of pixels does not match the image's height time pitch"); } }
/// <summary> /// Create default indexed bitmap with palette. /// </summary> public BitmapFile(ushort bitCount, uint width, int height, Color[] palette) : this(bitCount, width, height) { if (palette.Length > 1 << bitCount) { throw new System.Exception("Unable to create bitmap. Provided palette length is greater than provided bit count."); } // Expand palette, if needed int maxSize = ImageHeader.CalcMaxIndexedPaletteSize(bitCount); if (palette.Length != maxSize) { Color[] newPalette = new Color[maxSize]; System.Array.Copy(palette, newPalette, palette.Length < newPalette.Length ? palette.Length : newPalette.Length); palette = newPalette; } // Create headers int pixelOffset = BmpHeader.SizeInBytes + ImageHeader.SizeInBytes + palette.Length * Color.SizeInBytes; int fileSize = pixelOffset + ImageHeader.CalculatePitch(bitCount, (int)width) * System.Math.Abs(height); bmpHeader = BmpHeader.Create((uint)fileSize, (uint)pixelOffset); imageHeader = ImageHeader.Create((int)width, height, bitCount); // Store data this.palette = palette; }
// Write private static void WriteHeaders(BinaryWriter seekableWriter, ushort bitCount, int width, int height, Color[] palette) { int pixelOffset = BmpHeader.SizeInBytes + ImageHeader.SizeInBytes + palette.Length * Color.SizeInBytes; int fileSize = pixelOffset + ImageHeader.CalculatePitch(bitCount, width) * System.Math.Abs(height); //if (fileSize > uint.MaxValue) { // throw new System.Exception("Bitmap size is too large to save to disk."); //} BmpHeader bmpHeader = BmpHeader.Create((uint)fileSize, (uint)pixelOffset); ImageHeader imageHeader = ImageHeader.Create(width, height, bitCount); bmpHeader.Serialize(seekableWriter); imageHeader.Serialize(seekableWriter); }
private static void WritePixels(BinaryWriter seekableWriter, byte[] pixels, int width, int height, ushort bitCount) { height = System.Math.Abs(height); int pitch = ImageHeader.CalculatePitch(bitCount, width); int bytesOfPixelsPerRow = ImageHeader.CalcPixelByteWidth(bitCount, width); byte[] padding = new byte[pitch - bytesOfPixelsPerRow]; //for (int i = 0; i+bytesOfPixelsPerRow <= pixels.Length; i += pitch) { for (int y = 0; y < height; ++y) { seekableWriter.Write(pixels, y * pitch, bytesOfPixelsPerRow); seekableWriter.Write(padding); } }
public void InvertScanLines() { imageHeader.height *= -1; byte[] invertedPixels = new byte[pixels.Length]; int pitch = imageHeader.CalculatePitch(); for (int row = AbsoluteHeight() - 1, destIndex = 0; row >= 0; --row) { int srcIndex = row * pitch; int copyLength = pitch; System.Array.Copy(pixels, srcIndex, invertedPixels, destIndex, copyLength); destIndex += copyLength; } pixels = invertedPixels; }
/// <summary> /// Create default indexed bitmap. /// </summary> public BitmapFile(ushort bitCount, uint width, int height) { VerifyIndexedImageForSerialization(bitCount); // Create headers and default palette imageHeader = ImageHeader.Create((int)width, (int)height, bitCount); palette = new Color[imageHeader.CalcMaxIndexedPaletteSize()]; pixels = new byte[imageHeader.CalculatePitch() * System.Math.Abs(height)]; int pixelOffset = BmpHeader.SizeInBytes + ImageHeader.SizeInBytes + palette.Length * Color.SizeInBytes; int bitmapFileSize = pixelOffset + pixels.Length * sizeof(byte); //if (bitmapFileSize > uint.MaxValue) { // throw new System.Exception("Maximum size of a bitmap file has been exceeded"); //} bmpHeader = BmpHeader.Create((uint)bitmapFileSize, (uint)pixelOffset); }
public void SetPixel(int x, int y, int paletteIndex) { int pitch = ImageHeader.CalculatePitch(imageHeader.bitCount, imageHeader.width); int row = y * pitch; // The row of the pixel to set int bitOffset = x * imageHeader.bitCount; // The bit offset in the row int byteOffset = bitOffset / 8; // The byte offset in the row int index = row + byteOffset; // The index to set // The bit offset relative to the byte offset // The pixels are stored with most-significant first bitOffset %= 8; bitOffset = 8 - (bitOffset + imageHeader.bitCount); // A mask for the bits to set for the byte at the "index" in the pixel array int mask = ~(~0 << imageHeader.bitCount) << bitOffset; // NOTE: // We are assuming that the pixel will not fall between bytes (e.g. 2 bits on index 1 and 2 bits on index 2). // This is a safe assumption for 1, 2, 4, and 8 bits per pixel. pixels[index] &= (byte)~mask; // Clear masked bits pixels[index] |= (byte)((paletteIndex << bitOffset) & mask); // Insert masked palette index }