From 2104b29b9744e935cc17eb6aea079ebec31e12bd Mon Sep 17 00:00:00 2001 From: Sergiusz Zalewski <38229504+KeterSCP@users.noreply.github.com> Date: Sat, 16 Dec 2023 00:33:02 +0100 Subject: [PATCH] Move handlers to separate classes --- src/SharpEmf.Svg/EmfSvgWriter.cs | 282 ++---------------- src/SharpEmf.Svg/GraphicsObjectType.cs | 3 +- .../EmfControlRecordsHandlers.cs | 26 ++ .../EmfDrawingRecordsHandlers.cs | 65 ++++ .../EmfObjectCreationRecordsHandlers.cs | 22 ++ .../EmfObjectManipulationRecordsHandlers.cs | 68 +++++ .../EmfPathBracketRecordsHandlers.cs | 32 ++ .../EmfStateRecordsHandlers.cs | 54 ++++ src/SharpEmf.Svg/Utils.cs | 65 ++++ src/SharpEmf/Objects/ColorRef.cs | 8 + src/SharpEmf/Objects/LogBrushEx.cs | 9 + 11 files changed, 370 insertions(+), 264 deletions(-) create mode 100644 src/SharpEmf.Svg/RecordsProcessing/EmfControlRecordsHandlers.cs create mode 100644 src/SharpEmf.Svg/RecordsProcessing/EmfDrawingRecordsHandlers.cs create mode 100644 src/SharpEmf.Svg/RecordsProcessing/EmfObjectCreationRecordsHandlers.cs create mode 100644 src/SharpEmf.Svg/RecordsProcessing/EmfObjectManipulationRecordsHandlers.cs create mode 100644 src/SharpEmf.Svg/RecordsProcessing/EmfPathBracketRecordsHandlers.cs create mode 100644 src/SharpEmf.Svg/RecordsProcessing/EmfStateRecordsHandlers.cs create mode 100644 src/SharpEmf.Svg/Utils.cs diff --git a/src/SharpEmf.Svg/EmfSvgWriter.cs b/src/SharpEmf.Svg/EmfSvgWriter.cs index 493c241..817b0de 100644 --- a/src/SharpEmf.Svg/EmfSvgWriter.cs +++ b/src/SharpEmf.Svg/EmfSvgWriter.cs @@ -1,11 +1,10 @@ using System.Text; -using SharpEmf.Enums; -using SharpEmf.Records.Control.Header; using SharpEmf.Records.Drawing; using SharpEmf.Records.ObjectCreation; using SharpEmf.Records.ObjectManipulation; using SharpEmf.Records.PathBracket; using SharpEmf.Records.State; +using SharpEmf.Svg.RecordsProcessing; namespace SharpEmf.Svg; @@ -16,62 +15,62 @@ public static string ConvertToSvg(EnhancedMetafile emf) var sb = new StringBuilder(); var state = new EmfState(); - HandleHeaderRecord(sb, state, emf.Header); + EmfControlRecordsHandlers.HandleHeaderRecord(sb, state, emf.Header); foreach (var record in emf.Records) { switch (record) { case EmrSetMapMode setMapMode: - HandleSetMapModeRecord(state, setMapMode); + EmfStateRecordsHandlers.HandleSetMapModeRecord(state, setMapMode); break; case EmrSetBkMode setBkMode: - HandleSetBkModeRecord(state, setBkMode); + EmfStateRecordsHandlers.HandleSetBkModeRecord(state, setBkMode); break; case EmrSetWindowOrgEx setWindowOrgEx: - HandleSetWindowOrgExRecord(state, setWindowOrgEx); + EmfStateRecordsHandlers.HandleSetWindowOrgExRecord(state, setWindowOrgEx); break; case EmrSetViewportOrgEx setViewportOrgEx: - HandleSetViewportOrgExRecord(state, setViewportOrgEx); + EmfStateRecordsHandlers.HandleSetViewportOrgExRecord(state, setViewportOrgEx); break; case EmrSetWindowExtEx setWindowExtEx: - HandleSetWindowExtExRecord(state, setWindowExtEx); + EmfStateRecordsHandlers.HandleSetWindowExtExRecord(state, setWindowExtEx); break; case EmrSetViewportExtEx setViewportExtEx: - HandleSetViewportExtExRecord(state, setViewportExtEx); + EmfStateRecordsHandlers.HandleSetViewportExtExRecord(state, setViewportExtEx); break; case EmrSetPolyfillMode setPolyfillMode: - HandleSetPolyfillMode(state, setPolyfillMode); + EmfStateRecordsHandlers.HandleSetPolyfillMode(state, setPolyfillMode); break; case EmrCreateBrushIndirect createBrushIndirect: - HandleCreateBrushIndirect(state, createBrushIndirect); + EmfObjectCreationRecordsHandlers.HandleCreateBrushIndirect(state, createBrushIndirect); break; case EmrSelectObject selectObject: - HandleSelectObject(state, selectObject); + EmfObjectManipulationRecordsHandlers.HandleSelectObject(state, selectObject); break; case EmrDeleteObject deleteObject: - HandleDeleteObject(state, deleteObject); + EmfObjectManipulationRecordsHandlers.HandleDeleteObject(state, deleteObject); break; case EmrExtCreatePen extCreatePen: - HandleExtCreatePen(state, extCreatePen); + EmfObjectCreationRecordsHandlers.HandleExtCreatePen(state, extCreatePen); break; case EmrPolyPolygon16 polyPolygon16: - HandlePolyPolygon16(sb, state, polyPolygon16); + EmfDrawingRecordsHandlers.HandlePolyPolygon16(sb, state, polyPolygon16); break; case EmrBeginPath: - HandleBeginPath(sb, state); + EmfPathBracketRecordsHandlers.HandleBeginPath(sb, state); break; case EmrEndPath: - HandleEndPath(sb, state); + EmfPathBracketRecordsHandlers.HandleEndPath(sb, state); break; case EmrMoveToEx moveToEx: - HandleMoveToEx(sb, state, moveToEx); + EmfStateRecordsHandlers.HandleMoveToEx(sb, state, moveToEx); break; case EmrPolyBezierTo16 polyBezierTo16: - HandlePolybezierTo16(sb, state, polyBezierTo16); + EmfDrawingRecordsHandlers.HandlePolybezierTo16(sb, state, polyBezierTo16); break; case EmrCloseFigure: - sb.Append("Z "); + EmfPathBracketRecordsHandlers.HandleCloseFigure(sb); break; } } @@ -80,247 +79,4 @@ public static string ConvertToSvg(EnhancedMetafile emf) sb.AppendLine(""); return sb.ToString(); } - - private static void HandleHeaderRecord(StringBuilder svgSb, EmfState state, EmfMetafileHeader header) - { - var width = header.Bounds.Right - header.Bounds.Left; - var height = header.Bounds.Bottom - header.Bounds.Top; - var gTransform = $"translate({-header.Bounds.Left},{-header.Bounds.Top})"; - - state.Scaling = width / MathF.Abs(header.Bounds.Right - header.Bounds.Left); - - // TODO: +1 is a hack to make the object table start at index 1 - state.ObjectTable = new GraphicsObject[header.Handles + 1]; - - svgSb.AppendLine( - $""" - - - - """); - } - - private static void HandleSetMapModeRecord(EmfState state, EmrSetMapMode setMapMode) - { - state.MapMode = setMapMode.MapMode; - } - - private static void HandleSetBkModeRecord(EmfState state, EmrSetBkMode setBkMode) - { - state.CurrentPlaybackDeviceContext.BkMode = setBkMode.BackgroundMode; - } - - private static void HandleSetWindowOrgExRecord(EmfState state, EmrSetWindowOrgEx setWindowOrgEx) - { - state.WindowOrigin = setWindowOrgEx.Origin; - } - - private static void HandleSetViewportOrgExRecord(EmfState state, EmrSetViewportOrgEx setViewportOrgEx) - { - state.ViewportOrigin = setViewportOrgEx.Origin; - } - - private static void HandleSetWindowExtExRecord(EmfState state, EmrSetWindowExtEx setWindowExtEx) - { - state.WindowExtent = setWindowExtEx.Extent; - } - - private static void HandleSetViewportExtExRecord(EmfState state, EmrSetViewportExtEx setViewportExtEx) - { - state.ViewportExtent = setViewportExtEx.Extent; - } - - private static void HandleSetPolyfillMode(EmfState state, EmrSetPolyfillMode setPolyfillMode) - { - state.CurrentPlaybackDeviceContext.PolyFillMode = setPolyfillMode.PolygonFillMode; - } - - private static void HandleCreateBrushIndirect(EmfState state, EmrCreateBrushIndirect createBrushIndirect) - { - var index = createBrushIndirect.IHBrush; - - state.ObjectTable[index].LogBrush = createBrushIndirect.LogBrush; - state.ObjectTable[index].Type = GraphicsObjectType.Brush; - } - - private static void HandleSelectObject(EmfState state, EmrSelectObject selectObject) - { - var index = selectObject.IHObject; - - // TODO: Handle stock objects - - var graphicsObject = state.ObjectTable[index]; - - if (graphicsObject.Type is GraphicsObjectType.Pen) - { - state.CurrentPlaybackDeviceContext.SelectedPen = graphicsObject.LogPen; - } - else if (graphicsObject.Type is GraphicsObjectType.Brush) - { - state.CurrentPlaybackDeviceContext.SelectedBrush = graphicsObject.LogBrush; - } - else if (graphicsObject.Type is GraphicsObjectType.Unknown) - { - Console.WriteLine("Warning: Unknown object type selected"); - } - } - - private static void HandleDeleteObject(EmfState state, EmrDeleteObject deleteObject) - { - var index = deleteObject.IHObject; - state.ObjectTable[index] = default; - } - - private static void HandleExtCreatePen(EmfState state, EmrExtCreatePen extCreatePen) - { - var index = extCreatePen.IHPen; - - state.ObjectTable[index].LogPen = extCreatePen.Elp; - state.ObjectTable[index].Type = GraphicsObjectType.Pen; - } - - private static void HandlePolyPolygon16(StringBuilder svgSb, EmfState state, EmrPolyPolygon16 polyPolygon16) - { - var points = polyPolygon16.APoints; - var polygonPointCounts = polyPolygon16.PolygonPointCount; - - var scalingForMapMode = state.GetScalingForCurrentMapMode(); - var scaleMatrix = $"matrix({scalingForMapMode.X},0,0,{scalingForMapMode.Y},0,0)"; - - svgSb.Append($""); - } - - private static void HandleBeginPath(StringBuilder svgSb, EmfState state) - { - state.InPath = true; - - var scalingForMapMode = state.GetScalingForCurrentMapMode(); - var scaleMatrix = $"matrix({scalingForMapMode.X},0,0,{scalingForMapMode.Y},0,0)"; - - svgSb.Append($""); - } - - private static void AppendFill(StringBuilder svgSb, EmfState state) - { - var fillRuleStr = state.CurrentPlaybackDeviceContext.PolyFillMode switch - { - PolygonFillMode.WINDING => "fill-rule=\"nonzero\" ", - PolygonFillMode.ALTERNATE => "fill-rule=\"evenodd\" ", - _ => "" - }; - - switch (state.CurrentPlaybackDeviceContext.SelectedBrush.BrushStyle) - { - case BrushStyle.BS_NULL: - svgSb.Append("fill=\"none\" "); - break; - case BrushStyle.BS_SOLID: - svgSb.Append(fillRuleStr); - - svgSb.Append($"fill=\"#{state.CurrentPlaybackDeviceContext.SelectedBrush.Color.Red:X2}"); - svgSb.Append($"{state.CurrentPlaybackDeviceContext.SelectedBrush.Color.Green:X2}"); - svgSb.Append($"{state.CurrentPlaybackDeviceContext.SelectedBrush.Color.Blue:X2}\" "); - break; - case BrushStyle.BS_HATCHED: - case BrushStyle.BS_PATTERN: - case BrushStyle.BS_INDEXED: - case BrushStyle.BS_DIBPATTERN: - case BrushStyle.BS_DIBPATTERNPT: - case BrushStyle.BS_PATTERN8X8: - case BrushStyle.BS_DIBPATTERN8X8: - default: - svgSb.Append($"fill=\"#{state.CurrentPlaybackDeviceContext.SelectedBrush.Color.Red:X2}"); - svgSb.Append($"{state.CurrentPlaybackDeviceContext.SelectedBrush.Color.Green:X2}"); - svgSb.Append($"{state.CurrentPlaybackDeviceContext.SelectedBrush.Color.Blue:X2}\" "); - break; - } - } - - private static void AppendStroke(StringBuilder svgSb, EmfState state) - { - // TODO: use scaling from state - var selectedPen = state.CurrentPlaybackDeviceContext.SelectedPen; - if (selectedPen.PenStyle is PenStyle.PS_NULL) - { - svgSb.Append("stroke=\"none\" "); - } - - // switch (state.CurrentPlaybackDeviceContext.SelectedGraphicsObject.LogPen.PenStyle) - // { - // case PenStyle.PS_COSMETIC: - // sb.Append($"stroke-width=\"{stroke}\""); - // break; - // case PenStyle.PS_GEOMETRIC: - // sb.Append($"stroke-width=\"{stroke}\""); - // break; - // } - - // TODO: handle other pen styles - } } \ No newline at end of file diff --git a/src/SharpEmf.Svg/GraphicsObjectType.cs b/src/SharpEmf.Svg/GraphicsObjectType.cs index 76fa0b6..8a2f961 100644 --- a/src/SharpEmf.Svg/GraphicsObjectType.cs +++ b/src/SharpEmf.Svg/GraphicsObjectType.cs @@ -4,5 +4,6 @@ internal enum GraphicsObjectType { Unknown, Brush, - Pen + Pen, + // TODO: add more stock object (font, color space, palette) } \ No newline at end of file diff --git a/src/SharpEmf.Svg/RecordsProcessing/EmfControlRecordsHandlers.cs b/src/SharpEmf.Svg/RecordsProcessing/EmfControlRecordsHandlers.cs new file mode 100644 index 0000000..ed47b41 --- /dev/null +++ b/src/SharpEmf.Svg/RecordsProcessing/EmfControlRecordsHandlers.cs @@ -0,0 +1,26 @@ +using System.Text; +using SharpEmf.Records.Control.Header; + +namespace SharpEmf.Svg.RecordsProcessing; + +internal static class EmfControlRecordsHandlers +{ + public static void HandleHeaderRecord(StringBuilder svgSb, EmfState state, EmfMetafileHeader header) + { + var width = header.Bounds.Right - header.Bounds.Left; + var height = header.Bounds.Bottom - header.Bounds.Top; + var gTransform = $"translate({-header.Bounds.Left},{-header.Bounds.Top})"; + + state.Scaling = width / MathF.Abs(header.Bounds.Right - header.Bounds.Left); + + // TODO: +1 is a hack to make the object table start at index 1 + state.ObjectTable = new GraphicsObject[header.Handles + 1]; + + svgSb.AppendLine( + $""" + + + + """); + } +} \ No newline at end of file diff --git a/src/SharpEmf.Svg/RecordsProcessing/EmfDrawingRecordsHandlers.cs b/src/SharpEmf.Svg/RecordsProcessing/EmfDrawingRecordsHandlers.cs new file mode 100644 index 0000000..b38fc51 --- /dev/null +++ b/src/SharpEmf.Svg/RecordsProcessing/EmfDrawingRecordsHandlers.cs @@ -0,0 +1,65 @@ +using System.Text; +using SharpEmf.Records.Drawing; + +namespace SharpEmf.Svg.RecordsProcessing; + +internal static class EmfDrawingRecordsHandlers +{ + public static void HandlePolyPolygon16(StringBuilder svgSb, EmfState state, EmrPolyPolygon16 polyPolygon16) + { + var points = polyPolygon16.APoints; + var polygonPointCounts = polyPolygon16.PolygonPointCount; + + var scalingForMapMode = state.GetScalingForCurrentMapMode(); + var scaleMatrix = $"matrix({scalingForMapMode.X},0,0,{scalingForMapMode.Y},0,0)"; + + svgSb.Append($""); + } + + public static void HandlePolybezierTo16(StringBuilder svgSb, EmfState state, EmrPolyBezierTo16 polyBezierTo16) + { + if (!state.InPath) + { + return; + } + + var currentPointCounter = 0; + + foreach (var point in polyBezierTo16.APoints) + { + if (currentPointCounter % 3 == 0) + { + svgSb.Append("C "); + } + svgSb.Append($"{point.X} {point.Y} "); + + currentPointCounter++; + } + } +} \ No newline at end of file diff --git a/src/SharpEmf.Svg/RecordsProcessing/EmfObjectCreationRecordsHandlers.cs b/src/SharpEmf.Svg/RecordsProcessing/EmfObjectCreationRecordsHandlers.cs new file mode 100644 index 0000000..c03bb5b --- /dev/null +++ b/src/SharpEmf.Svg/RecordsProcessing/EmfObjectCreationRecordsHandlers.cs @@ -0,0 +1,22 @@ +using SharpEmf.Records.ObjectCreation; + +namespace SharpEmf.Svg.RecordsProcessing; + +internal static class EmfObjectCreationRecordsHandlers +{ + public static void HandleCreateBrushIndirect(EmfState state, EmrCreateBrushIndirect createBrushIndirect) + { + var index = createBrushIndirect.IHBrush; + + state.ObjectTable[index].LogBrush = createBrushIndirect.LogBrush; + state.ObjectTable[index].Type = GraphicsObjectType.Brush; + } + + public static void HandleExtCreatePen(EmfState state, EmrExtCreatePen extCreatePen) + { + var index = extCreatePen.IHPen; + + state.ObjectTable[index].LogPen = extCreatePen.Elp; + state.ObjectTable[index].Type = GraphicsObjectType.Pen; + } +} \ No newline at end of file diff --git a/src/SharpEmf.Svg/RecordsProcessing/EmfObjectManipulationRecordsHandlers.cs b/src/SharpEmf.Svg/RecordsProcessing/EmfObjectManipulationRecordsHandlers.cs new file mode 100644 index 0000000..1715c1d --- /dev/null +++ b/src/SharpEmf.Svg/RecordsProcessing/EmfObjectManipulationRecordsHandlers.cs @@ -0,0 +1,68 @@ +using SharpEmf.Enums; +using SharpEmf.Objects; +using SharpEmf.Records.ObjectManipulation; + +namespace SharpEmf.Svg.RecordsProcessing; + +internal static class EmfObjectManipulationRecordsHandlers +{ + public static void HandleSelectObject(EmfState state, EmrSelectObject selectObject) + { + var index = selectObject.IHObject; + + // Selecting a stock object + if ((index & 0x80000000) != 0) + { + var stockObject = (StockObject)index; + if (stockObject is StockObject.WHITE_BRUSH) + { + state.CurrentPlaybackDeviceContext.SelectedBrush = new LogBrushEx( + brushStyle: BrushStyle.BS_SOLID, + color: new ColorRef(0xFF, 0xFF, 0xFF)); + } + else if (stockObject is StockObject.LTGRAY_BRUSH) + { + state.CurrentPlaybackDeviceContext.SelectedBrush = new LogBrushEx( + brushStyle: BrushStyle.BS_SOLID, + color: new ColorRef(0xC0, 0xC0, 0xC0)); + } + else if (stockObject is StockObject.GRAY_BRUSH) + { + state.CurrentPlaybackDeviceContext.SelectedBrush = new LogBrushEx( + brushStyle: BrushStyle.BS_SOLID, + color: new ColorRef(0x80, 0x80, 0x80)); + } + else if (stockObject is StockObject.DKGRAY_BRUSH) + { + state.CurrentPlaybackDeviceContext.SelectedBrush = new LogBrushEx( + brushStyle: BrushStyle.BS_SOLID, + color: new ColorRef(0x40, 0x40, 0x40)); + } + else if (stockObject is StockObject.NULL_BRUSH) + { + state.CurrentPlaybackDeviceContext.SelectedBrush = LogBrushEx.Null; + } + } + + var graphicsObject = state.ObjectTable[index]; + + if (graphicsObject.Type is GraphicsObjectType.Pen) + { + state.CurrentPlaybackDeviceContext.SelectedPen = graphicsObject.LogPen; + } + else if (graphicsObject.Type is GraphicsObjectType.Brush) + { + state.CurrentPlaybackDeviceContext.SelectedBrush = graphicsObject.LogBrush; + } + else if (graphicsObject.Type is GraphicsObjectType.Unknown) + { + Console.WriteLine("Warning: Unknown object type selected"); + } + } + + public static void HandleDeleteObject(EmfState state, EmrDeleteObject deleteObject) + { + var index = deleteObject.IHObject; + state.ObjectTable[index] = default; + } +} \ No newline at end of file diff --git a/src/SharpEmf.Svg/RecordsProcessing/EmfPathBracketRecordsHandlers.cs b/src/SharpEmf.Svg/RecordsProcessing/EmfPathBracketRecordsHandlers.cs new file mode 100644 index 0000000..74c53f9 --- /dev/null +++ b/src/SharpEmf.Svg/RecordsProcessing/EmfPathBracketRecordsHandlers.cs @@ -0,0 +1,32 @@ +using System.Text; + +namespace SharpEmf.Svg.RecordsProcessing; + +internal static class EmfPathBracketRecordsHandlers +{ + public static void HandleBeginPath(StringBuilder svgSb, EmfState state) + { + state.InPath = true; + + var scalingForMapMode = state.GetScalingForCurrentMapMode(); + var scaleMatrix = $"matrix({scalingForMapMode.X},0,0,{scalingForMapMode.Y},0,0)"; + + svgSb.Append($""); + } + + public static void HandleCloseFigure(StringBuilder svgSb) + { + svgSb.Append("Z "); + } +} \ No newline at end of file diff --git a/src/SharpEmf.Svg/RecordsProcessing/EmfStateRecordsHandlers.cs b/src/SharpEmf.Svg/RecordsProcessing/EmfStateRecordsHandlers.cs new file mode 100644 index 0000000..9501011 --- /dev/null +++ b/src/SharpEmf.Svg/RecordsProcessing/EmfStateRecordsHandlers.cs @@ -0,0 +1,54 @@ +using System.Text; +using SharpEmf.Records.State; + +namespace SharpEmf.Svg.RecordsProcessing; + +internal static class EmfStateRecordsHandlers +{ + public static void HandleSetMapModeRecord(EmfState state, EmrSetMapMode setMapMode) + { + state.MapMode = setMapMode.MapMode; + } + + public static void HandleSetBkModeRecord(EmfState state, EmrSetBkMode setBkMode) + { + state.CurrentPlaybackDeviceContext.BkMode = setBkMode.BackgroundMode; + } + + public static void HandleSetWindowOrgExRecord(EmfState state, EmrSetWindowOrgEx setWindowOrgEx) + { + state.WindowOrigin = setWindowOrgEx.Origin; + } + + public static void HandleSetViewportOrgExRecord(EmfState state, EmrSetViewportOrgEx setViewportOrgEx) + { + state.ViewportOrigin = setViewportOrgEx.Origin; + } + + public static void HandleSetWindowExtExRecord(EmfState state, EmrSetWindowExtEx setWindowExtEx) + { + state.WindowExtent = setWindowExtEx.Extent; + } + + public static void HandleSetViewportExtExRecord(EmfState state, EmrSetViewportExtEx setViewportExtEx) + { + state.ViewportExtent = setViewportExtEx.Extent; + } + + public static void HandleSetPolyfillMode(EmfState state, EmrSetPolyfillMode setPolyfillMode) + { + state.CurrentPlaybackDeviceContext.PolyFillMode = setPolyfillMode.PolygonFillMode; + } + + public static void HandleMoveToEx(StringBuilder svgSb, EmfState state, EmrMoveToEx moveToEx) + { + if (state.InPath) + { + svgSb.Append($"M {moveToEx.Offset.X} {moveToEx.Offset.Y} "); + } + else + { + // TODO: set current position in state + } + } +} \ No newline at end of file diff --git a/src/SharpEmf.Svg/Utils.cs b/src/SharpEmf.Svg/Utils.cs new file mode 100644 index 0000000..b91c193 --- /dev/null +++ b/src/SharpEmf.Svg/Utils.cs @@ -0,0 +1,65 @@ +using System.Text; +using SharpEmf.Enums; + +namespace SharpEmf.Svg; + +internal static class Utils +{ + public static void AppendFill(StringBuilder svgSb, EmfState state) + { + var fillRuleStr = state.CurrentPlaybackDeviceContext.PolyFillMode switch + { + PolygonFillMode.WINDING => "fill-rule=\"nonzero\" ", + PolygonFillMode.ALTERNATE => "fill-rule=\"evenodd\" ", + _ => "" + }; + + switch (state.CurrentPlaybackDeviceContext.SelectedBrush.BrushStyle) + { + case BrushStyle.BS_NULL: + svgSb.Append("fill=\"none\" "); + break; + case BrushStyle.BS_SOLID: + svgSb.Append(fillRuleStr); + + svgSb.Append($"fill=\"#{state.CurrentPlaybackDeviceContext.SelectedBrush.Color.Red:X2}"); + svgSb.Append($"{state.CurrentPlaybackDeviceContext.SelectedBrush.Color.Green:X2}"); + svgSb.Append($"{state.CurrentPlaybackDeviceContext.SelectedBrush.Color.Blue:X2}\" "); + break; + case BrushStyle.BS_HATCHED: + case BrushStyle.BS_PATTERN: + case BrushStyle.BS_INDEXED: + case BrushStyle.BS_DIBPATTERN: + case BrushStyle.BS_DIBPATTERNPT: + case BrushStyle.BS_PATTERN8X8: + case BrushStyle.BS_DIBPATTERN8X8: + default: + svgSb.Append($"fill=\"#{state.CurrentPlaybackDeviceContext.SelectedBrush.Color.Red:X2}"); + svgSb.Append($"{state.CurrentPlaybackDeviceContext.SelectedBrush.Color.Green:X2}"); + svgSb.Append($"{state.CurrentPlaybackDeviceContext.SelectedBrush.Color.Blue:X2}\" "); + break; + } + } + + public static void AppendStroke(StringBuilder svgSb, EmfState state) + { + // TODO: use scaling from state + var selectedPen = state.CurrentPlaybackDeviceContext.SelectedPen; + if (selectedPen.PenStyle is PenStyle.PS_NULL) + { + svgSb.Append("stroke=\"none\" "); + } + + // switch (state.CurrentPlaybackDeviceContext.SelectedGraphicsObject.LogPen.PenStyle) + // { + // case PenStyle.PS_COSMETIC: + // sb.Append($"stroke-width=\"{stroke}\""); + // break; + // case PenStyle.PS_GEOMETRIC: + // sb.Append($"stroke-width=\"{stroke}\""); + // break; + // } + + // TODO: handle other pen styles + } +} \ No newline at end of file diff --git a/src/SharpEmf/Objects/ColorRef.cs b/src/SharpEmf/Objects/ColorRef.cs index e226f97..f754bee 100644 --- a/src/SharpEmf/Objects/ColorRef.cs +++ b/src/SharpEmf/Objects/ColorRef.cs @@ -26,6 +26,14 @@ public readonly struct ColorRef // DO NOT remove this field, it is required for proper calculation of the struct size private readonly byte _reserved; + public ColorRef(byte red, byte green, byte blue) + { + Red = red; + Green = green; + Blue = blue; + _reserved = 0; + } + private ColorRef(byte red, byte green, byte blue, byte reserved) { Red = red; diff --git a/src/SharpEmf/Objects/LogBrushEx.cs b/src/SharpEmf/Objects/LogBrushEx.cs index f6134c2..85f1a86 100644 --- a/src/SharpEmf/Objects/LogBrushEx.cs +++ b/src/SharpEmf/Objects/LogBrushEx.cs @@ -37,6 +37,13 @@ public readonly struct LogBrushEx /// public HatchStyle HatchStyle { get; } + public LogBrushEx(BrushStyle brushStyle, ColorRef color) + { + BrushStyle = brushStyle; + Color = color; + HatchStyle = HatchStyle.HS_SOLIDCLR; + } + private LogBrushEx(BrushStyle brushStyle, ColorRef color, HatchStyle hatchStyle) { BrushStyle = brushStyle; @@ -44,6 +51,8 @@ private LogBrushEx(BrushStyle brushStyle, ColorRef color, HatchStyle hatchStyle) HatchStyle = hatchStyle; } + public static LogBrushEx Null { get; } = new(BrushStyle.BS_NULL, color: default); + public static LogBrushEx Parse(Stream stream) { var brushStyle = stream.ReadEnum();