Simplify path construction operators

fix 're' operator to reflect documentation
Update ContentStreamProcessor with fill, stroke and clip operations
Throw errors when currentPosition is null in PdfSubpath
This commit is contained in:
BobLd
2020-04-02 17:21:51 +01:00
committed by Eliot Jones
parent 3ee9ac7915
commit 983cfcb2f6
13 changed files with 189 additions and 63 deletions

View File

@@ -166,8 +166,8 @@
} }
else else
{ {
// TODO: probably the wrong behaviour here, maybe line starts from (0, 0)? // PDF Reference 1.7 p226
MoveTo(x, y); throw new ArgumentNullException("LineTo(): currentPosition is null.");
} }
} }
@@ -176,11 +176,12 @@
/// </summary> /// </summary>
public void Rectangle(double x, double y, double width, double height) public void Rectangle(double x, double y, double width, double height)
{ {
currentPosition = new PdfPoint(x, y); // is equivalent to
LineTo(x + width, y); MoveTo(x, y); // x y m
LineTo(x + width, y + height); LineTo(x + width, y); // (x + width) y l
LineTo(x, y + height); LineTo(x + width, y + height); // (x + width) (y + height) l
LineTo(x, y); LineTo(x, y + height); // x (y + height) l
ClosePath(); // h
IsDrawnAsRectangle = true; IsDrawnAsRectangle = true;
} }
@@ -203,7 +204,8 @@
} }
else else
{ {
MoveTo(x3, y3); // PDF Reference 1.7 p226
throw new ArgumentNullException("BezierCurveTo(): currentPosition is null.");
} }
} }

View File

@@ -64,6 +64,15 @@
public void BeginSubpath() public void BeginSubpath()
{ {
}
public PdfPoint CloseSubpath()
{
return new PdfPoint();
}
public void AddCurrentSubpath()
{
} }
public void StrokePath(bool close) public void StrokePath(bool close)

View File

