diff --git a/src/UglyToad.PdfPig.Core/PdfSubpath.cs b/src/UglyToad.PdfPig.Core/PdfSubpath.cs
index 39414090..84669f4b 100644
--- a/src/UglyToad.PdfPig.Core/PdfSubpath.cs
+++ b/src/UglyToad.PdfPig.Core/PdfSubpath.cs
@@ -311,7 +311,7 @@
///
/// Converts from the path command to an SVG string representing the path operation.
///
- void WriteSvg(StringBuilder builder);
+ void WriteSvg(StringBuilder builder, double height);
}
///
@@ -326,7 +326,7 @@
}
///
- public void WriteSvg(StringBuilder builder)
+ public void WriteSvg(StringBuilder builder, double height)
{
builder.Append("Z ");
}
@@ -373,9 +373,9 @@
}
///
- public void WriteSvg(StringBuilder builder)
+ public void WriteSvg(StringBuilder builder, double height)
{
- builder.Append("M ").Append(Location.X).Append(' ').Append(Location.Y).Append(' ');
+ builder.Append($"M {Location.X} {height - Location.Y} ");
}
///
@@ -439,9 +439,9 @@
}
///
- public void WriteSvg(StringBuilder builder)
+ public void WriteSvg(StringBuilder builder, double height)
{
- builder.AppendFormat("L {0} {1} ", To.X, To.Y);
+ builder.Append($"L {To.X} {height - To.Y} ");
}
///
@@ -543,10 +543,9 @@
}
///
- public void WriteSvg(StringBuilder builder)
+ public void WriteSvg(StringBuilder builder, double height)
{
- builder.AppendFormat("C {0} {1}, {2} {3}, {4} {5} ", FirstControlPoint.X, FirstControlPoint.Y, SecondControlPoint.X, SecondControlPoint.Y,
- EndPoint.X, EndPoint.Y);
+ builder.Append($"C {FirstControlPoint.X} { height - FirstControlPoint.Y}, { SecondControlPoint.X} {height - SecondControlPoint.Y}, {EndPoint.X} {height - EndPoint.Y} ");
}
private bool TrySolveQuadratic(bool isX, double currentMin, double currentMax, out (double min, double max) solutions)
diff --git a/src/UglyToad.PdfPig.DocumentLayoutAnalysis/Export/SvgTextExporter.cs b/src/UglyToad.PdfPig.DocumentLayoutAnalysis/Export/SvgTextExporter.cs
new file mode 100644
index 00000000..f7f6bd56
--- /dev/null
+++ b/src/UglyToad.PdfPig.DocumentLayoutAnalysis/Export/SvgTextExporter.cs
@@ -0,0 +1,209 @@
+namespace UglyToad.PdfPig.DocumentLayoutAnalysis.Export
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using UglyToad.PdfPig.Content;
+ using UglyToad.PdfPig.Graphics;
+ using UglyToad.PdfPig.Graphics.Colors;
+ using UglyToad.PdfPig.Graphics.Core;
+
+ ///
+ ///
+ ///
+ public class SvgTextExporter : ITextExporter
+ {
+ static readonly int rounding = 4;
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public string Get(Page page)
+ {
+ var builder = new StringBuilder($"");
+ return builder.ToString();
+ }
+
+ static readonly Dictionary _fonts = new Dictionary()
+ {
+ { "ArialMT", "Arial Rounded MT Bold" }
+ };
+
+ private static string LetterToSvg(Letter l, double height)
+ {
+ string fontFamily = GetFontFamily(l.FontName, out string style, out string weight);
+ string rotation = "";
+ if (l.GlyphRectangle.Rotation != 0)
+ {
+ rotation = $" transform='rotate({Math.Round(-l.GlyphRectangle.Rotation, rounding)} {Math.Round(l.GlyphRectangle.BottomLeft.X, rounding)},{Math.Round(height - l.GlyphRectangle.TopLeft.Y, rounding)})'";
+ }
+
+ string fontSize = l.FontSize != 1 ? $"font-size='{l.FontSize.ToString("0")}'" : $"style='font-size:{Math.Round(l.GlyphRectangle.Height, 2)}px'";
+
+ return $"{l.Value}";
+ }
+
+ private static string GetFontFamily(string fontName, out string style, out string weight)
+ {
+ style = "normal"; // normal | italic | oblique
+ weight = "normal"; // normal | bold | bolder | lighter
+
+ // remove subset prefix
+ if (fontName.Contains('+'))
+ {
+ if (fontName.Length > 7 && fontName[6] == '+')
+ {
+ var split = fontName.Split('+');
+ if (split[0].All(c => char.IsUpper(c)))
+ {
+ fontName = split[1];
+ }
+ }
+ }
+
+ if (fontName.Contains('-'))
+ {
+ var infos = fontName.Split('-');
+ fontName = infos[0];
+
+ for (int i = 1; i < infos.Length; i++)
+ {
+ string infoLower = infos[i].ToLowerInvariant();
+ if (infoLower.Contains("light"))
+ {
+ weight = "lighter";
+ }
+ else if (infoLower.Contains("bolder"))
+ {
+ weight = "bolder";
+ }
+ else if (infoLower.Contains("bold"))
+ {
+ weight = "bold";
+ }
+
+ if (infoLower.Contains("italic"))
+ {
+ style = "italic";
+ }
+ else if (infoLower.Contains("oblique"))
+ {
+ style = "oblique";
+ }
+ }
+ }
+
+ if (_fonts.ContainsKey(fontName)) fontName = _fonts[fontName];
+ return fontName;
+ }
+
+ private static string ColorToSvg(IColor color)
+ {
+ if (color == null) return "";
+ var (r, g, b) = color.ToRGBValues();
+ return $"rgb({Math.Ceiling(r * 255)},{Math.Ceiling(g * 255)},{Math.Ceiling(b * 255)})";
+ }
+
+ private static string PathToSvg(PdfPath p, double height)
+ {
+ var builder = new StringBuilder();
+ foreach (var subpath in p)
+ {
+ foreach (var command in subpath.Commands)
+ {
+ command.WriteSvg(builder, height);
+ }
+ }
+
+ if (builder.Length == 0)
+ {
+ return string.Empty;
+ }
+
+ if (builder[builder.Length - 1] == ' ')
+ {
+ builder.Remove(builder.Length - 1, 1);
+ }
+
+ var glyph = builder.ToString();
+
+ string dashArray = "";
+ string capStyle = "";
+ string jointStyle = "";
+ string strokeColor = " stroke='none'";
+ string strokeWidth = "";
+
+ if (p.IsStroked)
+ {
+ strokeColor = $" stroke='{ColorToSvg(p.StrokeColor)}'";
+ strokeWidth = $" stroke-width='{p.LineWidth}'";
+
+ if (p.LineDashPattern.HasValue && p.LineDashPattern.Value.Array.Count > 0)
+ {
+ dashArray = $" stroke-dasharray='{string.Join(" ", p.LineDashPattern.Value.Array)}'";
+ }
+
+ if (p.LineCapStyle != LineCapStyle.Butt)
+ {
+ if (p.LineCapStyle == LineCapStyle.Round)
+ {
+ capStyle = " stroke-linecap='round'";
+ }
+ else
+ {
+ capStyle = " stroke-linecap='square'";
+ }
+ }
+
+ if (p.LineJoinStyle != LineJoinStyle.Miter)
+ {
+ if (p.LineJoinStyle == LineJoinStyle.Round)
+ {
+ jointStyle = " stroke-linejoin='round'";
+ }
+ else
+ {
+ jointStyle = " stroke-linejoin='bevel'";
+ }
+ }
+ }
+
+ string fillColor = " fill='none'";
+ string fillRule = "";
+
+ if (p.IsFilled)
+ {
+ fillColor = $" fill='{ColorToSvg(p.FillColor)}'";
+ //if (p.FillingRule == FillingRule.EvenOdd) fillRule = " fill-rule='evenodd'";
+ }
+
+ var path = $"";
+ return path;
+ }
+ }
+}
diff --git a/src/UglyToad.PdfPig.Tests/Fonts/CharacterPathTests.cs b/src/UglyToad.PdfPig.Tests/Fonts/CharacterPathTests.cs
index 59d9505d..71efdc6d 100644
--- a/src/UglyToad.PdfPig.Tests/Fonts/CharacterPathTests.cs
+++ b/src/UglyToad.PdfPig.Tests/Fonts/CharacterPathTests.cs
@@ -53,9 +53,9 @@
new PdfPoint(140, 160));
var builder = new StringBuilder();
- curve.WriteSvg(builder);
+ curve.WriteSvg(builder, 0);
- Assert.Equal("C 75 30, 215 115, 140 160 ", builder.ToString());
+ Assert.Equal("C 75 -30, 215 -115, 140 -160 ", builder.ToString());
}
}
}
diff --git a/src/UglyToad.PdfPig.Tests/Fonts/Type1/Type1FontParserTests.cs b/src/UglyToad.PdfPig.Tests/Fonts/Type1/Type1FontParserTests.cs
index b1693255..dee960b1 100644
--- a/src/UglyToad.PdfPig.Tests/Fonts/Type1/Type1FontParserTests.cs
+++ b/src/UglyToad.PdfPig.Tests/Fonts/Type1/Type1FontParserTests.cs
@@ -63,7 +63,7 @@
foreach (var charString in result.CharStrings.CharStrings)
{
Assert.True(result.CharStrings.TryGenerate(charString.Key, out var path));
- builder.AppendLine(path.ToFullSvg());
+ builder.AppendLine(path.ToFullSvg(double.NaN)); // TODO
}
builder.Append("