|
@@ -2,6 +2,9 @@
|
|
|
using netDxf.Tables;
|
|
|
using Svg;
|
|
|
using Svg.Transforms;
|
|
|
+using Syncfusion.Pdf;
|
|
|
+using Syncfusion.Pdf.Graphics;
|
|
|
+using Syncfusion.Pdf.Parsing;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Drawing;
|
|
@@ -14,10 +17,36 @@ using FontStyle = System.Drawing.FontStyle;
|
|
|
using Vector2 = System.Numerics.Vector2;
|
|
|
using Vector3 = System.Numerics.Vector3;
|
|
|
using Vector4 = System.Numerics.Vector4;
|
|
|
+using SPdfGraphics = Syncfusion.Pdf.Graphics.PdfGraphics;
|
|
|
+using Syncfusion.Pdf.Tables;
|
|
|
+using netDxf.Entities;
|
|
|
|
|
|
namespace InABox.Dxf;
|
|
|
|
|
|
-internal class TransformData
|
|
|
+public enum TextAlignment
|
|
|
+{
|
|
|
+ Left,
|
|
|
+ Center,
|
|
|
+ Right,
|
|
|
+ Justify
|
|
|
+}
|
|
|
+
|
|
|
+public enum TextLineAlignment
|
|
|
+{
|
|
|
+ Top,
|
|
|
+ Center,
|
|
|
+ Bottom,
|
|
|
+ Baseline
|
|
|
+}
|
|
|
+
|
|
|
+public class TextFormat
|
|
|
+{
|
|
|
+ public TextAlignment Alignment { get; set; } = TextAlignment.Left;
|
|
|
+
|
|
|
+ public TextLineAlignment LineAlignment { get; set; } = TextLineAlignment.Top;
|
|
|
+}
|
|
|
+
|
|
|
+public class TransformData
|
|
|
{
|
|
|
public DxfData Data { get; set; }
|
|
|
|
|
@@ -30,6 +59,11 @@ internal class TransformData
|
|
|
MatrixStack.Push(Transform);
|
|
|
}
|
|
|
|
|
|
+ public void TransformBy(Matrix4x4 matrix)
|
|
|
+ {
|
|
|
+ Transform = matrix * Transform;
|
|
|
+ }
|
|
|
+
|
|
|
protected virtual void UpdateTransform()
|
|
|
{
|
|
|
}
|
|
@@ -107,11 +141,6 @@ internal class TransformData
|
|
|
UpdateTransform();
|
|
|
}
|
|
|
|
|
|
- public float ConvertThickness(float thickness)
|
|
|
- {
|
|
|
- return thickness == 0 ? 1f / ScaleFactor() : thickness;
|
|
|
- }
|
|
|
-
|
|
|
public PointF TransformPoint(float x, float y)
|
|
|
{
|
|
|
var nVec = Vector4.Transform(new Vector4(x, y, 0, 1), Transform);
|
|
@@ -160,9 +189,61 @@ internal class TransformData
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-internal class DrawData : TransformData
|
|
|
+public class DrawData : TransformData
|
|
|
{
|
|
|
- public IGraphics Graphics { get; set; }
|
|
|
+ private IGraphics _graphics;
|
|
|
+ public IGraphics Graphics
|
|
|
+ {
|
|
|
+ get => _graphics;
|
|
|
+ set
|
|
|
+ {
|
|
|
+ _graphics = value;
|
|
|
+ _graphics.DrawData = this;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Stack<Color> _blockColours = new();
|
|
|
+
|
|
|
+ public Color BlockColour { get; set; } = Color.Black;
|
|
|
+
|
|
|
+ public void PushBlockColour(AciColor colour, EntityObject? obj)
|
|
|
+ {
|
|
|
+ _blockColours.Push(BlockColour);
|
|
|
+ BlockColour = ResolveColour(colour, obj);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void PushBlockColour(Color colour)
|
|
|
+ {
|
|
|
+ _blockColours.Push(BlockColour);
|
|
|
+ BlockColour = colour;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void PopBlockColour()
|
|
|
+ {
|
|
|
+ BlockColour = _blockColours.Pop();
|
|
|
+ }
|
|
|
+
|
|
|
+ public Color ResolveColour(AciColor colour, EntityObject? obj)
|
|
|
+ {
|
|
|
+ if (colour.IsByBlock)
|
|
|
+ {
|
|
|
+ return _blockColours.Count > 0
|
|
|
+ ? BlockColour
|
|
|
+ : (obj?.Layer is null ? Color.Black : ResolveColour(obj.Layer.Color, null));
|
|
|
+ }
|
|
|
+ else if (colour.IsByLayer)
|
|
|
+ {
|
|
|
+ return obj?.Layer is null ? Color.Black : ResolveColour(obj.Layer.Color, null);
|
|
|
+ }
|
|
|
+ if(colour.Index == 7)
|
|
|
+ {
|
|
|
+ return Color.Black;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return colour.ToColor();
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
protected override void UpdateTransform()
|
|
|
{
|
|
@@ -173,6 +254,8 @@ internal class DrawData : TransformData
|
|
|
|
|
|
public interface IGraphics
|
|
|
{
|
|
|
+ DrawData DrawData { get; set; }
|
|
|
+
|
|
|
void SetTransform(Matrix transform);
|
|
|
|
|
|
void DrawLine(Color color, float thickness, params PointF[] points);
|
|
@@ -187,9 +270,11 @@ public interface IGraphics
|
|
|
|
|
|
void SetFont(string fontName, float fontSize, FontStyle fontStyle = FontStyle.Regular);
|
|
|
|
|
|
- void DrawText(string text, Color color, PointF position);
|
|
|
+ void DrawText(string text, Color color, PointF position, float rotation, TextFormat format);
|
|
|
|
|
|
void Clear(Color color);
|
|
|
+
|
|
|
+ void Finish();
|
|
|
}
|
|
|
|
|
|
public class GdiGraphics : IGraphics
|
|
@@ -198,11 +283,18 @@ public class GdiGraphics : IGraphics
|
|
|
|
|
|
private Font Font { get; set; }
|
|
|
|
|
|
+ public DrawData DrawData { get; set; }
|
|
|
+
|
|
|
public GdiGraphics(Graphics graphics)
|
|
|
{
|
|
|
Graphics = graphics;
|
|
|
}
|
|
|
|
|
|
+ // public float ConvertThickness(float thickness)
|
|
|
+ // {
|
|
|
+ // return thickness == 0 ? 1f / ScaleFactor() : thickness;
|
|
|
+ // }
|
|
|
+
|
|
|
public void DrawLine(Color color, float thickness, params PointF[] points)
|
|
|
{
|
|
|
if(points.Length == 2)
|
|
@@ -215,9 +307,56 @@ public class GdiGraphics : IGraphics
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public void DrawText(string text, Color color, PointF position)
|
|
|
+ private void TransformText(string text, Font font, PointF position, float rotation, TextFormat format)
|
|
|
{
|
|
|
- Graphics.DrawString(text, Font, new SolidBrush(color), position, StringFormat.GenericTypographic);
|
|
|
+ DrawData.Translate(position);
|
|
|
+ DrawData.Rotate(rotation);
|
|
|
+ DrawData.Scale(1, -1);
|
|
|
+
|
|
|
+ var size = Graphics.MeasureString(text, font, new PointF(), StringFormat.GenericTypographic);
|
|
|
+ switch (format.LineAlignment)
|
|
|
+ {
|
|
|
+ case TextLineAlignment.Center:
|
|
|
+ DrawData.Translate(new PointF(0, -size.Height / 2));
|
|
|
+ break;
|
|
|
+ case TextLineAlignment.Bottom:
|
|
|
+ DrawData.Translate(new PointF(0, -size.Height));
|
|
|
+ break;
|
|
|
+ case TextLineAlignment.Baseline:
|
|
|
+ var ascent = font.FontFamily.GetCellAscent(font.Style);
|
|
|
+ var baseline = ascent * font.Height / font.FontFamily.GetEmHeight(font.Style);
|
|
|
+ DrawData.Translate(new PointF(0, -baseline));
|
|
|
+ break;
|
|
|
+ case TextLineAlignment.Top:
|
|
|
+ ascent = font.FontFamily.GetCellAscent(font.Style);
|
|
|
+ baseline = ascent * font.Height / font.FontFamily.GetEmHeight(font.Style);
|
|
|
+ var lineSpace = font.FontFamily.GetLineSpacing(font.Style);
|
|
|
+ var ratio = font.GetHeight(Graphics) / lineSpace;
|
|
|
+ DrawData.Translate(new PointF(0, -baseline + ascent * ratio));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (format.Alignment)
|
|
|
+ {
|
|
|
+ case TextAlignment.Left:
|
|
|
+ break;
|
|
|
+ case TextAlignment.Center:
|
|
|
+ DrawData.Translate(new PointF(-(float)size.Width / 2, 0));
|
|
|
+ break;
|
|
|
+ case TextAlignment.Right:
|
|
|
+ DrawData.Translate(new PointF(-(float)size.Width, 0));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void DrawText(string text, Color color, PointF position, float rotation, TextFormat format)
|
|
|
+ {
|
|
|
+ DrawData.PushTransform();
|
|
|
+ TransformText(text, Font, position, rotation, format);
|
|
|
+
|
|
|
+ Graphics.DrawString(text, Font, new SolidBrush(color), new PointF(0, 0), StringFormat.GenericTypographic);
|
|
|
+
|
|
|
+ DrawData.PopTransform();
|
|
|
}
|
|
|
|
|
|
public void FillPolygon(Color color, params PointF[] points)
|
|
@@ -248,20 +387,146 @@ public class GdiGraphics : IGraphics
|
|
|
{
|
|
|
Graphics.Clear(color);
|
|
|
}
|
|
|
+
|
|
|
+ public void Finish()
|
|
|
+ {
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+public class PdfGraphics : IGraphics
|
|
|
+{
|
|
|
+ public DrawData DrawData { get; set; }
|
|
|
+
|
|
|
+ private SPdfGraphics Graphics { get; set; }
|
|
|
+
|
|
|
+ private Matrix _transform = new();
|
|
|
+
|
|
|
+ private PdfFont _font = new PdfStandardFont(PdfFontFamily.Helvetica, 12, PdfFontStyle.Regular);
|
|
|
+
|
|
|
+ public PdfGraphics(SPdfGraphics graphics)
|
|
|
+ {
|
|
|
+ Graphics = graphics;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Clear(Color color)
|
|
|
+ {
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetTransform(Matrix transform)
|
|
|
+ {
|
|
|
+ _transform = transform;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void DrawLine(Color color, float thickness, params PointF[] points)
|
|
|
+ {
|
|
|
+ _transform.TransformPoints(points);
|
|
|
+
|
|
|
+ var pen = new PdfPen(color, thickness);
|
|
|
+ for(int i = 0; i < points.Length - 1; ++i)
|
|
|
+ {
|
|
|
+ Graphics.DrawLine(pen, points[i], points[i + 1]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetFont(float fontSize, FontStyle fontStyle = FontStyle.Regular)
|
|
|
+ {
|
|
|
+ _font = new PdfTrueTypeFont(new Font(SystemFonts.DefaultFont.FontFamily, fontSize));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetFont(string fontName, float fontSize, FontStyle fontStyle = FontStyle.Regular)
|
|
|
+ {
|
|
|
+ _font = new PdfTrueTypeFont(new Font(fontName, fontSize));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void DrawText(string text, Color color, PointF position, float rotation, TextFormat format)
|
|
|
+ {
|
|
|
+ var fmt = new PdfStringFormat();
|
|
|
+ fmt.Alignment = format.Alignment switch
|
|
|
+ {
|
|
|
+ TextAlignment.Center => PdfTextAlignment.Center,
|
|
|
+ TextAlignment.Right => PdfTextAlignment.Right,
|
|
|
+ TextAlignment.Justify => PdfTextAlignment.Justify,
|
|
|
+ _ => PdfTextAlignment.Left,
|
|
|
+ };
|
|
|
+ fmt.LineAlignment = format.LineAlignment switch
|
|
|
+ {
|
|
|
+ TextLineAlignment.Center => PdfVerticalAlignment.Middle,
|
|
|
+ TextLineAlignment.Bottom => PdfVerticalAlignment.Bottom,
|
|
|
+ _ => PdfVerticalAlignment.Top
|
|
|
+ };
|
|
|
+ if(format.LineAlignment == TextLineAlignment.Baseline)
|
|
|
+ {
|
|
|
+ fmt.EnableBaseline = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ Graphics.Save();
|
|
|
+
|
|
|
+ var point = _transform.Transform(position);
|
|
|
+ Graphics.TranslateTransform(point.X, point.Y);
|
|
|
+ Graphics.RotateTransform(-(_transform.GetRotation() + rotation));
|
|
|
+ var scale = (_font.Height / _font.Size) * _transform.GetScale();
|
|
|
+ Graphics.ScaleTransform(scale, scale);
|
|
|
+ Graphics.DrawString(text, _font, new PdfSolidBrush(color), new PointF(), fmt);
|
|
|
+
|
|
|
+ Graphics.Restore();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void FillPolygon(Color color, params PointF[] points)
|
|
|
+ {
|
|
|
+ _transform.TransformPoints(points);
|
|
|
+ var brush = new PdfSolidBrush(color);
|
|
|
+ Graphics.DrawPolygon(brush, points);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Finish()
|
|
|
+ {
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
public class SvgGraphics : IGraphics
|
|
|
{
|
|
|
+ public DrawData DrawData { get; set; }
|
|
|
+
|
|
|
public SvgDocument Document { get; set; }
|
|
|
|
|
|
- private SvgMatrix _transform;
|
|
|
+ private SvgMatrix _transform = new(new Matrix().Elements.ToList());
|
|
|
|
|
|
private SvgGroup _group;
|
|
|
+ private Matrix _groupTransform = new();
|
|
|
+
|
|
|
+ private static string[][] _groupProps = new[]
|
|
|
+ {
|
|
|
+ new[] { "stroke-width", "style" },
|
|
|
+ new[] { "vector-effect" }
|
|
|
+ };
|
|
|
|
|
|
public SvgGraphics(SvgDocument document)
|
|
|
{
|
|
|
Document = document;
|
|
|
_group = new SvgGroup();
|
|
|
+ Document.Stroke = new SvgColourServer(Color.Black);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void PushGroup()
|
|
|
+ {
|
|
|
+ if(_group.Children.Count > 0)
|
|
|
+ {
|
|
|
+ Document.Children.Add(_group);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void AddChild(SvgElement item)
|
|
|
+ {
|
|
|
+ var transMat = _transform.Matrix;
|
|
|
+ if(!Equals(transMat, _groupTransform))
|
|
|
+ {
|
|
|
+ PushGroup();
|
|
|
+
|
|
|
+ _group = new();
|
|
|
+ _group.Transforms = new() { _transform };
|
|
|
+ _groupTransform = transMat;
|
|
|
+ }
|
|
|
+ _group.Children.Add(item);
|
|
|
}
|
|
|
|
|
|
public void SetTransform(Matrix transform)
|
|
@@ -273,38 +538,51 @@ public class SvgGraphics : IGraphics
|
|
|
{
|
|
|
if(points.Length == 2)
|
|
|
{
|
|
|
- Document.Children.Add(new SvgLine
|
|
|
+ var line = new SvgLine
|
|
|
{
|
|
|
StartX = points[0].X,
|
|
|
StartY = points[0].Y,
|
|
|
EndX = points[1].X,
|
|
|
- EndY = points[1].Y,
|
|
|
- Transforms = new()
|
|
|
- {
|
|
|
- _transform
|
|
|
- },
|
|
|
- Stroke = new SvgColourServer(color),
|
|
|
- StrokeWidth = thickness
|
|
|
- });
|
|
|
+ EndY = points[1].Y
|
|
|
+ };
|
|
|
+ if(color != Color.Black)
|
|
|
+ {
|
|
|
+ line.Stroke = new SvgColourServer(color);
|
|
|
+ }
|
|
|
+ if(thickness == 0)
|
|
|
+ {
|
|
|
+ line.StrokeWidth = 1;
|
|
|
+ line.CustomAttributes.Add("vector-effect", "non-scaling-stroke");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ line.StrokeWidth = thickness;
|
|
|
+ }
|
|
|
+ AddChild(line);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- var line = new SvgPolyline
|
|
|
+ var line = new SvgPolyline();
|
|
|
+ if(color != Color.Black)
|
|
|
{
|
|
|
- Transforms = new()
|
|
|
- {
|
|
|
- _transform
|
|
|
- },
|
|
|
- Stroke = new SvgColourServer(color),
|
|
|
- StrokeWidth = thickness
|
|
|
- };
|
|
|
+ line.Stroke = new SvgColourServer(color);
|
|
|
+ }
|
|
|
foreach(var point in points)
|
|
|
{
|
|
|
line.Points.Add(point.X);
|
|
|
line.Points.Add(point.Y);
|
|
|
}
|
|
|
+ if(thickness == 0)
|
|
|
+ {
|
|
|
+ line.StrokeWidth = 1;
|
|
|
+ line.CustomAttributes.Add("vector-effect", "non-scaling-stroke");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ line.StrokeWidth = thickness;
|
|
|
+ }
|
|
|
|
|
|
- Document.Children.Add(line);
|
|
|
+ AddChild(line);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -320,11 +598,16 @@ public class SvgGraphics : IGraphics
|
|
|
{
|
|
|
}
|
|
|
|
|
|
- public void DrawText(string text, Color color, PointF position)
|
|
|
+ public void DrawText(string text, Color color, PointF position, float rotation, TextFormat format)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
public void Clear(Color color)
|
|
|
{
|
|
|
}
|
|
|
+
|
|
|
+ public void Finish()
|
|
|
+ {
|
|
|
+ PushGroup();
|
|
|
+ }
|
|
|
}
|