Skip to content

Commit

Permalink
Drawing of 24-bit DIB to png
Browse files Browse the repository at this point in the history
  • Loading branch information
KeterSCP committed Dec 17, 2023
1 parent 0226777 commit b478388
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 3 deletions.
81 changes: 81 additions & 0 deletions src/SharpEmf.Svg/BitmapUtils.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ internal static class EmfBitmapRecordsHandlers
{
public static void HandleStretchDIBits(StringBuilder svgSb, EmfState state, EmrStretchDiBits stretchDiBits)
{
// TODO: fix this
var bitmapBase64 = Convert.ToBase64String(stretchDiBits.BitsSrc);
var bitmapBase64 = BitmapUtils.DibToPngBase64(stretchDiBits.BitsSrc, stretchDiBits.BmiHeader);

var scalingForMapMode = state.GetScalingForCurrentMapMode();
var scaleMatrix = $"matrix({scalingForMapMode.X},0,0,{scalingForMapMode.Y},0,0)";
Expand All @@ -19,6 +18,6 @@ public static void HandleStretchDIBits(StringBuilder svgSb, EmfState state, EmrS
var height = stretchDiBits.CYDest;


svgSb.AppendLine($"<image transform=\"{scaleMatrix}\" x=\"{x}\" y=\"{y}\" width=\"{width}\" height=\"{height}\" xlink:href=\"data:image/bmp;base64,{bitmapBase64}\" />");
svgSb.AppendLine($"<image transform=\"{scaleMatrix}\" x=\"{x}\" y=\"{y}\" width=\"{width}\" height=\"{height}\" href=\"data:image/png;base64,{bitmapBase64}\" />");
}
}
5 changes: 5 additions & 0 deletions src/SharpEmf.Svg/SharpEmf.Svg.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\SharpEmf\SharpEmf.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="SkiaSharp" Version="2.88.6" />
</ItemGroup>

</Project>
2 changes: 2 additions & 0 deletions src/SharpEmf/Extensions/StreamExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit b478388

Please sign in to comment.