From eb7d60b681b2c5ad49de2066e6bc4a9c440458bc Mon Sep 17 00:00:00 2001 From: popow Date: Sat, 15 Dec 2018 16:18:55 +0100 Subject: [PATCH 1/5] added parsing of the OS22XBITMAPHEADER short variant (16 bytes) --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 5 ++++ src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs | 24 +++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index ef3ca24ee..f6eb78ea9 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -510,6 +510,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp // 12 bytes this.infoHeader = BmpInfoHeader.ParseCore(buffer); } + else if (headerSize == BmpInfoHeader.Os2Short) + { + // 16 bytes + this.infoHeader = BmpInfoHeader.ParseOs2Short(buffer); + } else if (headerSize >= BmpInfoHeader.Size) { // >= 40 bytes diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs index 4dd63a962..a32f806a9 100644 --- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs @@ -26,6 +26,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// public const int CoreSize = 12; + /// + /// Defines the size of the short variant of the OS22XBITMAPHEADER data structure in the bitmap file. + /// + public const int Os2Short = 16; + /// /// Defines the size of the biggest supported header data structure in the bitmap file. /// @@ -143,7 +148,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Parses the BITMAPCOREHEADER consisting of the headerSize, width, height, planes, and bitsPerPixel fields (12 bytes). /// - /// The data to parse, + /// The data to parse. /// Parsed header /// public static BmpInfoHeader ParseCore(ReadOnlySpan data) @@ -156,6 +161,23 @@ namespace SixLabors.ImageSharp.Formats.Bmp bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(10, 2))); } + /// + /// Parses a short variant of the OS22XBITMAPHEADER. It is identical to the BITMAPCOREHEADER, except that the width and height + /// are 4 bytes instead of 2. + /// + /// The data to parse. + /// Parsed header + /// + public static BmpInfoHeader ParseOs2Short(ReadOnlySpan data) + { + return new BmpInfoHeader( + headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)), + width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)), + height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)), + planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)), + bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2))); + } + public unsafe void WriteTo(Span buffer) { ref BmpInfoHeader dest = ref Unsafe.As(ref MemoryMarshal.GetReference(buffer)); From c25c34b4768a15f32f2c8c92b9b276d4f61df5ef Mon Sep 17 00:00:00 2001 From: popow Date: Sat, 15 Dec 2018 17:20:48 +0100 Subject: [PATCH 2/5] added unit test for decoding OS2 bitmap with 16 bytes header --- .../Formats/Bmp/BmpDecoderTests.cs | 30 +++++++++++++----- tests/Images/Input/Bmp/pal8os2v2-16.bmp | Bin 0 -> 9246 bytes 2 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 tests/Images/Input/Bmp/pal8os2v2-16.bmp diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index 5f2de9f51..dc858f950 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -88,19 +88,33 @@ namespace SixLabors.ImageSharp.Tests } } - [Theory] - [MemberData(nameof(RatioFiles))] - public void Identify_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) + [Fact] + public void DecodeOs22XShortHeader_VeryfyDimensions() { + string imagePath = @"Bmp/pal8os2v2-16.bmp"; var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { var decoder = new BmpDecoder(); - IImageInfo image = decoder.Identify(Configuration.Default, stream); - ImageMetaData meta = image.MetaData; - Assert.Equal(xResolution, meta.HorizontalResolution); - Assert.Equal(yResolution, meta.VerticalResolution); - Assert.Equal(resolutionUnit, meta.ResolutionUnits); + using (Image image = decoder.Decode(Configuration.Default, stream)) + { + Assert.Equal(127, image.Width); + Assert.Equal(64, image.Height); + } + } + } + + [Fact] + public void IdentifyOs22XShortHeader_VeryfyDimensions() + { + string imagePath = @"Bmp/pal8os2v2-16.bmp"; + var testFile = TestFile.Create(imagePath); + using (var stream = new MemoryStream(testFile.Bytes, false)) + { + IImageInfo imageInfo = Image.Identify(stream); + Assert.Equal(127, imageInfo.Width); + Assert.Equal(64, imageInfo.Height); + Assert.Equal(8, imageInfo.PixelType.BitsPerPixel); } } } diff --git a/tests/Images/Input/Bmp/pal8os2v2-16.bmp b/tests/Images/Input/Bmp/pal8os2v2-16.bmp new file mode 100644 index 0000000000000000000000000000000000000000..95a1d2345aa1dd29cd03b29d0ea50879e24be9e3 GIT binary patch literal 9246 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 z zs~Ja*;NRX)1BMtW8i4-?@dx0T%uf8J{W5u-xw5n}Ha7Od*f`_vUHm7fXh4#oub-Qn zGs!D^p65PF{>9w?)!hF_xc}R^|NEgIN+p+5Y!ILrP!#_sKZH=seM>#tla5hIA*DT3Hc)@@L!=f9U}J(@A~3 z_=|DAm1IAeu(r_tg8;Mua1Mas_M!fN4GDcJwF&^$%TDa0`6oF4odnQH^KWqeQ?x&| zvNTWop8>D{z)JuYCzDgZC8c|EJ^qrvWG}g|EjcA>SvmP@f1N)8Wcbs8HGew5puF*D`QhW|_Q7k@gCT9)gz zzs@~h2gDzM>Vw?>EzRd>e}Dh*&@k;!3BZTdwezp@m-ed;$N@0<12F!K`+woyOWHp* zwU}I_{V4&MTQ%O=e*LEjBAx%yP4gFfrt!yK`9HxQyVR=5|JRS_FXlS=+@IE#EyY_t z!~bB*k(QQo&F9Wt>mME_fLQ{V6@L}L2?fx3k$Llm1R(7PVP$oGer*01{GTn{U08T| z@8!!^Q;UlPuuK5U_`5h~El^y&_?Ed@{+$1;{L}uFU-MTT*d%|>e@6b(%AW6)#y;Z_ z|1F(`QMf_XP$Nyi$=rc0?FMhSI|Kz6l(*fmA{)`3jUqB!K-xkql@cL%iCn?UNKJ5pf z1pvyo44)gmM)_e?9st#T0-(GCxOwsBP0A|(2|%?UfCT_3zp(gn@fGD4Re1m;d%gHx JfN{>U{tG?^9{2zN literal 0 HcmV?d00001 From 377a2e50a2e8c1afb0c53f4cdfe1ac4aa9f18648 Mon Sep 17 00:00:00 2001 From: popow Date: Sun, 16 Dec 2018 21:36:29 +0100 Subject: [PATCH 3/5] Os2Short -> Os22ShortSize --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 4 ++-- src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index f6eb78ea9..2226a1ec9 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -510,10 +510,10 @@ namespace SixLabors.ImageSharp.Formats.Bmp // 12 bytes this.infoHeader = BmpInfoHeader.ParseCore(buffer); } - else if (headerSize == BmpInfoHeader.Os2Short) + else if (headerSize == BmpInfoHeader.Os22ShortSize) { // 16 bytes - this.infoHeader = BmpInfoHeader.ParseOs2Short(buffer); + this.infoHeader = BmpInfoHeader.ParseOs22Short(buffer); } else if (headerSize >= BmpInfoHeader.Size) { diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs index a32f806a9..5177bc325 100644 --- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Defines the size of the short variant of the OS22XBITMAPHEADER data structure in the bitmap file. /// - public const int Os2Short = 16; + public const int Os22ShortSize = 16; /// /// Defines the size of the biggest supported header data structure in the bitmap file. @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// The data to parse. /// Parsed header /// - public static BmpInfoHeader ParseOs2Short(ReadOnlySpan data) + public static BmpInfoHeader ParseOs22Short(ReadOnlySpan data) { return new BmpInfoHeader( headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)), From 0f5df545be7d314f25fb6cb3d96bbf4c382ed053 Mon Sep 17 00:00:00 2001 From: popow Date: Tue, 18 Dec 2018 20:29:21 +0100 Subject: [PATCH 4/5] updated unit test to be in line with the other tests --- .../Formats/Bmp/BmpDecoderTests.cs | 33 +++++-------------- tests/ImageSharp.Tests/TestImages.cs | 1 + 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index dc858f950..2d6a5474d 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -11,6 +11,7 @@ using Xunit; namespace SixLabors.ImageSharp.Tests { using SixLabors.ImageSharp.MetaData; + using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; using static TestImages.Bmp; public class BmpDecoderTests @@ -88,33 +89,15 @@ namespace SixLabors.ImageSharp.Tests } } - [Fact] - public void DecodeOs22XShortHeader_VeryfyDimensions() - { - string imagePath = @"Bmp/pal8os2v2-16.bmp"; - var testFile = TestFile.Create(imagePath); - using (var stream = new MemoryStream(testFile.Bytes, false)) - { - var decoder = new BmpDecoder(); - using (Image image = decoder.Decode(Configuration.Default, stream)) - { - Assert.Equal(127, image.Width); - Assert.Equal(64, image.Height); - } - } - } - - [Fact] - public void IdentifyOs22XShortHeader_VeryfyDimensions() + [Theory] + [WithFile(Os2v2Short, PixelTypes.Rgba32)] + public void BmpDecoder_CanDecode_Os2v2XShortHeader(TestImageProvider provider) + where TPixel : struct, IPixel { - string imagePath = @"Bmp/pal8os2v2-16.bmp"; - var testFile = TestFile.Create(imagePath); - using (var stream = new MemoryStream(testFile.Bytes, false)) + using (Image image = provider.GetImage(new BmpDecoder())) { - IImageInfo imageInfo = Image.Identify(stream); - Assert.Equal(127, imageInfo.Width); - Assert.Equal(64, imageInfo.Height); - Assert.Equal(8, imageInfo.PixelType.BitsPerPixel); + image.DebugSave(provider, "png"); + image.CompareToOriginal(provider); } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 1144a3f7c..8e226d337 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -201,6 +201,7 @@ namespace SixLabors.ImageSharp.Tests public const string Bit16 = "Bmp/test16.bmp"; public const string Bit16Inverted = "Bmp/test16-inverted.bmp"; public const string Bit32Rgb = "Bmp/rgb32.bmp"; + public const string Os2v2Short = "Bmp/pal8os2v2-16.bmp"; public static readonly string[] All = { From 7e55d2277f405d8243c881187b411e5833fb88de Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 20 Dec 2018 20:30:07 +1100 Subject: [PATCH 5/5] Disable comparison since the reference decoders cannpt decode the image. --- tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index 2d6a5474d..98c3c194d 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -11,7 +11,6 @@ using Xunit; namespace SixLabors.ImageSharp.Tests { using SixLabors.ImageSharp.MetaData; - using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; using static TestImages.Bmp; public class BmpDecoderTests @@ -97,7 +96,10 @@ namespace SixLabors.ImageSharp.Tests using (Image image = provider.GetImage(new BmpDecoder())) { image.DebugSave(provider, "png"); - image.CompareToOriginal(provider); + + // TODO: Neither System.Drawing not MagickReferenceDecoder + // can correctly decode this file. + // image.CompareToOriginal(provider); } } }