/// <summary> /// Create new Bitmap object /// </summary> /// <param name="width"></param> /// <param name="height"></param> /// <param name="pixelData"></param> /// <param name="bitsPerPixel"></param> public Bitmap(int width, int height, byte[] pixelData, BitsPerPixelEnum bitsPerPixel = BitsPerPixelEnum.RGB24) { this.Width = width; this.Height = height; this.PixelData = pixelData ?? throw new ArgumentNullException(nameof(pixelData)); this.BitsPerPixelEnum = bitsPerPixel; var rawImageSize = BytesPerRow * height; // Are we receiving proper byte[] size ? if (pixelData.Length != width * height * BytesPerPixel) { throw new ArgumentOutOfRangeException($"{nameof( pixelData )} has invalid size."); } if (bitsPerPixel == BitsPerPixelEnum.RGB24) { this.InfoHeaderBytes = new BitmapInfoHeader(width, height, bitsPerPixel, rawImageSize).HeaderInfoBytes; } if (bitsPerPixel == BitsPerPixelEnum.RGBA32) { this.InfoHeaderBytes = new BitmapInfoHeaderRGBA(width, height, bitsPerPixel, rawImageSize).HeaderInfoBytes; } this.FileHeader = new BitmapFileHeader(width, height, bitsPerPixel, rawImageSize); }
/// <summary> /// Create header and calculate file size depending on input data /// </summary> /// <param name="width"></param> /// <param name="height"></param> /// <param name="bitsPerPixel"></param> /// <param name="rawImageSize">Depends on row padding and number of rows</param> public BitmapFileHeader(int width = 1, int height = 1, BitsPerPixelEnum bitsPerPixel = BitsPerPixelEnum.RGB24, int rawImageSize = 0) { //if (System.BitConverter.IsLittleEndian) var infoHeaderSize = bitsPerPixel == BitsPerPixelEnum.RGB24 ? BitmapInfoHeader.SizeInBytes : BitmapInfoHeaderRGBA.SizeInBytes; FileSize = (uint)(BitmapFileHeader.BitmapFileHeaderSizeInBytes + infoHeaderSize + rawImageSize); PixelDataOffset = (uint)(BitmapFileHeader.BitmapFileHeaderSizeInBytes + infoHeaderSize); //infoHeader = new BitmapInfoHeader( Width, Height, BitsPerPixel: BitsPerPixel, rawImageSize: rawImageSize ); }
#pragma warning restore CS0414 /// <summary> /// DIB header (bitmap information header) /// This is standard Windows BITMAPINFOHEADER as described here https://en.wikipedia.org/wiki/BMP_file_format#Bitmap_file_header /// </summary> public BitmapInfoHeaderRGBA(int width, int height, BitsPerPixelEnum bitsPerPixel = BitsPerPixelEnum.RGB24, int rawImageSize = 0, int horizontalPixelPerMeter = 3780, int verticalPixelPerMeter = 3780, CompressionMethod compressionMethod = CompressionMethod.BI_BITFIELDS) : base(width, height, bitsPerPixel, rawImageSize, horizontalPixelPerMeter, verticalPixelPerMeter, compressionMethod) { //this.Width = width; //this.Height = height; //this.BitsPerPixel = bitsPerPixel; //this.CompressionMethod = (uint) CompressionMethod.BI_RGB; //this.ImageSize = rawImageSize; //this.HorizontalPixelPerMeter = horizontalPixelPerMeter; // 96 DPI //this.VerticalPixelPerMeter = verticalPixelPerMeter; // 96 DPI }
#pragma warning restore CS0414 /// <summary> /// DIB header (bitmap information header) /// This is standard Windows BITMAPINFOHEADER as described here https://en.wikipedia.org/wiki/BMP_file_format#Bitmap_file_header /// </summary> /// <param name="width"></param> /// <param name="height"></param> /// <param name="bitsPerPixel"></param> /// <param name="rawImageSize"></param> public BitmapInfoHeader(int width, int height, BitsPerPixelEnum bitsPerPixel = BitsPerPixelEnum.RGB24, int rawImageSize = 0, int horizontalPixelPerMeter = 3780, int verticalPixelPerMeter = 3780, CompressionMethod compressionMethod = CompressionMethod.BI_RGB) { this.Width = width; this.Height = height; this.BitsPerPixel = bitsPerPixel; this.CompressionMethod = compressionMethod; // CompressionMethod.BI_RGB; this.ImageSize = rawImageSize; this.HorizontalPixelPerMeter = horizontalPixelPerMeter; // 96 DPI this.VerticalPixelPerMeter = verticalPixelPerMeter; // 96 DPI this.nuberOfColorsInPallete = 0; // ignored this.numberOfImportantColorsUsed = 0; // ignored }
/// <summary> /// Check if padding is required (extra bytes for a row). /// </summary> /// <param name="width">Width of image</param> /// <param name="bitsPerPixel">Bits per pixels to calculate actual byte requirement</param> /// <param name="bytesPerRow">BMP required bytes per row</param> /// <returns>True/false if we need to allocate extra bytes (for BMP saving) for padding</returns> public static bool IsPaddingRequired(int width, BitsPerPixelEnum bitsPerPixel, int bytesPerRow) => bytesPerRow != width * (int)bitsPerPixel / 8;
/// <summary> /// BMP file must be aligned at 4 bytes at the end of row /// </summary> /// <param name="width">Image Width</param> /// <param name="bitsPerPixel">Bits per pixel</param> /// <returns>How many bytes BMP requires per row</returns> public static int RequiredBytesPerRow(int width, BitsPerPixelEnum bitsPerPixel) => (int)Math.Ceiling((decimal)(width * (int)bitsPerPixel) / 32) * 4;