Skip to content

Commit 29fed65

Browse files
committed
Drawing of 24-bit DIB to png
1 parent 0226777 commit 29fed65

File tree

4 files changed

+90
-7
lines changed

4 files changed

+90
-7
lines changed

src/SharpEmf.Svg/BitmapUtils.cs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using SharpEmf.WmfTypes.Bitmap;
2+
using SkiaSharp;
3+
4+
namespace SharpEmf.Svg;
5+
6+
internal static class BitmapUtils
7+
{
8+
public static unsafe string DibToPngBase64(byte[] dibData, BitmapInfoHeader bitmapHeader)
9+
{
10+
// TODO: this assumes that the DIB is 24-bit RGB, handle other cases
11+
12+
using var bitmap = new SKBitmap();
13+
14+
var width = bitmapHeader.Width;
15+
var height = bitmapHeader.Height;
16+
17+
var rgbaData = DibToRgba(dibData, bitmapHeader);
18+
19+
fixed(byte* rgbaDataPtr = rgbaData)
20+
{
21+
var rgbaDataPtr2 = (IntPtr)rgbaDataPtr;
22+
bitmap.InstallPixels(new SKImageInfo(width, height, SKColorType.Rgba8888, SKAlphaType.Unpremul), rgbaDataPtr2, width * 4);
23+
}
24+
25+
using var pngData = bitmap.Encode(SKEncodedImageFormat.Png, 100);
26+
var resultBase64Str = Convert.ToBase64String(pngData.Span);
27+
28+
return resultBase64Str;
29+
}
30+
31+
public static unsafe byte[] DibToRgba(byte[] dibData, BitmapInfoHeader bitmapHeader)
32+
{
33+
var usedBytes = (ushort)bitmapHeader.BitCount / 8 * bitmapHeader.Width;
34+
// DIB data is padded to the nearest DWORD (4-byte) boundary
35+
var padding = RoundUpToNearestMultipleOf4(usedBytes) - usedBytes;
36+
37+
var rgbaStride = bitmapHeader.Width * 4;
38+
39+
byte[] rgbaData = new byte[rgbaStride * bitmapHeader.Height];
40+
41+
fixed (byte* dibDataPtr = dibData)
42+
{
43+
fixed (byte* rgbaDataPtr = rgbaData)
44+
{
45+
var dibDataPtr2 = dibDataPtr;
46+
var rgbaDataPtr2 = rgbaDataPtr;
47+
48+
for (int y = 0; y < bitmapHeader.Height; y++)
49+
{
50+
// Due to the fact that emf arrays after reading are reversed, padding skipping is done before the X-row loop
51+
// Bytes order in EMF file: B, G, R, PADDED, PADDED, B, G, R, PADDED, PADDED, ...
52+
// After reversing: PADDED, PADDED, R, G, B, PADDED, PADDED, R, G, B, ...
53+
dibDataPtr2 += padding;
54+
55+
for (int x = 0; x < bitmapHeader.Width; x++)
56+
{
57+
var r = *dibDataPtr2;
58+
var g = *(dibDataPtr2 + 1);
59+
var b = *(dibDataPtr2 + 2);
60+
const byte a = 0xFF;
61+
62+
*rgbaDataPtr2 = r;
63+
*(rgbaDataPtr2 + 1) = g;
64+
*(rgbaDataPtr2 + 2) = b;
65+
*(rgbaDataPtr2 + 3) = a;
66+
67+
dibDataPtr2 += 3;
68+
rgbaDataPtr2 += 4;
69+
}
70+
}
71+
}
72+
}
73+
74+
return rgbaData;
75+
}
76+
77+
private static int RoundUpToNearestMultipleOf4(int num)
78+
{
79+
return (num + 3) / 4 * 4;
80+
}
81+
}

src/SharpEmf.Svg/RecordsProcessing/EmfBitmapRecordsHandlers.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,13 @@ internal static class EmfBitmapRecordsHandlers
77
{
88
public static void HandleStretchDIBits(StringBuilder svgSb, EmfState state, EmrStretchDiBits stretchDiBits)
99
{
10-
// TODO: fix this
11-
var bitmapBase64 = Convert.ToBase64String(stretchDiBits.BitsSrc);
12-
13-
var scalingForMapMode = state.GetScalingForCurrentMapMode();
14-
var scaleMatrix = $"matrix({scalingForMapMode.X},0,0,{scalingForMapMode.Y},0,0)";
10+
var bitmapBase64 = BitmapUtils.DibToPngBase64(stretchDiBits.BitsSrc, stretchDiBits.BmiHeader);
1511

1612
var x = stretchDiBits.XDest;
1713
var y = stretchDiBits.YDest;
1814
var width = stretchDiBits.CXDest;
1915
var height = stretchDiBits.CYDest;
2016

21-
22-
svgSb.AppendLine($"<image transform=\"{scaleMatrix}\" x=\"{x}\" y=\"{y}\" width=\"{width}\" height=\"{height}\" xlink:href=\"data:image/bmp;base64,{bitmapBase64}\" />");
17+
svgSb.AppendLine($"<image x=\"{x}\" y=\"{y}\" width=\"{width}\" height=\"{height}\" href=\"data:image/png;base64,{bitmapBase64}\" />");
2318
}
2419
}

src/SharpEmf.Svg/SharpEmf.Svg.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44
<TargetFramework>net8.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
7+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
78
</PropertyGroup>
89

910
<ItemGroup>
1011
<ProjectReference Include="..\SharpEmf\SharpEmf.csproj" />
1112
</ItemGroup>
1213

14+
<ItemGroup>
15+
<PackageReference Include="SkiaSharp" Version="2.88.6" />
16+
</ItemGroup>
17+
1318
</Project>

src/SharpEmf/Extensions/StreamExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ internal static byte[] ReadByteArray(this Stream stream, int length)
7575

7676
var buffer = new byte[length];
7777
stream.ReadExactly(buffer);
78+
buffer.AsSpan().Reverse();
79+
7880
return buffer;
7981
}
8082

0 commit comments

Comments
 (0)