@@ -1,8 +1,9 @@
namespace UglyToad.PdfPig.Content namespace UglyToad.PdfPig.Content
{ {
using System.Collections.Generic;
using Core; using Core;
using System.Collections.Generic;
using Tokens; using Tokens;
using UglyToad.PdfPig.Graphics;
/// <inheritdoc /> /// <inheritdoc />
/// <summary> /// <summary>
@@ -73,7 +74,7 @@
IReadOnlyList<NameToken> attached, IReadOnlyList<NameToken> attached,
IReadOnlyList<MarkedContentElement> children, IReadOnlyList<MarkedContentElement> children,
IReadOnlyList<Letter> letters, IReadOnlyList<Letter> letters,
IReadOnlyList<PdfSubpath> paths, IReadOnlyList<PdfPath> paths,
IReadOnlyList<IPdfImage> images, IReadOnlyList<IPdfImage> images,
int index) int index)
: base(markedContentIdentifier, tag, properties, language, : base(markedContentIdentifier, tag, properties, language,

View File

@@ -2,8 +2,8 @@
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Core;
using Tokens; using Tokens;
using UglyToad.PdfPig.Graphics;
/// <summary> /// <summary>
/// A marked content element can be used to provide application specific data in the /// A marked content element can be used to provide application specific data in the
@@ -50,7 +50,7 @@
/// <summary> /// <summary>
/// Paths contained in this marked content. /// Paths contained in this marked content.
/// </summary> /// </summary>
public IReadOnlyList<PdfSubpath> Paths { get; } public IReadOnlyList<PdfPath> Paths { get; }
/// <summary> /// <summary>
/// Images contained in this marked content. /// Images contained in this marked content.
@@ -88,7 +88,7 @@
bool isArtifact, bool isArtifact,
IReadOnlyList<MarkedContentElement> children, IReadOnlyList<MarkedContentElement> children,
IReadOnlyList<Letter> letters, IReadOnlyList<Letter> letters,
IReadOnlyList<PdfSubpath> paths, IReadOnlyList<PdfPath> paths,
IReadOnlyList<IPdfImage> images, IReadOnlyList<IPdfImage> images,
int index) int index)
{ {

View File

@@ -412,7 +412,7 @@
CurrentPath = new PdfPath(); CurrentPath = new PdfPath();
} }
AddSubpath(); AddCurrentSubpath();
CurrentSubpath = new PdfSubpath(); CurrentSubpath = new PdfSubpath();
} }
@@ -429,11 +429,11 @@
} }
CurrentSubpath.ClosePath(); CurrentSubpath.ClosePath();
AddSubpath(); AddCurrentSubpath();
return point; return point;
} }
public void AddSubpath() public void AddCurrentSubpath()
{ {
if (CurrentSubpath == null) if (CurrentSubpath == null)
{ {
@@ -446,22 +446,149 @@
public void StrokePath(bool close) public void StrokePath(bool close)
{ {
if (CurrentPath == null)
{
throw new ArgumentException("StrokePath(null)");
//return;
}
CurrentPath.SetStroked();
if (close)
{
CurrentSubpath.ClosePath();
}
ClosePath();
} }
public void FillPath(FillingRule fillingRule, bool close) public void FillPath(FillingRule fillingRule, bool close)
{ {
if (CurrentPath == null)
{
throw new ArgumentException("FillPath(null)");
//return;
}
CurrentPath.SetFilled(fillingRule);
if (close)
{
CurrentSubpath.ClosePath();
}
ClosePath();
} }
public void FillStrokePath(FillingRule fillingRule, bool close) public void FillStrokePath(FillingRule fillingRule, bool close)
{ {
if (CurrentPath == null)
{
throw new ArgumentException("FillStrokePath(null)");
//return;
}
CurrentPath.SetFilled(fillingRule);
CurrentPath.SetStroked();
if (close)
{
CurrentSubpath.ClosePath();
}
ClosePath();
} }
/// <summary>
/// End the path object without filling or stroking it. This operator shall be a path-painting no-op,
/// used primarily for the side effect of changing the current clipping path (see 8.5.4, "Clipping Path Operators").
/// </summary>
public void EndPath()
{
AddCurrentSubpath();
if (CurrentPath.IsClipping)
{
/*if (!clipPaths)
{
// if we don't clip paths, add clipping paths
paths.Add(CurrentPath);
markedContentStack.AddPath(CurrentPath);
}*/
CurrentPath = null;
return;
}
paths.Add(CurrentPath);
markedContentStack.AddPath(CurrentPath);
CurrentPath = null;
}
public void ClosePath() public void ClosePath()
{ {
AddCurrentSubpath();
if (CurrentPath.IsClipping)
{
EndPath();
return;
}
var currentState = this.GetCurrentState();
if (CurrentPath.IsStroked)
{
CurrentPath.LineDashPattern = currentState.LineDashPattern;
CurrentPath.StrokeColor = currentState.CurrentStrokingColor;
CurrentPath.LineWidth = currentState.LineWidth;
CurrentPath.LineCapStyle = currentState.CapStyle;
CurrentPath.LineJoinStyle = currentState.JoinStyle;
}
if (CurrentPath.IsFilled)
{
CurrentPath.FillColor = currentState.CurrentNonStrokingColor;
}
//if (clipPaths)
//{
var clippedPath = currentState.CurrentClippingPath.Clip(CurrentPath);
if (clippedPath != null)
{
paths.Add(clippedPath);
markedContentStack.AddPath(clippedPath);
}
/*}
else
{
paths.Add(CurrentPath);
markedContentStack.AddPath(CurrentPath);
}*/
CurrentPath = null;
}
public void ModifyClippingIntersect(FillingRule clippingRule)
{
if (CurrentPath == null)
{
throw new ArgumentException("ModifyClippingIntersect(null)");
}
AddCurrentSubpath();
CurrentPath.SetClipping(clippingRule);
var currentClipping = GetCurrentState().CurrentClippingPath;
currentClipping.SetClipping(clippingRule);
var newClippings = CurrentPath.Clip(currentClipping);
if (newClippings == null)
{
Console.WriteLine("ContentStreamProcessor.ModifyClippingIntersect(): Warning, empty clipping path found... Clipping path not updated.");
log.Warn("ModifyClippingIntersect(): Warning, empty clipping path found... Clipping path not updated.");
}
else
{
GetCurrentState().CurrentClippingPath = newClippings;
}
} }
public void SetNamedGraphicsState(NameToken stateName) public void SetNamedGraphicsState(NameToken stateName)
@@ -563,15 +690,5 @@
TextMatrices.TextMatrix = newMatrix; TextMatrices.TextMatrix = newMatrix;
} }
public void ModifyClippingIntersect(FillingRule clippingRule)
{
if (CurrentSubpath == null)
{
return;
}
}
} }
} }

