From 29fed6500f56e75f9a933ebb00d8aef90969238e Mon Sep 17 00:00:00 2001
From: Sergiusz Zalewski <38229504+KeterSCP@users.noreply.github.com>
Date: Sun, 17 Dec 2023 13:12:56 +0100
Subject: [PATCH] Drawing of 24-bit DIB to png
---
src/SharpEmf.Svg/BitmapUtils.cs | 81 +++++++++++++++++++
.../EmfBitmapRecordsHandlers.cs | 9 +--
src/SharpEmf.Svg/SharpEmf.Svg.csproj | 5 ++
src/SharpEmf/Extensions/StreamExtensions.cs | 2 +
4 files changed, 90 insertions(+), 7 deletions(-)
create mode 100644 src/SharpEmf.Svg/BitmapUtils.cs
diff --git a/src/SharpEmf.Svg/BitmapUtils.cs b/src/SharpEmf.Svg/BitmapUtils.cs
new file mode 100644
index 0000000..2c55b9d
--- /dev/null
+++ b/src/SharpEmf.Svg/BitmapUtils.cs
@@ -0,0 +1,81 @@
+using SharpEmf.WmfTypes.Bitmap;
+using SkiaSharp;
+
+namespace SharpEmf.Svg;
+
+internal static class BitmapUtils
+{
+ public static unsafe string DibToPngBase64(byte[] dibData, BitmapInfoHeader bitmapHeader)
+ {
+ // TODO: this assumes that the DIB is 24-bit RGB, handle other cases
+
+ using var bitmap = new SKBitmap();
+
+ var width = bitmapHeader.Width;
+ var height = bitmapHeader.Height;
+
+ var rgbaData = DibToRgba(dibData, bitmapHeader);
+
+ fixed(byte* rgbaDataPtr = rgbaData)
+ {
+ var rgbaDataPtr2 = (IntPtr)rgbaDataPtr;
+ bitmap.InstallPixels(new SKImageInfo(width, height, SKColorType.Rgba8888, SKAlphaType.Unpremul), rgbaDataPtr2, width * 4);
+ }
+
+ using var pngData = bitmap.Encode(SKEncodedImageFormat.Png, 100);
+ var resultBase64Str = Convert.ToBase64String(pngData.Span);
+
+ return resultBase64Str;
+ }
+
+ public static unsafe byte[] DibToRgba(byte[] dibData, BitmapInfoHeader bitmapHeader)
+ {
+ var usedBytes = (ushort)bitmapHeader.BitCount / 8 * bitmapHeader.Width;
+ // DIB data is padded to the nearest DWORD (4-byte) boundary
+ var padding = RoundUpToNearestMultipleOf4(usedBytes) - usedBytes;
+
+ var rgbaStride = bitmapHeader.Width * 4;
+
+ byte[] rgbaData = new byte[rgbaStride * bitmapHeader.Height];
+
+ fixed (byte* dibDataPtr = dibData)
+ {
+ fixed (byte* rgbaDataPtr = rgbaData)
+ {
+ var dibDataPtr2 = dibDataPtr;
+ var rgbaDataPtr2 = rgbaDataPtr;
+
+ for (int y = 0; y < bitmapHeader.Height; y++)
+ {
+ // Due to the fact that emf arrays after reading are reversed, padding skipping is done before the X-row loop
+ // Bytes order in EMF file: B, G, R, PADDED, PADDED, B, G, R, PADDED, PADDED, ...
+ // After reversing: PADDED, PADDED, R, G, B, PADDED, PADDED, R, G, B, ...
+ dibDataPtr2 += padding;
+
+ for (int x = 0; x < bitmapHeader.Width; x++)
+ {
+ var r = *dibDataPtr2;
+ var g = *(dibDataPtr2 + 1);
+ var b = *(dibDataPtr2 + 2);
+ const byte a = 0xFF;
+
+ *rgbaDataPtr2 = r;
+ *(rgbaDataPtr2 + 1) = g;
+ *(rgbaDataPtr2 + 2) = b;
+ *(rgbaDataPtr2 + 3) = a;
+
+ dibDataPtr2 += 3;
+ rgbaDataPtr2 += 4;
+ }
+ }
+ }
+ }
+
+ return rgbaData;
+ }
+
+ private static int RoundUpToNearestMultipleOf4(int num)
+ {
+ return (num + 3) / 4 * 4;
+ }
+}
\ No newline at end of file
diff --git a/src/SharpEmf.Svg/RecordsProcessing/EmfBitmapRecordsHandlers.cs b/src/SharpEmf.Svg/RecordsProcessing/EmfBitmapRecordsHandlers.cs
index d8ec25b..513fab1 100644
--- a/src/SharpEmf.Svg/RecordsProcessing/EmfBitmapRecordsHandlers.cs
+++ b/src/SharpEmf.Svg/RecordsProcessing/EmfBitmapRecordsHandlers.cs
@@ -7,18 +7,13 @@ internal static class EmfBitmapRecordsHandlers
{
public static void HandleStretchDIBits(StringBuilder svgSb, EmfState state, EmrStretchDiBits stretchDiBits)
{
- // TODO: fix this
- var bitmapBase64 = Convert.ToBase64String(stretchDiBits.BitsSrc);
-
- var scalingForMapMode = state.GetScalingForCurrentMapMode();
- var scaleMatrix = $"matrix({scalingForMapMode.X},0,0,{scalingForMapMode.Y},0,0)";
+ var bitmapBase64 = BitmapUtils.DibToPngBase64(stretchDiBits.BitsSrc, stretchDiBits.BmiHeader);
var x = stretchDiBits.XDest;
var y = stretchDiBits.YDest;
var width = stretchDiBits.CXDest;
var height = stretchDiBits.CYDest;
-
- svgSb.AppendLine($"");
+ svgSb.AppendLine($"");
}
}
\ No newline at end of file
diff --git a/src/SharpEmf.Svg/SharpEmf.Svg.csproj b/src/SharpEmf.Svg/SharpEmf.Svg.csproj
index 34e08d0..e1c1937 100644
--- a/src/SharpEmf.Svg/SharpEmf.Svg.csproj
+++ b/src/SharpEmf.Svg/SharpEmf.Svg.csproj
@@ -4,10 +4,15 @@
net8.0
enable
enable
+ true
+
+
+
+
diff --git a/src/SharpEmf/Extensions/StreamExtensions.cs b/src/SharpEmf/Extensions/StreamExtensions.cs
index 7aca345..cad631b 100644
--- a/src/SharpEmf/Extensions/StreamExtensions.cs
+++ b/src/SharpEmf/Extensions/StreamExtensions.cs
@@ -75,6 +75,8 @@ internal static byte[] ReadByteArray(this Stream stream, int length)
var buffer = new byte[length];
stream.ReadExactly(buffer);
+ buffer.AsSpan().Reverse();
+
return buffer;
}