diff --git a/.gitignore b/.gitignore
index e136e4a4..101a6dc8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,3 +53,4 @@ InternalAgentState.json
*tempfile.*
launchsettings.json
testEnvironments.json
+.cr/
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Pdf/PdfGraphicsState.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Pdf/PdfGraphicsState.cs
index 69fcc3f7..49a7c208 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Pdf/PdfGraphicsState.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Pdf/PdfGraphicsState.cs
@@ -42,13 +42,15 @@ public PdfGraphicsState Clone()
public void PushState()
{
// BeginGraphic
- renderer.Append("q/n");
+ renderer.Append("q");
+ renderer.Append(renderer.Owner.Options.LineEnding);
}
public void PopState()
{
//BeginGraphic
- renderer.Append("Q/n");
+ renderer.Append("Q");
+ renderer.Append(renderer.Owner.Options.LineEnding);
}
#region Stroke
@@ -64,8 +66,8 @@ public void PopState()
public void RealizePen(XPen pen, PdfColorMode colorMode)
{
- const string format = Config.SignificantDecimalPlaces3;
const string format2 = Config.SignificantDecimalPlaces2;
+ const string format3 = Config.SignificantDecimalPlaces3;
XColor color = pen.Color;
bool overPrint = pen.Overprint;
@@ -73,19 +75,22 @@ public void RealizePen(XPen pen, PdfColorMode colorMode)
if (_realizedLineWith != pen.Width)
{
- renderer.AppendFormatArgs("{0:" + format + "} w\n", pen.Width);
+ renderer.AppendFormatArgs("{0:" + format3 + "} w", pen.Width);
+ renderer.Append(renderer.Owner.Options.LineEnding);
_realizedLineWith = pen.Width;
}
if (_realizedLineCap != (int)pen.LineCap)
{
- renderer.AppendFormatArgs("{0} J\n", (int)pen.LineCap);
+ renderer.AppendFormatArgs("{0} J", (int)pen.LineCap);
+ renderer.Append(renderer.Owner.Options.LineEnding);
_realizedLineCap = (int)pen.LineCap;
}
if (_realizedLineJoin != (int)pen.LineJoin)
{
- renderer.AppendFormatArgs("{0} j\n", (int)pen.LineJoin);
+ renderer.AppendFormatArgs("{0} j", (int)pen.LineJoin);
+ renderer.Append(renderer.Owner.Options.LineEnding);
_realizedLineJoin = (int)pen.LineJoin;
}
@@ -93,7 +98,8 @@ public void RealizePen(XPen pen, PdfColorMode colorMode)
{
if (_realizedMiterLimit != (int)pen.MiterLimit && (int)pen.MiterLimit != 0)
{
- renderer.AppendFormatInt("{0} M\n", (int)pen.MiterLimit);
+ renderer.AppendFormatInt("{0} M", (int)pen.MiterLimit);
+ renderer.Append(renderer.Owner.Options.LineEnding);
_realizedMiterLimit = (int)pen.MiterLimit;
}
}
@@ -111,23 +117,28 @@ public void RealizePen(XPen pen, PdfColorMode colorMode)
switch (dashStyle)
{
case XDashStyle.Solid:
- renderer.Append("[]0 d\n");
+ renderer.Append("[]0 d");
+ renderer.Append(renderer.Owner.Options.LineEnding);
break;
case XDashStyle.Dash:
- renderer.AppendFormatArgs("[{0:" + format2 + "} {1:" + format2 + "}]0 d\n", dash, dot);
+ renderer.AppendFormatArgs("[{0:" + format2 + "} {1:" + format2 + "}]0 d", dash, dot);
+ renderer.Append(renderer.Owner.Options.LineEnding);
break;
case XDashStyle.Dot:
- renderer.AppendFormatArgs("[{0:" + format2 + "}]0 d\n", dot);
+ renderer.AppendFormatArgs("[{0:" + format2 + "}]0 d", dot);
+ renderer.Append(renderer.Owner.Options.LineEnding);
break;
case XDashStyle.DashDot:
- renderer.AppendFormatArgs("[{0:" + format2 + "} {1:" + format2 + "} {1:" + format2 + "} {1:" + format2 + "}]0 d\n", dash, dot);
+ renderer.AppendFormatArgs("[{0:" + format2 + "} {1:" + format2 + "} {1:" + format2 + "} {1:" + format2 + "}]0 d", dash, dot);
+ renderer.Append(renderer.Owner.Options.LineEnding);
break;
case XDashStyle.DashDotDot:
- renderer.AppendFormatArgs("[{0:" + format2 + "} {1:" + format2 + "} {1:" + format2 + "} {1:" + format2 + "} {1:" + format2 + "} {1:" + format2 + "}]0 d\n", dash, dot);
+ renderer.AppendFormatArgs("[{0:" + format2 + "} {1:" + format2 + "} {1:" + format2 + "} {1:" + format2 + "} {1:" + format2 + "} {1:" + format2 + "}]0 d", dash, dot);
+ renderer.Append(renderer.Owner.Options.LineEnding);
break;
case XDashStyle.Custom:
@@ -146,7 +157,8 @@ public void RealizePen(XPen pen, PdfColorMode colorMode)
pdf.Append(' ');
pdf.Append(PdfEncoders.ToString(0.2 * pen.Width));
}
- pdf.AppendFormat(CultureInfo.InvariantCulture, "]{0:" + format + "} d\n", pen.DashOffset * pen.Width);
+ pdf.AppendFormat(CultureInfo.InvariantCulture, "]{0:" + format3 + "} d", pen.DashOffset * pen.Width);
+ pdf.Append(renderer.Owner.Options.LineEnding);
string pattern = pdf.ToString();
// IMPROVE
@@ -168,7 +180,8 @@ public void RealizePen(XPen pen, PdfColorMode colorMode)
if (_realizedStrokeColor.Rgb != color.Rgb)
{
renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Rgb));
- renderer.Append(" RG\n");
+ renderer.Append(" RG");
+ renderer.Append(renderer.Owner.Options.LineEnding);
}
}
else
@@ -176,7 +189,8 @@ public void RealizePen(XPen pen, PdfColorMode colorMode)
if (!ColorSpaceHelper.IsEqualCmyk(_realizedStrokeColor, color))
{
renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Cmyk));
- renderer.Append(" K\n");
+ renderer.Append(" K");
+ renderer.Append(renderer.Owner.Options.LineEnding);
}
}
@@ -184,7 +198,8 @@ public void RealizePen(XPen pen, PdfColorMode colorMode)
{
PdfExtGState extGState = renderer.Owner.ExtGStateTable.GetExtGStateStroke(color.A, overPrint);
string gs = renderer.Resources.AddExtGState(extGState);
- renderer.AppendFormatString("{0} gs\n", gs);
+ renderer.AppendFormatString("{0} gs", gs);
+ renderer.Append(renderer.Owner.Options.LineEnding);
// Must create transparency group.
if (renderer._page != null! && color.A < 1)
@@ -238,8 +253,10 @@ public void RealizeBrush(XBrush brush, PdfColorMode colorMode, int renderingMode
PdfShadingPattern pattern = new PdfShadingPattern(renderer.Owner);
pattern.SetupFromBrush(gradientBrush, matrix, renderer);
string name = renderer.Resources.AddPattern(pattern);
- renderer.AppendFormatString("/Pattern cs\n", name);
- renderer.AppendFormatString("{0} scn\n", name);
+ renderer.AppendFormatString("/Pattern cs", name);
+ renderer.Append(renderer.Owner.Options.LineEnding);
+ renderer.AppendFormatString("{0} scn", name);
+ renderer.Append(renderer.Owner.Options.LineEnding);
// Invalidate fill color.
_realizedFillColor = XColor.Empty;
@@ -256,7 +273,8 @@ void RealizeFillColor(XColor color, bool overPrint, PdfColorMode colorMode)
if (_realizedFillColor.IsEmpty || _realizedFillColor.Rgb != color.Rgb)
{
renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Rgb));
- renderer.Append(" rg\n");
+ renderer.Append(" rg");
+ renderer.Append(renderer.Owner.Options.LineEnding);
}
}
else
@@ -266,7 +284,8 @@ void RealizeFillColor(XColor color, bool overPrint, PdfColorMode colorMode)
if (_realizedFillColor.IsEmpty || !ColorSpaceHelper.IsEqualCmyk(_realizedFillColor, color))
{
renderer.Append(PdfEncoders.ToString(color, PdfColorMode.Cmyk));
- renderer.Append(" k\n");
+ renderer.Append(" k");
+ renderer.Append(renderer.Owner.Options.LineEnding);
}
}
@@ -275,7 +294,8 @@ void RealizeFillColor(XColor color, bool overPrint, PdfColorMode colorMode)
PdfExtGState extGState = renderer.Owner.ExtGStateTable.GetExtGStateNonStroke(color.A, overPrint);
string gs = renderer.Resources.AddExtGState(extGState);
- renderer.AppendFormatString("{0} gs\n", gs);
+ renderer.AppendFormatString("{0} gs", gs);
+ renderer.Append(renderer.Owner.Options.LineEnding);
// Must create transparency group.
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
@@ -307,7 +327,8 @@ internal void RealizeNonStrokeTransparency(double transparency, PdfColorMode col
public void RealizeFont(XGlyphTypeface glyphTypeface, double emSize, XBrush brush, int renderingMode, FontType fontType)
{
- const string format = Config.SignificantDecimalPlaces3;
+ const string format3 = Config.SignificantDecimalPlaces3;
+ const string format = "{0} {1:" + format3 + "} Tf";
// So far rendering mode 0 (fill text) and 2 (fill, then stroke text) only.
RealizeBrush(brush, renderer._colorMode, renderingMode, emSize); // _renderer.page.document.Options.ColorMode);
@@ -315,7 +336,8 @@ public void RealizeFont(XGlyphTypeface glyphTypeface, double emSize, XBrush brus
// Realize rendering mode.
if (_realizedRenderingMode != renderingMode)
{
- renderer.AppendFormatInt("{0} Tr\n", renderingMode);
+ renderer.AppendFormatInt("{0} Tr", renderingMode);
+ renderer.Append(renderer.Owner.Options.LineEnding);
_realizedRenderingMode = renderingMode;
}
@@ -324,7 +346,8 @@ public void RealizeFont(XGlyphTypeface glyphTypeface, double emSize, XBrush brus
{
if (_realizedCharSpace != 0)
{
- renderer.Append("0 Tc\n");
+ renderer.Append("0 Tc");
+ renderer.Append(renderer.Owner.Options.LineEnding);
_realizedCharSpace = 0;
}
}
@@ -333,7 +356,8 @@ public void RealizeFont(XGlyphTypeface glyphTypeface, double emSize, XBrush brus
double charSpace = emSize * Const.BoldEmphasis;
if (_realizedCharSpace != charSpace)
{
- renderer.AppendFormatDouble("{0:" + format + "} Tc\n", charSpace);
+ renderer.AppendFormatDouble("{0:" + format3 + "} Tc", charSpace);
+ renderer.Append(renderer.Owner.Options.LineEnding);
_realizedCharSpace = charSpace;
}
}
@@ -342,26 +366,24 @@ public void RealizeFont(XGlyphTypeface glyphTypeface, double emSize, XBrush brus
string fontName = renderer.GetFontName(glyphTypeface, fontType, out _realizedFont);
if (fontName != _realizedFontName || _realizedFontSize != emSize)
{
- s_formatTf ??= "{0} {1:" + format + "} Tf\n";
if (renderer.Gfx.PageDirection == XPageDirection.Downwards)
{
// earlier:
// renderer.AppendFormatFont("{0} {1:" + format + "} Tf\n", fontName, emSize);
- renderer.AppendFormatFont(s_formatTf, fontName, emSize);
+ renderer.AppendFormatFont(format, fontName, emSize);
+ renderer.Append(renderer.Owner.Options.LineEnding);
}
else
{
// earlier:
// renderer.AppendFormatFont("{0} {1:" + format + "} Tf\n", fontName, emSize);
- renderer.AppendFormatFont(s_formatTf, fontName, emSize);
+ renderer.AppendFormatFont(format, fontName, emSize);
+ renderer.Append(renderer.Owner.Options.LineEnding);
}
_realizedFontName = fontName;
_realizedFontSize = emSize;
}
}
- // ReSharper disable InconsistentNaming
- static string? s_formatTf;
- // ReSharper restore InconsistentNaming
public XPoint RealizedTextPosition;
@@ -445,21 +467,22 @@ public void AddTransform(XMatrix value, XMatrixOrder matrixOrder)
///
public void RealizeCtm()
{
+ const string format7 = Config.SignificantDecimalPlaces7;
+ const string format = "{0:" + format7 + "} {1:" + format7 + "} {2:" + format7 + "} {3:" + format7 + "} {4:"
+ + format7 + "} {5:" + format7 + "} cm";
+
//if (MustRealizeCtm)
if (!UnrealizedCtm.IsIdentity)
{
Debug.Assert(!UnrealizedCtm.IsIdentity, "mrCtm is unnecessarily set.");
- const string format = Config.SignificantDecimalPlaces7;
- s_formatCtm ??= "{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:"
- + format + "} {5:" + format + "} cm\n";
-
double[] matrix = UnrealizedCtm.GetElements();
// Use up to six decimal digits to prevent round up problems.
// earlier:
// renderer.AppendFormatArgs("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} cm\n",
// matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
- renderer.AppendFormatArgs(s_formatCtm, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
+ renderer.AppendFormatArgs(format, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
+ renderer.Append(renderer.Owner.Options.LineEnding);
RealizedCtm.Prepend(UnrealizedCtm);
UnrealizedCtm = new XMatrix();
@@ -468,9 +491,6 @@ public void RealizeCtm()
InverseEffectiveCtm.Invert();
}
}
- // ReSharper disable InconsistentNaming
- static string? s_formatCtm;
- // ReSharper restore InconsistentNaming
#endregion
#region Clip Path
@@ -519,7 +539,8 @@ void RealizeClipPath(XGraphicsPath clipPath)
else
renderer.AppendPath(clipPath._pathGeometry);
#endif
- renderer.Append(clipPath.FillMode == XFillMode.Winding ? "W n\n" : "W* n\n");
+ renderer.Append(clipPath.FillMode == XFillMode.Winding ? "W n" : "W* n");
+ renderer.Append(renderer.Owner.Options.LineEnding);
}
#endregion
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Pdf/XGraphicsPdfRenderer.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Pdf/XGraphicsPdfRenderer.cs
index 32a856c6..39120213 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Pdf/XGraphicsPdfRenderer.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.Pdf/XGraphicsPdfRenderer.cs
@@ -131,10 +131,15 @@ public void DrawLines(XPen pen, XPoint[] points)
Realize(pen);
const string format = Config.SignificantDecimalPlaces4;
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", points[0].X, points[0].Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} m", points[0].X, points[0].Y);
+ _content.Append(Owner.Options.LineEnding);
for (int idx = 1; idx < count; idx++)
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} l\n", points[idx].X, points[idx].Y);
- _content.Append("S\n");
+ {
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} l", points[idx].X, points[idx].Y);
+ _content.Append(Owner.Options.LineEnding);
+ }
+ _content.Append("S");
+ _content.Append(Owner.Options.LineEnding);
}
// ----- DrawBezier ---------------------------------------------------------------------------
@@ -167,12 +172,16 @@ public void DrawBeziers(XPen pen, XPoint[] points)
Realize(pen);
const string format = Config.SignificantDecimalPlaces4;
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", points[0].X, points[0].Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} m", points[0].X, points[0].Y);
+ _content.Append(Owner.Options.LineEnding);
for (int idx = 1; idx < count; idx += 3)
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n",
+ {
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c",
points[idx].X, points[idx].Y,
points[idx + 1].X, points[idx + 1].Y,
points[idx + 2].X, points[idx + 2].Y);
+ _content.Append(Owner.Options.LineEnding);
+ }
AppendStrokeFill(pen, null, XFillMode.Alternate, false);
}
@@ -202,7 +211,8 @@ public void DrawCurve(XPen pen, XPoint[] points, double tension)
Realize(pen);
const string format = Config.SignificantDecimalPlaces4;
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", points[0].X, points[0].Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} m", points[0].X, points[0].Y);
+ _content.Append(Owner.Options.LineEnding);
if (count == 2)
{
// Just draws a line.
@@ -252,14 +262,16 @@ public void DrawRectangle(XPen? pen, XBrush? brush, double x, double y, double w
Realize(pen, brush);
//AppendFormat123("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} re\n", x, y, width, -height);
- AppendFormatRect("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} re\n", x, y + height, width, height);
+ AppendFormatRect("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} re", x, y + height, width, height);
+ _content.Append(Owner.Options.LineEnding);
if (pen != null && brush != null)
- _content.Append("B\n");
+ _content.Append("B");
else if (pen != null)
- _content.Append("S\n");
+ _content.Append("S");
else
- _content.Append("f\n");
+ _content.Append("f");
+ _content.Append(Owner.Options.LineEnding);
}
// ----- DrawRectangles -----------------------------------------------------------------------
@@ -310,15 +322,20 @@ public void DrawEllipse(XPen? pen, XBrush? brush, double x, double y, double wid
// Approximate an ellipse by drawing four cubic splines.
const string format = Config.SignificantDecimalPlaces4;
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", x0 + δx, y0);
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n",
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} m", x0 + δx, y0);
+ _content.Append(Owner.Options.LineEnding);
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c",
x0 + δx, y0 + fy, x0 + fx, y0 + δy, x0, y0 + δy);
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n",
+ _content.Append(Owner.Options.LineEnding);
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c",
x0 - fx, y0 + δy, x0 - δx, y0 + fy, x0 - δx, y0);
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n",
+ _content.Append(Owner.Options.LineEnding);
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c",
x0 - δx, y0 - fy, x0 - fx, y0 - δy, x0, y0 - δy);
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n",
+ _content.Append(Owner.Options.LineEnding);
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c",
x0 + fx, y0 - δy, x0 + δx, y0 - fy, x0 + δx, y0);
+ _content.Append(Owner.Options.LineEnding);
AppendStrokeFill(pen, brush, XFillMode.Winding, true);
}
@@ -337,9 +354,13 @@ public void DrawPolygon(XPen? pen, XBrush? brush, XPoint[] points, XFillMode fil
throw new ArgumentException(PsMsgs.PointArrayAtLeast(2), nameof(points));
const string format = Config.SignificantDecimalPlaces4;
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", points[0].X, points[0].Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} m", points[0].X, points[0].Y);
+ _content.Append(Owner.Options.LineEnding);
for (int idx = 1; idx < count; idx++)
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} l\n", points[idx].X, points[idx].Y);
+ {
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} l", points[idx].X, points[idx].Y);
+ _content.Append(Owner.Options.LineEnding);
+ }
AppendStrokeFill(pen, brush, fillmode, true);
}
@@ -356,7 +377,8 @@ public void DrawPie(XPen? pen, XBrush? brush, double x, double y, double width,
Realize(pen, brush);
const string format = Config.SignificantDecimalPlaces4;
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", x + width / 2, y + height / 2);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} m", x + width / 2, y + height / 2);
+ _content.Append(Owner.Options.LineEnding);
AppendPartialArc(x, y, width, height, startAngle, sweepAngle, PathStart.LineTo1st, new XMatrix());
AppendStrokeFill(pen, brush, XFillMode.Alternate, true);
}
@@ -381,7 +403,8 @@ public void DrawClosedCurve(XPen? pen, XBrush? brush, XPoint[] points, double te
Realize(pen, brush);
const string format = Config.SignificantDecimalPlaces4;
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", points[0].X, points[0].Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} m", points[0].X, points[0].Y);
+ _content.Append(Owner.Options.LineEnding);
if (count == 2)
{
// Just draw a line.
@@ -687,12 +710,14 @@ public void DrawString(string s, XFont font, XBrush brush, XRect rect, XStringFo
var pos = new XPoint(x, y);
pos = WorldToView(pos);
AdjustTdOffset(ref pos, 0, false);
- AppendFormatArgs("{0:" + format2 + "} {1:" + format2 + "} Td {2} Tj\n", pos.X, pos.Y, text);
+ AppendFormatArgs("{0:" + format2 + "} {1:" + format2 + "} Td {2} Tj", pos.X, pos.Y, text);
+ _content.Append(Owner.Options.LineEnding);
}
else
{
// Rest of the layers are rendered on top of the first layer.
- AppendFormatArgs("0 0 Td {0} Tj\n", text);
+ AppendFormatArgs("0 0 Td {0} Tj", text);
+ _content.Append(Owner.Options.LineEnding);
}
}
x += chunkWidth;
@@ -744,7 +769,7 @@ void RenderText(string text, XFont font, XBrush brush, double x, double y, doubl
}
// Select the number of decimal places used for the relative text positioning.
- const string formatTj = Config.SignificantDecimalPlaces4;
+ const string format4 = Config.SignificantDecimalPlaces4;
#if ITALIC_SIMULATION
if (italicSimulation)
{
@@ -752,25 +777,32 @@ void RenderText(string text, XFont font, XBrush brush, double x, double y, doubl
{ // Case: Simulate Italic and simulation is already on.
// Build format string only once.
- s_format1 ??= "{0:" + formatTj + "} {1:" + formatTj + "} Td\n{2} Tj\n";
+ const string s_format1 = "{0:" + format4 + "} {1:" + format4 + "} Td";
+ const string s_format2 = "{0} Tj";
AdjustTdOffset(ref pos, verticalOffset, true);
// earlier:
//AppendFormatArgs("{0:" + format2 + "} {1:" + format2 + "} Td\n{2} Tj\n", pos.X, pos.Y, text);
- AppendFormatArgs(s_format1, pos.X, pos.Y, text);
+ AppendFormatArgs(s_format1, pos.X, pos.Y);
+ _content.Append(Owner.Options.LineEnding);
+ AppendFormatArgs(s_format2, text);
+ _content.Append(Owner.Options.LineEnding);
}
else
{ // Case: Simulate Italic and turn simulation on.
- s_format2 ??= "{0:" + formatTj + "} {1:" + formatTj + "} {2:" + formatTj + "} {3:" + formatTj + "} {4:"
- + formatTj + "} {5:" + formatTj + "} Tm\n{6} Tj\n";
+ const string s_format1 = "{0:" + format4 + "} {1:" + format4 + "} {2:" + format4 + "} {3:" + format4 + "} {4:" + format4 + "} {5:" + format4 + "} Tm";
+ const string s_format2 = "{0} Tj";
// Italic simulation is done by skewing characters 20° to the right.
var m = new XMatrix(1, 0, Const.ItalicSkewAngleSinus, 1, pos.X, pos.Y);
// earlier:
//AppendFormatArgs("{0:" + format2 + "} {1:" + format2 + "} {2:" + format2 + "} {3:" + format2 + "} {4:" + format2 + "} {5:" + format2 + "} Tm\n{6} Tj\n",
// m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY, text);
- AppendFormatArgs(s_format2, m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY, text);
+ AppendFormatArgs(s_format1, m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY);
+ _content.Append(Owner.Options.LineEnding);
+ AppendFormatArgs(s_format2, text);
+ _content.Append(Owner.Options.LineEnding);
_gfxState.ItalicSimulationOn = true;
AdjustTdOffset(ref pos, verticalOffset, false);
}
@@ -781,14 +813,17 @@ void RenderText(string text, XFont font, XBrush brush, double x, double y, doubl
{ // Case: Do not simulate Italic but simulation is currently on.
// Same as format2, but keep code clear.
- s_format3 ??= "{0:" + formatTj + "} {1:" + formatTj + "} {2:" + formatTj + "} {3:" + formatTj + "} {4:"
- + formatTj + "} {5:" + formatTj + "} Tm\n{6} Tj\n";
+ const string s_format1 = "{0:" + format4 + "} {1:" + format4 + "} {2:" + format4 + "} {3:" + format4 + "} {4:" + format4 + "} {5:" + format4 + "} Tm";
+ const string s_format2 = "{0} Tj";
var m = new XMatrix(1, 0, 0, 1, pos.X, pos.Y);
// earlier:
//AppendFormatArgs("{0:" + format2 + "} {1:" + format2 + "} {2:" + format2 + "} {3:" + format2 + "} {4:" + format2 + "} {5:" + format2 + "} Tm\n{6} Tj\n",
// m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY, text);
- AppendFormatArgs(s_format3, m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY, text);
+ AppendFormatArgs(s_format1, m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY);
+ _content.Append(Owner.Options.LineEnding);
+ AppendFormatArgs(s_format2, text);
+ _content.Append(Owner.Options.LineEnding);
_gfxState.ItalicSimulationOn = false;
AdjustTdOffset(ref pos, verticalOffset, false);
}
@@ -796,17 +831,22 @@ void RenderText(string text, XFont font, XBrush brush, double x, double y, doubl
{ // Case: Do not simulate Italic and simulation is already off.
// Same as format1, but keep code clear.
- s_format4 ??= "{0:" + formatTj + "} {1:" + formatTj + "} Td\n{2} Tj\n";
+ const string s_format1 = "{0:" + format4 + "} {1:" + format4 + "} Td";
+ const string s_format2 = "{0} Tj";
AdjustTdOffset(ref pos, verticalOffset, false);
// earlier:
//AppendFormatArgs("{0:" + format2 + "} {1:" + format2 + "} Td {2} Tj\n", pos.X, pos.Y, text);
- AppendFormatArgs(s_format4, pos.X, pos.Y, text);
+ AppendFormatArgs(s_format1, pos.X, pos.Y);
+ _content.Append(Owner.Options.LineEnding);
+ AppendFormatArgs(s_format2, text);
+ _content.Append(Owner.Options.LineEnding);
}
}
#else
AdjustTextMatrix(ref pos);
- AppendFormat2("{0:" + format2 + "} {1:" + format2 + "} Td {2} Tj\n", pos.X, pos.Y, text);
+ AppendFormat2("{0:" + format2 + "} {1:" + format2 + "} Td {2} Tj", pos.X, pos.Y, text);
+ _content.Append(Owner.Options.LineEnding);
#endif
if (underline)
{
@@ -831,13 +871,6 @@ void RenderText(string text, XFont font, XBrush brush, double x, double y, doubl
}
}
- // ReSharper disable InconsistentNaming
- static string? s_format1;
- static string? s_format2;
- static string? s_format3;
- static string? s_format4;
- // ReSharper restore InconsistentNaming
-
public void DrawString(string s, XGlyphTypeface typeface, XBrush brush, XRect rect, XStringFormat format)
{
// Placeholder
@@ -890,13 +923,13 @@ public void DrawImage(XImage image, double x, double y, double width, double hei
{
if (_gfx.PageDirection == XPageDirection.Downwards)
{
- AppendFormatImage("q {2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do Q\n",
- x, y + height, width, height, name);
+ AppendFormatImage("q {2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do Q", x, y + height, width, height, name);
+ _content.Append(Owner.Options.LineEnding);
}
else
{
- AppendFormatImage("q {2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do Q\n",
- x, y, width, height, name);
+ AppendFormatImage("q {2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do Q", x, y, width, height, name);
+ _content.Append(Owner.Options.LineEnding);
}
}
else
@@ -915,7 +948,7 @@ public void DrawImage(XImage image, double x, double y, double width, double hei
var xForm = form as XPdfForm;
// Reset colors in this graphics state. Usually PDF images should set them.
// But in rare cases they aren’t which may result in changed colors inside the image.
- var resetColor = xForm != null ? "\n0 g\n0 G\n" : " ";
+ var resetColor = xForm != null ? $" 0 g 0 G " : " ";
if (_gfx.PageDirection == XPageDirection.Downwards)
{
@@ -928,14 +961,14 @@ public void DrawImage(XImage image, double x, double y, double width, double hei
xDraw -= xForm.Page!.MediaBox.X1;
yDraw += xForm.Page.MediaBox.Y1;
}
- AppendFormatImage("q" + resetColor + "{2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm 100 Tz {4} Do Q\n",
- xDraw, yDraw + height, cx, cy, name);
+ AppendFormatImage("q" + resetColor + "{2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm 100 Tz {4} Do Q", xDraw, yDraw + height, cx, cy, name);
+ _content.Append(Owner.Options.LineEnding);
}
else
{
// TODO_OLD Translation for MediaBox.
- AppendFormatImage("q" + resetColor + "{2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do Q\n",
- x, y, cx, cy, name);
+ AppendFormatImage("q" + resetColor + "{2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do Q", x, y, cx, cy, name);
+ _content.Append(Owner.Options.LineEnding);
}
}
}
@@ -960,13 +993,13 @@ public void DrawImage(XImage image, XRect destRect, XRect srcRect, XGraphicsUnit
{
if (_gfx.PageDirection == XPageDirection.Downwards)
{
- AppendFormatImage("q {2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do\nQ\n",
- x, y + height, width, height, name);
+ AppendFormatImage("q {2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do Q", x, y + height, width, height, name);
+ _content.Append(Owner.Options.LineEnding);
}
else
{
- AppendFormatImage("q {2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do Q\n",
- x, y, width, height, name);
+ AppendFormatImage("q {2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do Q", x, y, width, height, name);
+ _content.Append(Owner.Options.LineEnding);
}
}
else
@@ -984,7 +1017,7 @@ public void DrawImage(XImage image, XRect destRect, XRect srcRect, XGraphicsUnit
{
var xForm = form as XPdfForm;
// Reset colors in this graphics state. Usually PDF images should set them, but in rare cases they don’t and this may result in changed colors inside the image.
- var resetColor = xForm != null ? "\n0 g\n0 G\n" : " ";
+ var resetColor = xForm != null ? " 0 g 0 G " : " ";
if (_gfx.PageDirection == XPageDirection.Downwards)
{
@@ -996,14 +1029,14 @@ public void DrawImage(XImage image, XRect destRect, XRect srcRect, XGraphicsUnit
xDraw -= xForm.Page!.MediaBox.X1;
yDraw += xForm.Page.MediaBox.Y1;
}
- AppendFormatImage("q" + resetColor + "{2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do Q\n",
- xDraw, yDraw + height, cx, cy, name);
+ AppendFormatImage("q" + resetColor + "{2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do Q", xDraw, yDraw + height, cx, cy, name);
+ _content.Append(Owner.Options.LineEnding);
}
else
{
// TODO_OLD Translation for MediaBox.
- AppendFormatImage("q" + resetColor + "{2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do Q\n",
- x, y, cx, cy, name);
+ AppendFormatImage("q" + resetColor + "{2:" + format + "} 0 0 {3:" + format + "} {0:" + format + "} {1:" + format + "} cm {4} Do Q", x, y, cx, cy, name);
+ _content.Append(Owner.Options.LineEnding);
}
}
}
@@ -1165,9 +1198,10 @@ public void ResetClip()
///
public void WriteComment(string comment)
{
- comment = comment.Replace("\n", "\n% ");
+ comment = comment.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", Owner.Options.LineEnding + "% ");
// Nothing right of '% ' can break a PDF file.
- Append("% " + comment + "\n");
+ Append(Invariant($"% {comment}"));
+ Append(Owner.Options.LineEnding);
}
#endregion
@@ -1344,12 +1378,14 @@ void AppendPartialArcQuadrant(double x, double y, double width, double height, d
{
case PathStart.MoveTo1st:
pt1 = matrix.Transform(new XPoint(x0 + δx * cosα, y0 + δy * sinα));
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", pt1.X, pt1.Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} m", pt1.X, pt1.Y);
+ _content.Append(Owner.Options.LineEnding);
break;
case PathStart.LineTo1st:
pt1 = matrix.Transform(new XPoint(x0 + δx * cosα, y0 + δy * sinα));
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} l\n", pt1.X, pt1.Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} l", pt1.X, pt1.Y);
+ _content.Append(Owner.Options.LineEnding);
break;
case PathStart.Ignore1st:
@@ -1358,8 +1394,9 @@ void AppendPartialArcQuadrant(double x, double y, double width, double height, d
pt1 = matrix.Transform(new XPoint(x0 + δx * (cosα - κ * sinα), y0 + δy * (sinα + κ * cosα)));
pt2 = matrix.Transform(new XPoint(x0 + δx * (cosβ + κ * sinβ), y0 + δy * (sinβ - κ * cosβ)));
pt3 = matrix.Transform(new XPoint(x0 + δx * cosβ, y0 + δy * sinβ));
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n",
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c",
pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y);
+ _content.Append(Owner.Options.LineEnding);
}
else
{
@@ -1368,12 +1405,14 @@ void AppendPartialArcQuadrant(double x, double y, double width, double height, d
{
case PathStart.MoveTo1st:
pt1 = matrix.Transform(new XPoint(x0 - δx * cosα, y0 - δy * sinα));
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", pt1.X, pt1.Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} m", pt1.X, pt1.Y);
+ _content.Append(Owner.Options.LineEnding);
break;
case PathStart.LineTo1st:
pt1 = matrix.Transform(new XPoint(x0 - δx * cosα, y0 - δy * sinα));
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} l\n", pt1.X, pt1.Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} l", pt1.X, pt1.Y);
+ _content.Append(Owner.Options.LineEnding);
break;
case PathStart.Ignore1st:
@@ -1382,8 +1421,9 @@ void AppendPartialArcQuadrant(double x, double y, double width, double height, d
pt1 = matrix.Transform(new XPoint(x0 - δx * (cosα - κ * sinα), y0 - δy * (sinα + κ * cosα)));
pt2 = matrix.Transform(new XPoint(x0 - δx * (cosβ + κ * sinβ), y0 - δy * (sinβ - κ * cosβ)));
pt3 = matrix.Transform(new XPoint(x0 - δx * cosβ, y0 - δy * sinβ));
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n",
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c",
pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y);
+ _content.Append(Owner.Options.LineEnding);
}
}
@@ -1403,12 +1443,19 @@ void AppendPartialArc(SysPoint point1, SysPoint point2, double rotationAngle,
int count = points.Count;
int start = count % 3 == 1 ? 1 : 0;
if (start == 1)
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", points[0].X, points[0].Y);
+ {
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} m", points[0].X, points[0].Y);
+ _content.Append(Owner.Options.LineEnding);
+ }
+
for (int idx = start; idx < count; idx += 3)
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n",
+ {
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c",
points[idx].X, points[idx].Y,
points[idx + 1].X, points[idx + 1].Y,
points[idx + 2].X, points[idx + 2].Y);
+ _content.Append(Owner.Options.LineEnding);
+ }
}
#endif
@@ -1418,10 +1465,11 @@ void AppendPartialArc(SysPoint point1, SysPoint point2, double rotationAngle,
void AppendCurveSegment(XPoint pt0, XPoint pt1, XPoint pt2, XPoint pt3, double tension3)
{
const string format = Config.SignificantDecimalPlaces4;
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n",
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c",
pt1.X + tension3 * (pt2.X - pt0.X), pt1.Y + tension3 * (pt2.Y - pt0.Y),
pt2.X - tension3 * (pt3.X - pt1.X), pt2.Y - tension3 * (pt3.Y - pt1.Y),
pt2.X, pt2.Y);
+ _content.Append(Owner.Options.LineEnding);
}
#if _CORE_
@@ -1452,14 +1500,19 @@ internal void AppendPath(GraphicsPath path)
{
case PathPointTypeStart:
//PDF_moveto(pdf, points[idx].X, points[idx].Y);
- AppendFormat("{0:" + format + "} {1:" + format + "} m\n", points[idx].X, points[idx].Y);
+ AppendFormat("{0:" + format + "} {1:" + format + "} m", points[idx].X, points[idx].Y);
+ _content.Append(Owner.Options.LineEnding);
break;
case PathPointTypeLine:
//PDF_lineto(pdf, points[idx].X, points[idx].Y);
- AppendFormat("{0:" + format + "} {1:" + format + "} l\n", points[idx].X, points[idx].Y);
+ AppendFormat("{0:" + format + "} {1:" + format + "} l", points[idx].X, points[idx].Y);
+ _content.Append(Owner.Options.LineEnding);
if ((type & PathPointTypeCloseSubpath) != 0)
- Append("h\n");
+ {
+ Append("h");
+ _content.Append(Owner.Options.LineEnding);
+ }
break;
case PathPointTypeBezier:
@@ -1467,10 +1520,15 @@ internal void AppendPath(GraphicsPath path)
//PDF_curveto(pdf, points[idx].X, points[idx].Y,
// points[idx + 1].X, points[idx + 1].Y,
// points[idx + 2].X, points[idx + 2].Y);
- AppendFormat("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n", points[idx].X, points[idx].Y,
+ AppendFormat("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c", points[idx].X, points[idx].Y,
points[++idx].X, points[idx].Y, points[++idx].X, points[idx].Y);
+ _content.Append(Owner.Options.LineEnding);
if ((types[idx] & PathPointTypeCloseSubpath) != 0)
- Append("h\n");
+ {
+ Append("h");
+ _content.Append(Owner.Options.LineEnding);
+ }
+
break;
}
}
@@ -1566,14 +1624,19 @@ internal void AppendPath(GraphicsPath path)
{
case PathPointTypeStart:
//PDF_moveto(pdf, points[idx].X, points[idx].Y);
- AppendFormat("{0:" + format + "} {1:" + format + "} m\n", points[idx].X, points[idx].Y);
+ AppendFormat("{0:" + format + "} {1:" + format + "} m", points[idx].X, points[idx].Y);
+ _content.Append(Owner.Options.LineEnding);
break;
case PathPointTypeLine:
//PDF_lineto(pdf, points[idx].X, points[idx].Y);
- AppendFormat("{0:" + format + "} {1:" + format + "} l\n", points[idx].X, points[idx].Y);
+ AppendFormat("{0:" + format + "} {1:" + format + "} l", points[idx].X, points[idx].Y);
+ _content.Append(Owner.Options.LineEnding);
if ((type & PathPointTypeCloseSubpath) != 0)
- Append("h\n");
+ {
+ Append("h");
+ _content.Append(Owner.Options.LineEnding);
+ }
break;
case PathPointTypeBezier:
@@ -1581,10 +1644,14 @@ internal void AppendPath(GraphicsPath path)
//PDF_curveto(pdf, points[idx].X, points[idx].Y,
// points[idx + 1].X, points[idx + 1].Y,
// points[idx + 2].X, points[idx + 2].Y);
- AppendFormat("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n", points[idx].X, points[idx].Y,
+ AppendFormat("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c", points[idx].X, points[idx].Y,
points[++idx].X, points[idx].Y, points[++idx].X, points[idx].Y);
+ _content.Append(Owner.Options.LineEnding);
if ((types[idx] & PathPointTypeCloseSubpath) != 0)
- Append("h\n");
+ {
+ Append("h");
+ _content.Append(Owner.Options.LineEnding);
+ }
break;
}
}
@@ -1618,14 +1685,19 @@ void AppendPath(XPoint[] points, byte[] types)
{
case PathPointTypeStart:
//PDF_moveto(pdf, points[idx].X, points[idx].Y);
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", points[idx].X, points[idx].Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} m", points[idx].X, points[idx].Y);
+ _content.Append(Owner.Options.LineEnding);
break;
case PathPointTypeLine:
//PDF_lineto(pdf, points[idx].X, points[idx].Y);
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} l\n", points[idx].X, points[idx].Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} l", points[idx].X, points[idx].Y);
+ _content.Append(Owner.Options.LineEnding);
if ((type & PathPointTypeCloseSubpath) != 0)
- Append("h\n");
+ {
+ Append("h");
+ _content.Append(Owner.Options.LineEnding);
+ }
break;
case PathPointTypeBezier:
@@ -1633,10 +1705,14 @@ void AppendPath(XPoint[] points, byte[] types)
//PDF_curveto(pdf, points[idx].X, points[idx].Y,
// points[idx + 1].X, points[idx + 1].Y,
// points[idx + 2].X, points[idx + 2].Y);
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n", points[idx].X, points[idx].Y,
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c", points[idx].X, points[idx].Y,
points[++idx].X, points[idx].Y, points[++idx].X, points[idx].Y);
+ _content.Append(Owner.Options.LineEnding);
if ((types[idx] & PathPointTypeCloseSubpath) != 0)
- Append("h\n");
+ {
+ Append("h");
+ _content.Append(Owner.Options.LineEnding);
+ }
break;
}
}
@@ -1673,7 +1749,8 @@ internal void AppendPath(PathGeometry geometry)
{
// Move to start point.
var currentPoint = figure.StartPoint;
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} m\n", currentPoint.X, currentPoint.Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} m", currentPoint.X, currentPoint.Y);
+ _content.Append(Owner.Options.LineEnding);
foreach (PathSegment segment in figure.Segments)
{
@@ -1683,7 +1760,8 @@ internal void AppendPath(PathGeometry geometry)
{
// Draw a single line.
var point = lineSegment.Point;
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} l\n", point.X, point.Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} l", point.X, point.Y);
+ _content.Append(Owner.Options.LineEnding);
currentPoint = point;
}
break;
@@ -1694,7 +1772,8 @@ internal void AppendPath(PathGeometry geometry)
var points = polyLineSegment.Points;
foreach (SysPoint point in points)
{
- AppendFormatPoint("{0:" + format + "} {1:" + format + "} l\n", point.X, point.Y);
+ AppendFormatPoint("{0:" + format + "} {1:" + format + "} l", point.X, point.Y);
+ _content.Append(Owner.Options.LineEnding);
}
currentPoint = points[^1];
}
@@ -1706,8 +1785,9 @@ internal void AppendPath(PathGeometry geometry)
var point1 = bezierSegment.Point1;
var point2 = bezierSegment.Point2;
var point3 = bezierSegment.Point3;
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n",
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c",
point1.X, point1.Y, point2.X, point2.Y, point3.X, point3.Y);
+ _content.Append(Owner.Options.LineEnding);
currentPoint = point3;
}
break;
@@ -1725,8 +1805,9 @@ internal void AppendPath(PathGeometry geometry)
var point1 = points[idx];
var point2 = points[idx + 1];
var point3 = points[idx + 2];
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n",
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c",
point1.X, point1.Y, point2.X, point2.Y, point3.X, point3.Y);
+ _content.Append(Owner.Options.LineEnding);
}
currentPoint = points[count - 1];
}
@@ -1771,8 +1852,9 @@ These calculations position the control points C1 and C2 so that the cubic curve
var point1 = quadraticBezierSegment.Point1;
var point2 = quadraticBezierSegment.Point2;
var controlPoints = QuadraticToCubic(currentPoint.X, currentPoint.Y, point1.X, point1.Y, point2.X, point2.Y);
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n",
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c",
controlPoints.C1X, controlPoints.C1Y, controlPoints.C2X, controlPoints.C2Y, point2.X, point2.Y);
+ _content.Append(Owner.Options.LineEnding);
currentPoint = point2;
}
break;
@@ -1792,8 +1874,9 @@ These calculations position the control points C1 and C2 so that the cubic curve
var point2 = points[idx + 1];
var controlPoints = QuadraticToCubic(currentPoint.X, currentPoint.Y, point1.X, point1.Y, point2.X, point2.Y);
- AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c\n",
+ AppendFormat3Points("{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "} {4:" + format + "} {5:" + format + "} c",
controlPoints.C1X, controlPoints.C1Y, controlPoints.C2X, controlPoints.C2Y, point2.X, point2.Y);
+ _content.Append(Owner.Options.LineEnding);
currentPoint = point2;
}
}
@@ -1811,7 +1894,10 @@ These calculations position the control points C1 and C2 so that the cubic curve
}
}
if (figure.IsClosed)
- Append("h\n");
+ {
+ Append("h");
+ _content.Append(Owner.Options.LineEnding);
+ }
}
}
}
@@ -1822,6 +1908,36 @@ internal void Append(string value)
_content.Append(value);
}
+ internal void AppendFormatArgs(string format, object arg1)
+ {
+ _content.AppendFormat(CultureInfo.InvariantCulture, format, arg1);
+#if DEBUG_
+ string dummy = _content.ToString();
+ dummy = dummy.Substring(Math.Max(0, dummy.Length - 100));
+ dummy.GetType();
+#endif
+ }
+
+ internal void AppendFormatArgs(string format, object arg1, object arg2)
+ {
+ _content.AppendFormat(CultureInfo.InvariantCulture, format, arg1, arg2);
+#if DEBUG_
+ string dummy = _content.ToString();
+ dummy = dummy.Substring(Math.Max(0, dummy.Length - 100));
+ dummy.GetType();
+#endif
+ }
+
+ internal void AppendFormatArgs(string format, object arg1, object arg2, object arg3)
+ {
+ _content.AppendFormat(CultureInfo.InvariantCulture, format, arg1, arg2, arg3);
+#if DEBUG_
+ string dummy = _content.ToString();
+ dummy = dummy.Substring(Math.Max(0, dummy.Length - 100));
+ dummy.GetType();
+#endif
+ }
+
internal void AppendFormatArgs(string format, params object[] args)
{
_content.AppendFormat(CultureInfo.InvariantCulture, format, args);
@@ -1898,20 +2014,22 @@ void AppendStrokeFill(XPen? pen, XBrush? brush, XFillMode fillMode, bool closePa
if (fillMode == XFillMode.Winding)
{
if (pen != null && brush != null)
- _content.Append("B\n");
+ _content.Append("B");
else if (pen != null)
- _content.Append("S\n");
+ _content.Append("S");
else
- _content.Append("f\n");
+ _content.Append("f");
+ _content.Append(Owner.Options.LineEnding);
}
else
{
if (pen != null && brush != null)
- _content.Append("B*\n");
+ _content.Append("B*");
else if (pen != null)
- _content.Append("S\n");
+ _content.Append("S");
else
- _content.Append("f*\n");
+ _content.Append("f*");
+ _content.Append(Owner.Options.LineEnding);
}
}
#endregion
@@ -2050,7 +2168,8 @@ void EndPage()
{
if (_streamMode == StreamMode.Text)
{
- _content.Append("ET\n");
+ _content.Append("ET");
+ _content.Append(Owner.Options.LineEnding);
_streamMode = StreamMode.Graphic;
}
@@ -2079,7 +2198,10 @@ internal void BeginGraphicMode()
// Why the check?
if (_streamMode == StreamMode.Text)
- _content.Append("ET\n");
+ {
+ _content.Append("ET");
+ _content.Append(Owner.Options.LineEnding);
+ }
_streamMode = StreamMode.Graphic;
}
@@ -2095,7 +2217,8 @@ internal void BeginTextMode()
Debug.Assert(_streamMode == StreamMode.Graphic, "Undefined stream mode. Check what happened.");
_streamMode = StreamMode.Text;
- _content.Append("BT\n");
+ _content.Append("BT");
+ _content.Append(Owner.Options.LineEnding);
// Text matrix is empty after BT.
_gfxState.RealizedTextPosition = new XPoint();
_gfxState.ItalicSimulationOn = false;
@@ -2380,7 +2503,8 @@ void SaveState()
_gfxStateStack.Push(_gfxState);
_gfxState = _gfxState.Clone();
_gfxState.Level = _gfxStateStack.Count;
- Append("q\n");
+ Append("q");
+ _content.Append(Owner.Options.LineEnding);
}
///
@@ -2391,7 +2515,8 @@ void RestoreState()
Debug.Assert(_streamMode == StreamMode.Graphic, "Cannot restore state in text mode.");
_gfxState = _gfxStateStack.Pop();
- Append("Q\n");
+ Append("Q");
+ _content.Append(Owner.Options.LineEnding);
}
PdfGraphicsState RestoreState(InternalGraphicsState state)
@@ -2400,11 +2525,13 @@ PdfGraphicsState RestoreState(InternalGraphicsState state)
var top = _gfxStateStack.Pop();
while (top.InternalState != state)
{
- Append("Q\n");
+ Append("Q");
+ _content.Append(Owner.Options.LineEnding);
count++;
top = _gfxStateStack.Pop();
}
- Append("Q\n");
+ Append("Q");
+ _content.Append(Owner.Options.LineEnding);
_gfxState = top;
return top;
}
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.AcroForms/PdfTextField.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.AcroForms/PdfTextField.cs
index cefef326..09ea50ec 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.AcroForms/PdfTextField.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.AcroForms/PdfTextField.cs
@@ -217,7 +217,7 @@ void RenderAppearance()
string s = xobj.Stream?.ToString() ?? "";
// Thank you Adobe: Without putting the content in 'EMC brackets'
// the text is not rendered by PDF Reader 9 or higher.
- s = "/Tx BMC\n" + s + "\nEMC";
+ s = "/Tx BMC" + _document.Options.LineEnding + s + _document.Options.LineEnding + "EMC";
if (xobj.Stream != null)
xobj.Stream.Value = new RawEncoding().GetBytes(s);
#endif
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfContent.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfContent.cs
index 902f72b8..08bb15c7 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfContent.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfContent.cs
@@ -93,23 +93,39 @@ internal void PreserveGraphicsState()
// prepended or appended. Some nasty PDF tools do not preserve the graphical state correctly.
// Therefore, we try to relieve the problem by surrounding the content stream with push/restore
// graphic state operation.
- if (Stream != null!)
+ if (Stream != null)
{
var value = Stream.Value;
- if (value != null!) // NRT
+ if (value != null) // NRT
{
int length = value.Length;
- if (length > 1 && ((value[0] != (byte)'q' || value[1] != (byte)'\n')))
+ if (length > 1 && (value[0] != (byte)'q' || value[1] is not (byte)'\r' and not (byte)'\n' and not (byte)' '))
{
- var newValue = new byte[length + 2 + 3];
- newValue[0] = (byte)'q';
- newValue[1] = (byte)'\n';
- Array.Copy(value, 0, newValue, 2, length);
- newValue[length + 2] = (byte)' ';
- newValue[length + 3] = (byte)'Q';
- newValue[length + 4] = (byte)'\n';
+ var lineEnding = _document.Options.LineEndingBytes;
+ var newValue = new byte[length + 2 * lineEnding.Length + 3];
+ int written = 0;
+
+ newValue[written] = (byte)'q';
+ written++;
+ Array.Copy(lineEnding, 0, newValue, written, lineEnding.Length);
+ written += lineEnding.Length;
+
+ Array.Copy(value, 0, newValue, written, length);
+ written += length;
+
+ newValue[written] = (byte)' ';
+ written++;
+ newValue[written] = (byte)'Q';
+ written++;
+ Array.Copy(lineEnding, 0, newValue, written, lineEnding.Length);
+ written += lineEnding.Length;
+
+#if DEBUG
+ Debug.Assert(written == newValue.Length);
+#endif
+
Stream.Value = newValue;
- Elements.SetInteger("/Length", Stream.Length);
+ Elements.SetInteger("/Length", newValue.Length);
}
}
}
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfContents.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfContents.cs
index 34583149..9bfb52da 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfContents.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfContents.cs
@@ -76,23 +76,26 @@ public PdfContent PrependContent()
/// Creates a single content stream with the bytes from the array of the content streams.
/// This operation does not modify any of the content streams in this array.
///
+ /// This operation actually concats multiple streams by new line
public PdfContent CreateSingleContent()
{
- byte[] bytes = [];
- byte[] bytes1;
- byte[] bytes2;
- foreach (PdfItem iref in Elements)
+ var content = new PdfContent(Owner);
+ var lineEnding = _document.Options.LineEndingBytes;
+ using (var stream = new MemoryStream())
{
- PdfDictionary cont = (PdfDictionary)((PdfReference)iref).Value;
- bytes1 = bytes;
- bytes2 = cont.Stream!.UnfilteredValue;
- bytes = new byte[bytes1.Length + bytes2.Length + 1];
- bytes1.CopyTo(bytes, 0);
- bytes[bytes1.Length] = (byte)'\n';
- bytes2.CopyTo(bytes, bytes1.Length + 1);
+ foreach (PdfItem iref in Elements)
+ {
+ var cont = (PdfDictionary)((PdfReference)iref).Value;
+ var data = cont.Stream!.UnfilteredValue;
+ stream.Write(data, 0, data.Length);
+ stream.Write(lineEnding, 0, lineEnding.Length);
+ }
+
+ if (stream.Length > 0)
+ stream.SetLength(stream.Length - lineEnding.Length);
+
+ content.Stream = new PdfStream(stream.ToArray(), content);
}
- PdfContent content = new PdfContent(Owner);
- content.Stream = new PdfDictionary.PdfStream(bytes, content);
return content;
}
@@ -140,30 +143,53 @@ void SetModified()
else if (count > 1)
{
// Surround content streams with q/Q operations
- byte[] value;
- int length;
- PdfContent content = (PdfContent)((PdfReference)Elements[0]).Value;
+ var lineEnding = _document.Options.LineEndingBytes;
+
+ var content = (PdfContent)((PdfReference)Elements[0]).Value;
if (content != null && content.Stream != null)
{
- length = content.Stream.Length;
- value = new byte[length + 2];
- value[0] = (byte)'q';
- value[1] = (byte)'\n';
- Array.Copy(content.Stream.Value, 0, value, 2, length);
+ int written = 0;
+ var length = content.Stream.Length;
+ var value = new byte[length + 1 + lineEnding.Length];
+
+ value[written] = (byte)'q';
+ written++;
+
+ Array.Copy(lineEnding, 0, value, written, lineEnding.Length);
+ written += lineEnding.Length;
+
+ Array.Copy(content.Stream.Value, 0, value, written, length);
+ written += length;
+#if DEBUG
+ Debug.Assert(written == value.Length);
+#endif
content.Stream.Value = value;
- content.Elements.SetInteger("/Length", length + 2);
+ content.Elements.SetInteger("/Length", value.Length);
}
+
content = (PdfContent)((PdfReference)Elements[count - 1]).Value;
if (content != null && content.Stream != null)
{
- length = content.Stream.Length;
- value = new byte[length + 3];
- Array.Copy(content.Stream.Value, 0, value, 0, length);
- value[length] = (byte)' ';
- value[length + 1] = (byte)'Q';
- value[length + 2] = (byte)'\n';
+ int written = 0;
+ var length = content.Stream.Length;
+ var value = new byte[length + 2 + lineEnding.Length];
+
+ Array.Copy(content.Stream.Value, 0, value, written, length);
+ written += length;
+
+ value[written] = (byte)' ';
+ written++;
+
+ value[written] = (byte)'Q';
+ written++;
+
+ Array.Copy(lineEnding, 0, value, written, lineEnding.Length);
+ written += lineEnding.Length;
+#if DEBUG
+ Debug.Assert(written == value.Length);
+#endif
content.Stream.Value = value;
- content.Elements.SetInteger("/Length", length + 3);
+ content.Elements.SetInteger("/Length", value.Length);
}
}
}
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfCrossReferenceTable.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfCrossReferenceTable.cs
index 327c212c..5963400d 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfCrossReferenceTable.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfCrossReferenceTable.cs
@@ -181,20 +181,36 @@ public int GetNewObjectNumber()
///
internal void WriteObject(PdfWriter writer)
{
- writer.WriteRaw("xref\n");
+ writer.WriteRaw("xref");
+ writer.WriteRaw(document.Options.LineEnding);
var iRefs = AllReferences;
int count = iRefs.Length;
- writer.WriteRaw(Invariant($"0 {count + 1}\n"));
- writer.WriteRaw(Invariant($"{0:0000000000} {65535:00000} f \n"));
+ writer.WriteRaw(Invariant($"0 {count + 1}"));
+ writer.WriteRaw(document.Options.LineEnding);
+
+ // Acrobat is very pedantic; it must be exactly 20 bytes per line.
+ switch (document.Options.LineEnding.Length)
+ {
+ case 1: writer.WriteRaw("0000000000 65535 f "); break;
+ case 2: writer.WriteRaw("0000000000 65535 f"); break;
+ default: throw new ArgumentOutOfRangeException(nameof(document.Options.LineEnding), document.Options.LineEnding.Length, "Line ending length is invalid");
+ }
+ writer.WriteRaw(document.Options.LineEnding);
for (int idx = 0; idx < count; idx++)
{
var iref = iRefs[idx];
// Acrobat is very pedantic; it must be exactly 20 bytes per line.
- writer.WriteRaw(Invariant($"{iref.Position:0000000000} {iref.GenerationNumber:00000} n \n"));
+ switch (document.Options.LineEnding.Length)
+ {
+ case 1: writer.WriteRaw(Invariant($"{iref.Position:0000000000} {iref.GenerationNumber:00000} n ")); break;
+ case 2: writer.WriteRaw(Invariant($"{iref.Position:0000000000} {iref.GenerationNumber:00000} n")); break;
+ default: throw new ArgumentOutOfRangeException(nameof(document.Options.LineEnding), document.Options.LineEnding.Length, "Line ending length is invalid");
+ }
+ writer.WriteRaw(document.Options.LineEnding);
}
}
@@ -237,6 +253,9 @@ internal void HandleOrphanedReferences()
///
internal int Compact()
{
+ if (!document.Options.EnableReferenceCompaction)
+ return 0;
+
// IMPROVE: remove PdfBooleanObject, PdfIntegerObject etc.
int removed = _objectTable.Count;
PdfReference[] irefs = TransitiveClosure(document.Trailer);
@@ -313,6 +332,9 @@ internal int Compact()
///
internal void Renumber()
{
+ if (!document.Options.EnableReferenceRenumbering)
+ return;
+
//CheckConsistence();
PdfReference[] irefs = AllReferences;
_objectTable.Clear();
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfReference.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfReference.cs
index 7240a8b5..dfced52c 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfReference.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfReference.cs
@@ -100,7 +100,13 @@ internal void WriteXRefEntry(PdfWriter writer)
// PDFsharp does not yet support PDF 1.5 object streams for writing.
// Each line must be exactly 20 bytes long, otherwise Acrobat repairs the file.
- writer.WriteRaw(Invariant($"{_position:0000000000} {_objectID.GenerationNumber:00000} n \n"));
+ switch (Document.Options.LineEnding.Length)
+ {
+ case 1: writer.WriteRaw(Invariant($"{_position:0000000000} {_objectID.GenerationNumber:00000} n ")); break;
+ case 2: writer.WriteRaw(Invariant($"{_position:0000000000} {_objectID.GenerationNumber:00000} n")); break;
+ default: throw new ArgumentOutOfRangeException(nameof(Document.Options.LineEnding), Document.Options.LineEnding.Length, "Line ending length is invalid");
+ }
+ writer.WriteRaw(Document.Options.LineEnding);
}
///
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfToUnicodeMap.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfToUnicodeMap.cs
index 928b384a..3ab898cb 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfToUnicodeMap.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Advanced/PdfToUnicodeMap.cs
@@ -38,11 +38,11 @@ internal override void PrepareForSave()
// This code comes literally from PDF Reference.
string prefix =
- "/CIDInit /ProcSet findresource begin\n" +
- "12 dict begin\n" +
- "begincmap\n" +
- "/CIDSystemInfo << /Registry (Adobe)/Ordering (UCS)/Supplement 0>> def\n" +
- "/CMapName /Adobe-Identity-UCS def /CMapType 2 def\n";
+ "/CIDInit /ProcSet findresource begin" + _document.Options.LineEnding +
+ "12 dict begin" + _document.Options.LineEnding +
+ "begincmap" + _document.Options.LineEnding +
+ "/CIDSystemInfo << /Registry (Adobe)/Ordering (UCS)/Supplement 0>> def" + _document.Options.LineEnding +
+ "/CMapName /Adobe-Identity-UCS def /CMapType 2 def" + _document.Options.LineEnding;
string suffix = "endcmap CMapName currentdict /CMap defineresource pop end end";
//var glyphIndexToCharacter = new Dictionary();
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content/ContentWriter.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content/ContentWriter.cs
index a8821dae..dd427233 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content/ContentWriter.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.Content/ContentWriter.cs
@@ -68,6 +68,7 @@ public void WriteRaw(string rawString)
_lastCat = GetCategory((char)bytes[bytes.Length - 1]);
}
+ [Obsolete("Does not honor document line endings")]
public void WriteLineRaw(string rawString)
{
if (String.IsNullOrEmpty(rawString))
@@ -148,6 +149,7 @@ void WriteSeparator(CharCat cat)
WriteSeparator(cat, '\0');
}
+ [Obsolete("Does not honor document line endings")]
public void NewLine()
{
if (_lastCat != CharCat.NewLine)
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/Lexer.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/Lexer.cs
index c02e6add..2a119ae4 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/Lexer.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/Lexer.cs
@@ -1180,7 +1180,7 @@ public string DumpNeighborhoodOfPosition(SizeType position = -1, bool hex = fals
//Chars.SP => "・", // U+30FB
//<= ' ' => $"⁌((int)ch).ToString(\"X2\")⁍",
- <= ' ' => $"""⟬{(((int)ch).ToString("X2"))}⟭""",
+ <= ' ' => $"⟬{(int)ch:X2}⟭",
_ => ch.ToString()
};
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfReader.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfReader.cs
index f9b9f6fc..8fed9f59 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfReader.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfReader.cs
@@ -267,8 +267,7 @@ PdfDocument OpenFromFile(string path, string? password, PdfDocumentOpenMode open
///
/// Opens a PDF document from a stream.
///
- PdfDocument OpenFromStream(Stream stream, string? password, PdfDocumentOpenMode openMode,
- PdfPasswordProvider? passwordProvider, PdfReaderOptions? options = null)
+ PdfDocument OpenFromStream(Stream stream, string? password, PdfDocumentOpenMode openMode, PdfPasswordProvider? passwordProvider)
{
try
{
@@ -279,6 +278,18 @@ PdfDocument OpenFromStream(Stream stream, string? password, PdfDocumentOpenMode
var lexer = new Lexer(stream, _logger);
_document = new PdfDocument(lexer);
+
+ _document.Options.EnableReferenceRenumbering = _options.EnableReferenceRenumbering;
+ _document.Options.EnableReferenceCompaction = _options.EnableReferenceCompaction;
+ _document.Options.EnableImplicitTransparencyGroup = _options.EnableImplicitTransparencyGroup;
+ _document.Options.EnableImplicitMetadata = _options.EnableImplicitMetadata;
+ _document.Options.EnableWriterCommentInTrailer = _options.EnableWriterCommentInTrailer;
+ _document.Options.EnableLfLineEndings = _options.EnableLfLineEndings;
+ _document.Options.EnableOwnBinaryHeader = _options.EnableOwnBinaryHeader;
+ _document.Options.EnableLineBreakInArrayObjects = _options.EnableLineBreakInArrayObjects;
+ _document.Options.DisablePagesAndCatalogAtEnd = _options.DisablePagesAndCatalogAtEnd;
+ _document.Options.EnableOwnerPasswordSecurityChecks = _options.EnableOwnerPasswordSecurityChecks;
+
_document._state |= DocumentState.Imported;
_document._openMode = openMode;
@@ -310,7 +321,7 @@ PdfDocument OpenFromStream(Stream stream, string? password, PdfDocumentOpenMode
// After reading all objects, all documents placeholder references get replaced by references knowing their objects in FinishReferences(),
// which finally sets IsUnderConstruction to false.
_document.IrefTable.IsUnderConstruction = true;
- var parser = new Parser(_document, options ?? new PdfReaderOptions(), _logger);
+ var parser = new Parser(_document, _options , _logger);
// 1. Read all trailers or cross-reference streams, but no objects.
_document.Trailer = parser.ReadTrailer();
@@ -370,7 +381,11 @@ PdfDocument OpenFromStream(Stream stream, string? password, PdfDocumentOpenMode
goto TryAgain;
}
else
- throw new PdfReaderException(PsMsgs.OwnerPasswordRequired);
+ {
+ if(_document.Options.EnableOwnerPasswordSecurityChecks)
+ throw new PdfReaderException(PsMsgs.OwnerPasswordRequired);
+ _document.SecuritySettings.HasOwnerPermissions = true;
+ }
}
// ReSharper restore RedundantIfElseBlock
}
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfReaderOptions.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfReaderOptions.cs
index ed530d51..0a19e853 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfReaderOptions.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfReaderOptions.cs
@@ -99,6 +99,50 @@ public class PdfReaderOptions
public ReaderProblemDelegate? ReaderProblemCallback { get; set; }
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableReferenceRenumbering { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableReferenceCompaction { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableImplicitTransparencyGroup { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableImplicitMetadata { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableWriterCommentInTrailer { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableLfLineEndings { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableOwnBinaryHeader { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableLineBreakInArrayObjects { get; set; } = true;
+
+ public bool DisablePagesAndCatalogAtEnd { get; set; } = true;
+
+ public bool EnableOwnerPasswordSecurityChecks { get; set; } = true;
+
// Testing only
//public bool UseOldCode { get; set; } = false;
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfWriter.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfWriter.cs
index dbbc1c19..f25deaa6 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfWriter.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfWriter.cs
@@ -355,9 +355,16 @@ public void WriteBeginObject(PdfObject obj)
if (indirect)
{
if (obj is PdfArray)
- WriteRaw("[\n");
+ {
+ WriteRaw("[");
+ if(_document.Options.EnableLineBreakInArrayObjects)
+ WriteRaw(_document.Options.LineEnding);
+ }
else if (obj is PdfDictionary)
- WriteRaw("<<\n");
+ {
+ WriteRaw("<<");
+ WriteRaw(_document.Options.LineEnding);
+ }
_lastCat = CharCat.NewLine;
}
else
@@ -372,7 +379,8 @@ public void WriteBeginObject(PdfObject obj)
{
NewLine();
WriteSeparator(CharCat.Delimiter);
- WriteRaw("<<\n");
+ WriteRaw("<<");
+ WriteRaw(_document.Options.LineEnding);
_lastCat = CharCat.NewLine;
}
}
@@ -401,7 +409,10 @@ public void WriteEndObject()
{
if (indirect)
{
- WriteRaw("\n]\n");
+ if (_document.Options.EnableLineBreakInArrayObjects)
+ WriteRaw(_document.Options.LineEnding);
+ WriteRaw("]");
+ WriteRaw(_document.Options.LineEnding);
_lastCat = CharCat.NewLine;
}
else
@@ -415,22 +426,30 @@ public void WriteEndObject()
if (indirect)
{
if (!stackItem.HasStream)
- WriteRaw(_lastCat == CharCat.NewLine ? ">>\n" : " >>\n");
+ {
+ WriteRaw(_lastCat == CharCat.NewLine ? ">>" : " >>");
+ WriteRaw(_document.Options.LineEnding);
+ }
}
else
{
Debug.Assert(!stackItem.HasStream, "Direct object with stream??");
WriteSeparator(CharCat.NewLine);
- WriteRaw(">>\n");
+ WriteRaw(">>");
+ WriteRaw(_document.Options.LineEnding);
_lastCat = CharCat.NewLine;
}
}
if (indirect)
{
NewLine();
- WriteRaw("endobj\n");
+ WriteRaw("endobj");
+ WriteRaw(_document.Options.LineEnding);
if (Layout == PdfWriterLayout.Verbose)
- WriteRaw("%--------------------------------------------------------------------------------------------------\n");
+ {
+ WriteRaw("%--------------------------------------------------------------------------------------------------");
+ WriteRaw(_document.Options.LineEnding);
+ }
}
}
@@ -444,11 +463,15 @@ public void WriteStream(PdfDictionary value, bool omitStream)
Debug.Assert(stackItem.Object.IsIndirect);
stackItem.HasStream = true;
- WriteRaw(_lastCat == CharCat.NewLine ? ">>\nstream\n" : " >>\nstream\n");
+ WriteRaw(_lastCat == CharCat.NewLine ? ">>" : " >>");
+ WriteRaw(_document.Options.LineEnding);
+ WriteRaw("stream");
+ WriteRaw(_document.Options.LineEnding);
if (omitStream)
{
- WriteRaw(" «…stream content omitted…»\n"); // useful for debugging only
+ WriteRaw(" «…stream content omitted…»"); // useful for debugging only
+ WriteRaw(_document.Options.LineEnding);
}
else
{
@@ -458,7 +481,9 @@ public void WriteStream(PdfDictionary value, bool omitStream)
if (bytes.Length != 0)
Write(bytes);
}
- WriteRaw("\nendstream\n");
+ WriteRaw(_document.Options.LineEnding);
+ WriteRaw("endstream");
+ WriteRaw(_document.Options.LineEnding);
}
public void WriteRaw(string rawString)
@@ -493,82 +518,106 @@ void WriteObjectAddress(PdfObject value)
if (Layout == PdfWriterLayout.Verbose)
{
string comment = value.Comment;
- if (!String.IsNullOrEmpty(comment))
- comment = $" -- {value.Comment}";
+ if (String.IsNullOrEmpty(comment))
+ comment = value.GetType().FullName!;
+ else
+ comment = $"{value.GetType().FullName} -- {value.Comment}";
+ comment = comment.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", _document.Options.LineEnding + "% ");
+
+ // Nothing right of '% ' can break a PDF file.
#if DEBUG_
if (_document is null)
_ = typeof(int);
#endif
// #PDF-A
- if (_document.IsPdfA)
+ //if (_document.IsPdfA)
{
// Write full type name and comment in a separate line to be PDF-A conform.
- WriteRaw(Invariant($"% {value.GetType().FullName}{comment}\n"));
- WriteRaw(Invariant($"{value.ObjectID.ObjectNumber} {value.ObjectID.GenerationNumber} obj\n"));
- }
- else
- {
- // Write object number and full type name and comment in one line.
- WriteRaw(Invariant($"{value.ObjectID.ObjectNumber} {value.ObjectID.GenerationNumber} obj % {value.GetType().FullName}{comment}\n"));
+ WriteRaw(Invariant($"% {comment}"));
+ WriteRaw(_document.Options.LineEnding);
+ WriteRaw(Invariant($"{value.ObjectID.ObjectNumber} {value.ObjectID.GenerationNumber} obj"));
+ WriteRaw(_document.Options.LineEnding);
}
+ //else
+ //{
+ // // Write object number and full type name and comment in one line.
+ // WriteRaw(Invariant($"{value.ObjectID.ObjectNumber} {value.ObjectID.GenerationNumber} obj % {value.GetType().FullName}{comment}"));
+ // WriteRaw(_document.Options.LineEnding);
+ //}
}
else
{
// Write object number only.
- WriteRaw(Invariant($"{value.ObjectID.ObjectNumber} {value.ObjectID.GenerationNumber} obj\n"));
+ WriteRaw(Invariant($"{value.ObjectID.ObjectNumber} {value.ObjectID.GenerationNumber} obj"));
+ WriteRaw(_document.Options.LineEnding);
}
}
+ const string blank = "% ";
+
public void WriteFileHeader(PdfDocument document)
{
- var header = new StringBuilder("%PDF-");
int version = document._version;
- //header.Append((version / 10).ToString(CultureInfo.InvariantCulture) + "." +
- // (version % 10).ToString(CultureInfo.InvariantCulture) + "\n%\xD3\xF4\xCC\xE1\n");
- header.Append(Invariant($"{version / 10}.{version % 10}\n%\xD3\xF4\xCC\xE1\n"));
- WriteRaw(header.ToString());
+ WriteRaw(Invariant($"%PDF-{version / 10}.{version % 10}"));
+ WriteRaw(document.Options.LineEnding);
+ if(document.Options.EnableOwnBinaryHeader)
+ WriteRaw("%\xD3\xF4\xCC\xE1");
+ else
+ WriteRaw("%\xE2\xE3\xCF\xD3");
+ WriteRaw(document.Options.LineEnding);
if (Layout == PdfWriterLayout.Verbose)
{
- WriteRaw($"% PDFsharp Version {PdfSharpProductVersionInformation.Version} (verbose mode)\n");
+ WriteRaw($"% PDFsharp Version {PdfSharpProductVersionInformation.Version} (verbose mode)");
+ WriteRaw(_document.Options.LineEnding);
// Keep some space for later fix-up.
_commentPosition = (int)_stream.Position + 2;
- WriteRaw("% \n"); // Creation date placeholder
- WriteRaw("% \n"); // Creation time placeholder
- WriteRaw("% \n"); // File size placeholder
- WriteRaw("% \n"); // Pages placeholder
- WriteRaw("% \n"); // Objects placeholder
+
+ //Should match lineLen below
+ WriteRaw(blank); WriteRaw(document.Options.LineEnding); // Creation date placeholder
+ WriteRaw(blank); WriteRaw(document.Options.LineEnding); // Creation time placeholder
+ WriteRaw(blank); WriteRaw(document.Options.LineEnding); // File size placeholder
+ WriteRaw(blank); WriteRaw(document.Options.LineEnding); // Pages placeholder
+ WriteRaw(blank); WriteRaw(document.Options.LineEnding); // Objects placeholder
#if DEBUG
- WriteRaw("% This document is created from a DEBUG build. Do not use a DEBUG build of PDFsharp for production.\n");
+ WriteRaw("% This document is created from a DEBUG build. Do not use a DEBUG build of PDFsharp for production.");
+ WriteRaw(document.Options.LineEnding);
#endif
- WriteRaw("%--------------------------------------------------------------------------------------------------\n");
}
}
public void WriteEof(PdfDocument document, SizeType startxref)
{
- WriteRaw($"% Created with PDFsharp {PdfSharpProductVersionInformation.SemanticVersion} ({Capabilities.Build.BuildName}) under .NET {Capabilities.Build.Framework}\n");
- WriteRaw("startxref\n");
- WriteRaw(startxref.ToString(CultureInfo.InvariantCulture));
- WriteRaw("\n%%EOF\n");
- SizeType fileSize = (SizeType)_stream.Position;
+ if(document.Options.EnableWriterCommentInTrailer)
+ {
+ WriteRaw($"% Created with PDFsharp {PdfSharpProductVersionInformation.SemanticVersion} ({Capabilities.Build.BuildName}) under .NET {Capabilities.Build.Framework}");
+ WriteRaw(document.Options.LineEnding);
+ }
+ WriteRaw("startxref");
+ WriteRaw(document.Options.LineEnding);
+ WriteRaw(startxref.ToString(CultureInfo.InvariantCulture));
+ WriteRaw(document.Options.LineEnding);
+ WriteRaw("%%EOF");
+ WriteRaw(document.Options.LineEnding);
if (Layout == PdfWriterLayout.Verbose)
{
+ var fileSize = _stream.Position;
TimeSpan duration = DateTime.Now - document._creation;
+ var lineLen = blank.Length + document.Options.LineEnding.Length;
_stream.Position = _commentPosition;
// Without InvariantCulture parameter the following line fails if the current culture is e.g.
// a Far East culture, because the date string contains non-ASCII characters.
// So never never never never use ToString without a culture info.
WriteRaw(Invariant($"Creation date: {document._creation:G}"));
- _stream.Position = _commentPosition + 50;
+ _stream.Position = _commentPosition + lineLen;
WriteRaw(Invariant($"Creation time: {duration.TotalSeconds:0.000} seconds"));
- _stream.Position = _commentPosition + 100;
+ _stream.Position = _commentPosition + 2* lineLen;
WriteRaw(Invariant($"File size: {fileSize:#,###} bytes"));
- _stream.Position = _commentPosition + 150;
+ _stream.Position = _commentPosition + 3* lineLen;
WriteRaw(Invariant($"Pages: {document.Pages.Count:#}")); // No thousands separator here.
- _stream.Position = _commentPosition + 200;
+ _stream.Position = _commentPosition + 4* lineLen;
WriteRaw(Invariant($"Objects: {document.IrefTable.Count:#,###}"));
}
}
@@ -640,7 +689,7 @@ void WriteSeparator(CharCat cat /*, char ch = '\0'*/)
public void NewLine()
{
if (_lastCat != CharCat.NewLine)
- WriteRaw('\n');
+ WriteRaw(_document.Options.LineEnding);
}
static CharCat GetCategory(char ch)
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocument.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocument.cs
index 68cd0250..4b503539 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocument.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocument.cs
@@ -359,22 +359,38 @@ async Task DoSaveAsync(PdfWriter writer)
effectiveSecurityHandler?.PrepareForWriting();
writer.WriteFileHeader(this);
- var irefs = IrefTable.AllReferences;
- int count = irefs.Length;
- for (int idx = 0; idx < count; idx++)
+ var irefs = IrefTable.AllReferences.ToList();
+ if (!Options.DisablePagesAndCatalogAtEnd)
+ {
+ irefs.Sort((a, b) =>
+ {
+ int getPrio(PdfReference r) => r.Value switch
+ {
+ PdfPages => 1,
+ PdfCatalog => 2,
+ _ => 0,
+ };
+ var cmp = getPrio(a).CompareTo(getPrio(b));
+ if (cmp != 0)
+ return cmp;
+ cmp = a.GenerationNumber.CompareTo(b.GenerationNumber);
+ if (cmp != 0)
+ return cmp;
+ cmp = a.ObjectNumber.CompareTo(b.ObjectNumber);
+ return cmp;
+ });
+ }
+ int count = irefs.Count;
+ foreach(var iref in irefs)
{
- PdfReference iref = irefs[idx];
-#if DEBUG_
- if (iref.ObjectNumber == 378)
- _ = typeof(int);
-#endif
iref.Position = writer.Position;
iref.Value.WriteObject(writer);
}
// ReSharper disable once RedundantCast. Redundant only if 64 bit.
var startXRef = (SizeType)writer.Position;
IrefTable.WriteObject(writer);
- writer.WriteRaw("trailer\n");
+ writer.WriteRaw("trailer");
+ writer.WriteRaw(Options.LineEnding);
Trailer.Elements.SetInteger("/Size", count + 1);
Trailer.WriteObject(writer);
writer.WriteEof(this, startXRef);
@@ -502,7 +518,8 @@ internal override void PrepareForSave()
// #PDF-UA
// Create PdfMetadata now to include the final document information in XMP generation.
- Catalog.Elements.SetReference(PdfCatalog.Keys.Metadata, new PdfMetadata(this));
+ if (Options.EnableImplicitMetadata)
+ Catalog.Elements.SetReference(PdfCatalog.Keys.Metadata, new PdfMetadata(this));
}
///
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocumentOptions.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocumentOptions.cs
index fcc8df71..adf4df6f 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocumentOptions.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfDocumentOptions.cs
@@ -3,6 +3,8 @@
// ReSharper disable ConvertToAutoProperty
+using System.Text;
+
namespace PdfSharp.Pdf
{
///
@@ -81,5 +83,53 @@ public PdfUseFlateDecoderForJpegImages UseFlateDecoderForJpegImages
set => _useFlateDecoderForJpegImages = value;
}
PdfUseFlateDecoderForJpegImages _useFlateDecoderForJpegImages = PdfUseFlateDecoderForJpegImages.Never;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableReferenceRenumbering { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableReferenceCompaction { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableImplicitTransparencyGroup { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableImplicitMetadata { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableWriterCommentInTrailer { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableLfLineEndings { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableOwnBinaryHeader { get; set; } = true;
+
+ ///
+ /// Set to to enable greater compatibility
+ ///
+ public bool EnableLineBreakInArrayObjects { get; set; } = true;
+
+ public bool DisablePagesAndCatalogAtEnd { get; set; } = true;
+
+ public bool EnableOwnerPasswordSecurityChecks { get; set; } = true;
+
+ public string LineEnding => EnableLfLineEndings ? "\n" : "\r\n";
+
+ public byte[] LineEndingBytes => Encoding.ASCII.GetBytes(LineEnding);
}
}
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfMetadata.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfMetadata.cs
index 9bbef518..dac194a2 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfMetadata.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfMetadata.cs
@@ -76,45 +76,43 @@ static DateTime SpecifyLocalDateTimeKindIfUnspecified(DateTime value)
string? pdfA = null;
if (_document.IsPdfA)
{
+ pdfA =
+ " " + _document.Options.LineEnding +
+ " 1" + _document.Options.LineEnding +
+ " A" + _document.Options.LineEnding +
+ " ";
// #PDF-A
- pdfA = $"""
-
- 1
- A
-
- """;
}
#if true
// Created based on a PDF created with Microsoft Word.
- var str = $"""
-
-
-
-
- {producer}{keywords}
-
-
- {title}
- {author}
- {subject}
-
-
- {creator}
- {creationDate}
- {modificationDate}
-
-
- uuid:{documentId}
- uuid:{instanceId}
-
- {pdfA}
-
-
-
- """;
+ var str =
+ "" + _document.Options.LineEnding +
+ " " + _document.Options.LineEnding +
+ " " + _document.Options.LineEnding +
+ " " + _document.Options.LineEnding +
+ $" {producer}{keywords}" + _document.Options.LineEnding +
+ " " + _document.Options.LineEnding +
+ " " + _document.Options.LineEnding +
+ $" {title}" + _document.Options.LineEnding +
+ $" {author}" + _document.Options.LineEnding +
+ $" {subject}" + _document.Options.LineEnding +
+ " " + _document.Options.LineEnding +
+ " " + _document.Options.LineEnding +
+ $" {creator}" + _document.Options.LineEnding +
+ $" {creationDate}" + _document.Options.LineEnding +
+ $" {modificationDate}" + _document.Options.LineEnding +
+ " " + _document.Options.LineEnding +
+ " " + _document.Options.LineEnding +
+ $" uuid:{documentId}" + _document.Options.LineEnding +
+ $" uuid:{instanceId}" + _document.Options.LineEnding +
+ " " + _document.Options.LineEnding +
+ pdfA + _document.Options.LineEnding +
+ " " + _document.Options.LineEnding +
+ " " + _document.Options.LineEnding +
+ "";
#else
// Does not exist anymore.
- // XMP Documentation: http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMP%20SDK%20Release%20cc-2016-08/XMPSpecificationPart1.pdf
+ // XMP Documentation: http://www.images.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMP%20SDK%20Release%20cc-2016-08/XMPSpecificationPart1.pdf
var str =
// UTF-8 Byte order mark "" and GUID (like in Reference) to avoid accidental usage in data stream.
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfOutline.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfOutline.cs
index c5989ff1..9a1f563d 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfOutline.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfOutline.cs
@@ -610,7 +610,7 @@ static string Fd(double? value)
internal override void WriteObject(PdfWriter writer)
{
#if DEBUG
- writer.WriteRaw("% Title = " + FilterUnicode(Title) + "\n");
+ writer.WriteRaw("% Title = " + FilterUnicode(Title) + Owner.Options.LineEnding);//
#endif
// TODO_OLD: Proof that there is nothing to do here.
bool hasKids = HasChildren;
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfPage.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfPage.cs
index 9d451f45..604980a0 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfPage.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf/PdfPage.cs
@@ -815,7 +815,7 @@ internal override void WriteObject(PdfWriter writer)
// we respect this and skip the transparency group.
TransparencyUsed = true; // TODO_OLD: check XObjects
if (TransparencyUsed && !Elements.ContainsKey(Keys.Group) &&
- _document.Options.ColorMode != PdfColorMode.Undefined)
+ _document.Options.ColorMode != PdfColorMode.Undefined && _document.Options.EnableImplicitTransparencyGroup)
{
var group = new PdfDictionary();
Elements["/Group"] = group;
diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/UniversalAccessibility/StructureElementStack.cs b/src/foundation/src/PDFsharp/src/PdfSharp/UniversalAccessibility/StructureElementStack.cs
index 58f85943..c346f7ae 100644
--- a/src/foundation/src/PDFsharp/src/PdfSharp/UniversalAccessibility/StructureElementStack.cs
+++ b/src/foundation/src/PDFsharp/src/PdfSharp/UniversalAccessibility/StructureElementStack.cs
@@ -110,13 +110,15 @@ public override void BeginItem()
{
base.BeginItem();
// Begin marked content.
- StructureBuilder.Content.Write($"{Tag}<>BDC\n");
+ StructureBuilder.Content.Write($"{Tag}<>BDC");
+ StructureBuilder.Content.Write(StructureBuilder.UaManager.Owner.Options.LineEnding);
}
public override void EndItem()
{
// End marked content.
- StructureBuilder.Content.Write("EMC\n");
+ StructureBuilder.Content.Write("EMC");
+ StructureBuilder.Content.Write(StructureBuilder.UaManager.Owner.Options.LineEnding);
base.EndItem();
}
}
@@ -134,13 +136,15 @@ public override void BeginItem()
{
base.BeginItem();
// Begin artifact.
- StructureBuilder.Content.Write("/Artifact BMC\n");
+ StructureBuilder.Content.Write("/Artifact BMC");
+ StructureBuilder.Content.Write(StructureBuilder.UaManager.Owner.Options.LineEnding);
}
public override void EndItem()
{
// End artifact.
- StructureBuilder.Content.Write("EMC\n");
+ StructureBuilder.Content.Write("EMC");
+ StructureBuilder.Content.Write(StructureBuilder.UaManager.Owner.Options.LineEnding);
base.EndItem();
}
}
diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/WriterTests.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/WriterTests.cs
index 2b03e397..aec29993 100644
--- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/WriterTests.cs
+++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/WriterTests.cs
@@ -6,6 +6,7 @@
using PdfSharp.Drawing;
using PdfSharp.Fonts;
using PdfSharp.Pdf;
+using PdfSharp.Pdf.Advanced;
using PdfSharp.Pdf.IO;
using PdfSharp.Quality;
using PdfSharp.Snippets.Font;
@@ -29,5 +30,54 @@ public void Write_import_file()
Action save = () => doc.Save(filename);
save.Should().Throw();
}
+
+ [Fact]
+ public void Memory_Write_import_file()
+ {
+ var testFile = IOUtility.GetAssetsPath("archives/samples-1.5/PDFs/SomeLayout.pdf")!;
+
+ var doc = PdfReader.Open(testFile, PdfDocumentOpenMode.Import);
+
+ Action save = () =>
+ {
+ using var mem = new MemoryStream();
+ doc.Save(mem);
+ };
+ save.Should().Throw();
+ }
+
+ [Fact]
+ public void Memory_Write_modify_file()
+ {
+ var testFile = IOUtility.GetAssetsPath("archives/samples-1.5/PDFs/SomeLayout.pdf")!;
+
+ var doc = PdfReader.Open(testFile, PdfDocumentOpenMode.Modify);
+
+ Action save = () =>
+ {
+ using var mem = new MemoryStream();
+ doc.Save(mem);
+ };
+ save.Should().NotThrow();
+ }
+
+ [Fact]
+ public void Memory_Write_modify_file2()
+ {
+ var testFile = @"C:\Projekty\PDForge\ValidatorTests\in.pdf";
+
+ var doc = PdfReader.Open(testFile, PdfDocumentOpenMode.Modify, new PdfReaderOptions()
+ {
+ EnableReferenceCompaction = false,
+ EnableReferenceRenumbering = false,
+ });
+
+ Action save = () =>
+ {
+ using var mem = new MemoryStream();
+ doc.Save(mem);
+ };
+ save.Should().NotThrow();
+ }
}
}