From 186a1574386319f82f9316e85cf9d62e69b6d477 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Wed, 20 May 2020 13:46:40 -0400 Subject: [PATCH] still has bugs but at least some of them have been fixed --- .../Microsoft/Bitmap/BitmapDataFormat.cs | 109 ++++++++++++++---- .../Microsoft/Bitmap/BitmapInfoHeader.cs | 14 ++- 2 files changed, 100 insertions(+), 23 deletions(-) diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Microsoft/Bitmap/BitmapDataFormat.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Microsoft/Bitmap/BitmapDataFormat.cs index ba17f636..b67752f5 100644 --- a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Microsoft/Bitmap/BitmapDataFormat.cs +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Microsoft/Bitmap/BitmapDataFormat.cs @@ -33,13 +33,15 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap public class BitmapDataFormat : DataFormat { public const int BITMAP_HEADER_SIZE = (2 + 6 * 4 + 2 * 2 + 6 * 4); - public const int BITMAP_PALETTE_ENTRY_SIZE = 4; + + public const int BITMAP_PALETTE_ENTRY_SIZE_24BIT = 3; + public const int BITMAP_PALETTE_ENTRY_SIZE_32BIT = 4; /// /// The number of bits-per-pixel. The biBitCount member of the BITMAPINFOHEADER structure determines the /// number of bits that define each pixel and the maximum number of colors in the bitmap. /// - public BitmapBitsPerPixel PixelDepth { get; set; } = BitmapBitsPerPixel.TrueColor; + public BitmapBitsPerPixel PixelDepth { get; set; } = BitmapBitsPerPixel.DeepColor; protected override DataFormatReference MakeReferenceInternal() { @@ -57,6 +59,21 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap return dfr; } + /// + /// The horizontal resolution, in pixels-per-meter, of the target device for the bitmap. An application + /// can use this value to select a bitmap from a resource group that best matches the characteristics of + /// the current device. + /// + /// The horizontal resolution, in pixels-per-meter, of the target device for the bitmap. + public int HorizontalResolution { get; set; } = 0; + /// + /// The vertical resolution, in pixels-per-meter, of the target device for the bitmap. An application + /// can use this value to select a bitmap from a resource group that best matches the characteristics of + /// the current device. + /// + /// The vertical resolution, in pixels-per-meter, of the target device for the bitmap. + public int VerticalResolution { get; set; } = 0; + protected override void LoadInternal(ref ObjectModel objectModel) { PictureObjectModel pic = (objectModel as PictureObjectModel); @@ -82,13 +99,15 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap } } - int fileSize = br.ReadInt32(); + int fileSize = br.ReadInt32(); // 4522 short reserved1 = br.ReadInt16(); short reserved2 = br.ReadInt16(); - int offset = br.ReadInt32(); + int offset = br.ReadInt32(); // 122 BitmapInfoHeader header = BitmapInfoHeader.Load(br); - PixelDepth = header.PixelDepth; + HorizontalResolution = header.PelsPerMeterX; + VerticalResolution = header.PelsPerMeterY; + PixelDepth = header.PixelDepth; // TrueColor pic.Width = header.Width; pic.Height = header.Height; @@ -101,14 +120,62 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap // there is a palette // To read the palette, we can simply read in a block of bytes // since our array elements are guaranteed to be contiguous and in row-major order. - int paletteSize = offset - header.HeaderSize; - int numPaletteEntries = paletteSize / BITMAP_PALETTE_ENTRY_SIZE; + int paletteSize = offset - header.HeaderSize; // 122 - 108 = 14 + int bitmapPaletteEntrySize = 0; + + switch (PixelDepth) + { + case BitmapBitsPerPixel.Color256: + { + bitmapPaletteEntrySize = 4; + break; + } + case BitmapBitsPerPixel.TrueColor: + { + bitmapPaletteEntrySize = BITMAP_PALETTE_ENTRY_SIZE_24BIT; + break; + } + case BitmapBitsPerPixel.DeepColor: + { + bitmapPaletteEntrySize = BITMAP_PALETTE_ENTRY_SIZE_32BIT; + break; + } + } + int numPaletteEntries = paletteSize / bitmapPaletteEntrySize; // 14 / 4 = 3 + + if (header.UsedColorIndexCount > 0) + numPaletteEntries = header.UsedColorIndexCount; // use this, it's more accurate if available + for (int i = 0; i < numPaletteEntries; i++) { - byte b = br.ReadByte(); - byte g = br.ReadByte(); - byte r = br.ReadByte(); - byte a = br.ReadByte(); + byte b = 0, g = 0, r = 0, a = 255; + switch (PixelDepth) + { + case BitmapBitsPerPixel.TrueColor: + { + b = br.ReadByte(); + g = br.ReadByte(); + r = br.ReadByte(); + break; + } + case BitmapBitsPerPixel.Color256: + { + b = br.ReadByte(); + g = br.ReadByte(); + r = br.ReadByte(); + a = br.ReadByte(); + a = 255; + break; + } + case BitmapBitsPerPixel.DeepColor: + { + b = br.ReadByte(); + g = br.ReadByte(); + r = br.ReadByte(); + a = br.ReadByte(); + break; + } + } palette.Add(Color.FromRGBAByte(r, g, b, a)); } @@ -178,6 +245,7 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap } case BitmapBitsPerPixel.TrueColor: { + // The 24-bit pixel (24bpp) format supports 16,777,216 distinct colors and stores 1 pixel value per 3 bytes. Each pixel value defines the red, green and blue samples of the pixel (8.8.8.0.0 in RGBAX notation). Specifically, in the order: blue, green and red (8 bits per each sample). b = br.ReadByte(); // (2,2) B 204 g = br.ReadByte(); // (2,2) G 72 r = br.ReadByte(); // (2,2) R 63 @@ -189,10 +257,11 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap { // this is really black magic going on here. these aren't bitfields at all.. - a = br.ReadByte(); // (2,2) R 63 + // a = br.ReadByte(); // (2,2) R 63 b = br.ReadByte(); // (2,2) B 204 g = br.ReadByte(); // (2,2) B 204 r = br.ReadByte(); // (2,2) G 72 + a = br.ReadByte(); a = 255; } else @@ -210,6 +279,7 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap Color color = Color.FromRGBAByte(r, g, b, a); pic.SetPixel(color, x, y); } + br.Align(4); } } protected override void SaveInternal(ObjectModel objectModel) @@ -223,14 +293,15 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap int bpp = 4; switch (PixelDepth) { - case BitmapBitsPerPixel.TrueColor: + case BitmapBitsPerPixel.TrueColor: { bpp = 3; break; } } - int fileSize = 54 + (pic.Width * pic.Height * bpp); + int imageSize = (pic.Width * pic.Height * bpp) + pic.Height; + int fileSize = 54 + imageSize; bw.WriteInt32(fileSize); short reserved1 = 0; @@ -247,9 +318,9 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap header.Planes = 1; header.PixelDepth = PixelDepth; header.Compression = BitmapCompression.None; - header.ImageSize = 0; - header.PelsPerMeterX = 0; - header.PelsPerMeterY = 0; + header.ImageSize = imageSize; + header.PelsPerMeterX = HorizontalResolution; + header.PelsPerMeterY = VerticalResolution; header.UsedColorIndexCount = 0; header.RequiredColorIndexCount = 0; BitmapInfoHeader.Save(bw, header); @@ -290,17 +361,15 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap } case BitmapBitsPerPixel.DeepColor: { - bw.WriteByte(a); bw.WriteByte(b); bw.WriteByte(g); bw.WriteByte(r); + bw.WriteByte(a); break; } } } } - - bw.Flush(); } } } diff --git a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Microsoft/Bitmap/BitmapInfoHeader.cs b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Microsoft/Bitmap/BitmapInfoHeader.cs index cb1451b8..7ccf9c18 100644 --- a/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Microsoft/Bitmap/BitmapInfoHeader.cs +++ b/Plugins/UniversalEditor.Plugins.Multimedia/DataFormats/Multimedia/Picture/Microsoft/Bitmap/BitmapInfoHeader.cs @@ -95,6 +95,8 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap public static BitmapInfoHeader Load(IO.Reader br) { + long start = br.Accessor.Position; + BitmapInfoHeader header = new BitmapInfoHeader(); header.HeaderSize = br.ReadInt32(); // 40 vs. 56 header.Width = br.ReadInt32(); @@ -102,9 +104,9 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap header.Planes = br.ReadInt16(); // 1 header.PixelDepth = (BitmapBitsPerPixel)br.ReadInt16(); header.Compression = (BitmapCompression)br.ReadInt32(); - header.ImageSize = br.ReadInt32(); - header.PelsPerMeterX = br.ReadInt32(); - header.PelsPerMeterY = br.ReadInt32(); + header.ImageSize = br.ReadInt32(); // 4400 + header.PelsPerMeterX = br.ReadInt32(); // 11811 + header.PelsPerMeterY = br.ReadInt32(); // 11811 header.UsedColorIndexCount = br.ReadInt32(); header.RequiredColorIndexCount = br.ReadInt32(); @@ -112,6 +114,12 @@ namespace UniversalEditor.DataFormats.Multimedia.Picture.Microsoft.Bitmap { br.Seek(56 - header.HeaderSize, SeekOrigin.Current); } + + if (br.Accessor.Position != (start + header.HeaderSize)) + { + long offset = (start + header.HeaderSize) - br.Accessor.Position; + br.Seek(offset, SeekOrigin.Current); + } return header; } public static void Save(IO.Writer bw, BitmapInfoHeader header)