View File

@@ -85,6 +85,17 @@
/// Start a new sub-path. /// Start a new sub-path.
/// </summary> /// </summary>
void BeginSubpath(); void BeginSubpath();
/// <summary>
/// Close the current subpath.
/// </summary>
/// <returns></returns>
PdfPoint CloseSubpath();
/// <summary>
/// Add the current subpath to the path.
/// </summary>
void AddCurrentSubpath();
/// <summary> /// <summary>
/// Stroke the current path. /// Stroke the current path.

View File

@@ -57,7 +57,7 @@
top?.AddLetter(letter); top?.AddLetter(letter);
} }
public void AddPath(PdfSubpath path) public void AddPath(PdfPath path)
{ {
top?.AddPath(path); top?.AddPath(path);
} }
@@ -86,7 +86,7 @@
private readonly DictionaryToken properties; private readonly DictionaryToken properties;
private readonly List<Letter> letters = new List<Letter>(); private readonly List<Letter> letters = new List<Letter>();
private readonly List<PdfSubpath> paths = new List<PdfSubpath>(); private readonly List<PdfPath> paths = new List<PdfPath>();
private readonly List<IPdfImage> images = new List<IPdfImage>(); private readonly List<IPdfImage> images = new List<IPdfImage>();
public List<MarkedContentElement> Children { get; } = new List<MarkedContentElement>(); public List<MarkedContentElement> Children { get; } = new List<MarkedContentElement>();
@@ -108,7 +108,7 @@
images.Add(image); images.Add(image);
} }
public void AddPath(PdfSubpath path) public void AddPath(PdfPath path)
{ {
paths.Add(path); paths.Add(path);
} }

View File

