Skip to content

Commit 707f248

Browse files
authored
Fix parsing of bitmap resources (#156)
1 parent 11583e1 commit 707f248

File tree

3 files changed

+82
-38
lines changed

3 files changed

+82
-38
lines changed

MetadataProcessor.Shared/Tables/nanoResourcesTable.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,16 @@ public void Write(
7979

8080
if (kind == ResourceKind.Bitmap)
8181
{
82+
// Bitmaps at this stage are byte arrays with a 4 byte length prefix
8283
using (var stream = new MemoryStream(resourceData.Length))
8384
{
84-
var bitmapProcessor = new nanoBitmapProcessor((Bitmap)resource.Value);
85+
byte[] subset = new byte[resourceData.Length - 4];
86+
Array.Copy(resourceData, 4, subset, 0, subset.Length);
87+
MemoryStream ms = new MemoryStream(subset);
88+
89+
Bitmap recreatedBitmap = new Bitmap(ms);
90+
91+
var bitmapProcessor = new nanoBitmapProcessor(recreatedBitmap);
8592
bitmapProcessor.Process(writer.GetMemoryBasedClone(stream));
8693
resourceData = stream.ToArray();
8794
}
@@ -165,12 +172,23 @@ private static ResourceKind GetResourceKind(
165172
return ResourceKind.String;
166173
}
167174

168-
if (resourceType.StartsWith("System.Drawing.Bitmap"))
175+
// Check if the data is a bitmap, failure just means it is not.
176+
try
169177
{
178+
byte[] subset = new byte[resourceData.Length - 4];
179+
Array.Copy(resourceData, 4,subset, 0,subset.Length);
180+
MemoryStream ms = new MemoryStream(subset);
181+
182+
Bitmap bitmapImage = Image.FromStream(ms) as Bitmap;
170183
return ResourceKind.Bitmap;
171184
}
185+
catch
186+
{
187+
// Ignore error if not a bitmap
188+
}
172189

173-
using(var stream = new MemoryStream(resourceData))
190+
// None of the above, assume binary
191+
using (var stream = new MemoryStream(resourceData))
174192
using (var reader = new BinaryReader(stream))
175193
{
176194
var size = reader.ReadUInt32();

MetadataProcessor.Shared/Utility/nanoBitmapProcessor.cs

Lines changed: 61 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// See LICENSE file in the project root for full license information.
55
//
66

7+
using System;
78
using System.Drawing;
89
using System.Drawing.Imaging;
910

@@ -13,68 +14,99 @@ internal sealed class nanoBitmapProcessor
1314
{
1415
private readonly Bitmap _bitmap;
1516

16-
public nanoBitmapProcessor(
17+
// Bitmap types supported by the native code found in "CLR_GFX_BitmapDescription"
18+
private enum BitmapType
19+
{
20+
// Format of bitmap is 16-bit rgb565 format
21+
nanoCLRBitmap = 0,
22+
// Format of bitmap is GIF
23+
Gif = 1,
24+
// Format of bitmap JPEG
25+
Jpeg = 2,
26+
// Format of bitmap is Windows bitmap
27+
// NOTE: There is support for compressed bitmaps in the native code, but the conversion of resources to Format16bppRgb565
28+
// by the metadata processor eliminates this code being used.
29+
WindowsBmp = 3,
30+
// Not supported or unknown bitmap type
31+
UnKnown = 255
32+
}
33+
34+
public nanoBitmapProcessor(
1735
Bitmap bitmap)
1836
{
1937
_bitmap = bitmap;
2038
}
2139

22-
public void Process(
40+
public void Process(
2341
nanoBinaryWriter writer)
2442
{
43+
// CLR_GFX_BitmapDescription header as required by the native side
2544
writer.WriteUInt32((uint)_bitmap.Width);
2645
writer.WriteUInt32((uint)_bitmap.Height);
2746

2847
writer.WriteUInt16(0x00); // flags
2948

3049
var nanoImageFormat = GetnanoImageFormat(_bitmap.RawFormat);
3150

51+
// For GIF and JPEG, we do not convert
3252
if (nanoImageFormat != 0)
3353
{
34-
writer.WriteByte(0x01); // bpp
35-
writer.WriteByte(nanoImageFormat);
54+
writer.WriteByte(0x01);
55+
writer.WriteByte((byte)nanoImageFormat);
3656
_bitmap.Save(writer.BaseStream, _bitmap.RawFormat);
3757
}
3858
else
3959
{
40-
writer.WriteByte(0x10); // bpp
41-
writer.WriteByte(nanoImageFormat);
60+
byte bitsPerPixel = 16;
61+
writer.WriteByte(bitsPerPixel);
62+
writer.WriteByte((byte)nanoImageFormat);
4263

43-
var rect = new Rectangle(Point.Empty, _bitmap.Size);
44-
using (var convertedBitmap =
45-
_bitmap.Clone(new Rectangle(Point.Empty, _bitmap.Size),
46-
PixelFormat.Format16bppRgb565))
64+
try
4765
{
48-
var bitmapData = convertedBitmap.LockBits(
49-
rect, ImageLockMode.ReadOnly, convertedBitmap.PixelFormat);
50-
51-
var buffer = new short[bitmapData.Stride * convertedBitmap.Height / sizeof(short)];
52-
System.Runtime.InteropServices.Marshal.Copy(
53-
bitmapData.Scan0, buffer, 0, buffer.Length);
54-
55-
convertedBitmap.UnlockBits(bitmapData);
56-
foreach (var item in buffer)
66+
Bitmap clone = new Bitmap(_bitmap.Width, _bitmap.Height, PixelFormat.Format16bppRgb565);
67+
using (Graphics gr = Graphics.FromImage(clone))
5768
{
58-
writer.WriteInt16(item);
69+
gr.DrawImageUnscaled(_bitmap, 0, 0);
5970
}
71+
72+
Rectangle rect = new Rectangle(0, 0, clone.Width, clone.Height);
73+
BitmapData bitmapData = clone.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format16bppRgb565);
74+
75+
// Format16bppRgb565 == 2 bytes per pixel
76+
byte[] data = new byte[clone.Width * clone.Height * 2];
77+
78+
System.Runtime.InteropServices.Marshal.Copy(bitmapData.Scan0, data, 0, data.Length);
79+
clone.UnlockBits(bitmapData);
80+
writer.WriteBytes(data);
81+
82+
}
83+
catch
84+
{
85+
throw new NotSupportedException($"PixelFormat ({_bitmap.PixelFormat.ToString()}) could not be converted to Format16bppRgb565.");
6086
}
6187
}
6288
}
6389

64-
private byte GetnanoImageFormat(
90+
private BitmapType GetnanoImageFormat(
6591
ImageFormat rawFormat)
6692
{
67-
if (rawFormat.Equals(ImageFormat.Gif))
93+
// Any windows bitmap format is marked for conversion to nanoCLRBitmap ( i.e. Format16bppRgb565 )
94+
if (rawFormat.Equals(ImageFormat.Bmp))
6895
{
69-
return 1;
96+
return BitmapType.nanoCLRBitmap;
7097
}
71-
72-
if (rawFormat.Equals(ImageFormat.Jpeg))
98+
else if (rawFormat.Equals(ImageFormat.Gif))
7399
{
74-
return 2;
100+
return BitmapType.Gif;
101+
}
102+
else if (rawFormat.Equals(ImageFormat.Jpeg))
103+
{
104+
return BitmapType.Jpeg;
105+
}
106+
else
107+
{
108+
return BitmapType.UnKnown;
75109
}
76-
77-
return 0;
78110
}
79111
}
80-
}
112+
}

MetadataProcessor.Tests/Core/Utility/nanoBitmapProcessorTests.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@ namespace nanoFramework.Tools.MetadataProcessor.Tests.Core.Utility
1111
[TestClass]
1212
public class nanoBitmapProcessorTests
1313
{
14-
[TestMethod]
15-
public void ProcessBmpTest()
16-
{
17-
DoProcessTest("bmp.bmp", "bmp_expected_result.bin");
18-
}
19-
2014
[TestMethod]
2115
public void ProcessJpegTest()
2216
{

0 commit comments

Comments
 (0)