@@ -71,17 +71,12 @@
/// <inheritdoc /> /// <inheritdoc />
public void Run(IOperationContext operationContext) public void Run(IOperationContext operationContext)
{ {
var controlPoint1 = new PdfPoint(X1, Y1); var controlPoint1 = operationContext.CurrentTransformationMatrix.Transform(new PdfPoint(X1, Y1));
var controlPoint2 = new PdfPoint(X2, Y2); var controlPoint2 = operationContext.CurrentTransformationMatrix.Transform(new PdfPoint(X2, Y2));
var end = new PdfPoint(X3, Y3); var end = operationContext.CurrentTransformationMatrix.Transform(new PdfPoint(X3, Y3));
operationContext.CurrentSubpath.BezierCurveTo(controlPoint1.X, controlPoint1.Y,
var controlPoint1Transform = operationContext.CurrentTransformationMatrix.Transform(controlPoint1); controlPoint2.X, controlPoint2.Y, end.X, end.Y);
var controlPoint2Transform = operationContext.CurrentTransformationMatrix.Transform(controlPoint2); operationContext.CurrentPosition = end;
var endTransform = operationContext.CurrentTransformationMatrix.Transform(end);
operationContext.CurrentSubpath.BezierCurveTo(controlPoint1Transform.X, controlPoint1Transform.Y,
controlPoint2Transform.X, controlPoint2Transform.Y,
endTransform.X, endTransform.Y);
operationContext.CurrentPosition = endTransform;
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -56,16 +56,10 @@
/// <inheritdoc /> /// <inheritdoc />
public void Run(IOperationContext operationContext) public void Run(IOperationContext operationContext)
{ {
var controlPoint1 = new PdfPoint(X1, Y1); var controlPoint1 = operationContext.CurrentTransformationMatrix.Transform(new PdfPoint(X1, Y1));
var end = new PdfPoint(X3, Y3); var end = operationContext.CurrentTransformationMatrix.Transform(new PdfPoint(X3, Y3));
var controlPoint1Transform = operationContext.CurrentTransformationMatrix.Transform(controlPoint1); operationContext.CurrentSubpath.BezierCurveTo(controlPoint1.X, controlPoint1.Y, end.X, end.Y, end.X, end.Y);
var endTransform = operationContext.CurrentTransformationMatrix.Transform(end); operationContext.CurrentPosition = end;
operationContext.CurrentSubpath.BezierCurveTo(controlPoint1Transform.X, controlPoint1Transform.Y,
endTransform.X,
endTransform.Y,
endTransform.X,
endTransform.Y);
operationContext.CurrentPosition = endTransform;
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -56,14 +56,12 @@
/// <inheritdoc /> /// <inheritdoc />
public void Run(IOperationContext operationContext) public void Run(IOperationContext operationContext)
{ {
var lowerLeft = new PdfPoint(LowerLeftX, LowerLeftY);
var upperRight = new PdfPoint(LowerLeftX + Width, LowerLeftY + Height);
operationContext.BeginSubpath(); operationContext.BeginSubpath();
var lowerLeftTransform = operationContext.CurrentTransformationMatrix.Transform(lowerLeft); var lowerLeft = operationContext.CurrentTransformationMatrix.Transform(new PdfPoint(LowerLeftX, LowerLeftY));
var upperRightTransform = operationContext.CurrentTransformationMatrix.Transform(upperRight); var upperRight = operationContext.CurrentTransformationMatrix.Transform(new PdfPoint(LowerLeftX + Width, LowerLeftY + Height));
operationContext.CurrentSubpath.Rectangle(lowerLeftTransform.X, lowerLeftTransform.Y, upperRightTransform.X - lowerLeftTransform.X, upperRightTransform.Y - lowerLeftTransform.Y); operationContext.CurrentSubpath.Rectangle(lowerLeft.X, lowerLeft.Y, upperRight.X - lowerLeft.X, upperRight.Y - lowerLeft.Y);
operationContext.AddCurrentSubpath();
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -41,11 +41,10 @@
/// <inheritdoc /> /// <inheritdoc />
public void Run(IOperationContext operationContext) public void Run(IOperationContext operationContext)
{ {
var point = new PdfPoint(X, Y);
operationContext.BeginSubpath(); operationContext.BeginSubpath();
var pointTransform = operationContext.CurrentTransformationMatrix.Transform(point); var point = operationContext.CurrentTransformationMatrix.Transform(new PdfPoint(X, Y));
operationContext.CurrentPosition = pointTransform; operationContext.CurrentPosition = point;
operationContext.CurrentSubpath.MoveTo(pointTransform.X, pointTransform.Y); operationContext.CurrentSubpath.MoveTo(point.X, point.Y);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -29,7 +29,7 @@
/// <inheritdoc /> /// <inheritdoc />
public void Run(IOperationContext operationContext) public void Run(IOperationContext operationContext)
{ {
operationContext.CurrentSubpath?.ClosePath(); operationContext.CurrentPosition = operationContext.CloseSubpath();
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -45,7 +45,7 @@
/// <summary> /// <summary>
/// Thickness in user space units of path to be stroked. /// Thickness in user space units of path to be stroked.
/// </summary> /// </summary>
public double LineWidth { get; set; } = double.NaN; public decimal LineWidth { get; set; }
/// <summary> /// <summary>
/// The pattern to be used for stroked lines. /// The pattern to be used for stroked lines.