diff --git a/src/UglyToad.PdfPig.Tokenization/NumericTokenizer.cs b/src/UglyToad.PdfPig.Tokenization/NumericTokenizer.cs index e5c56fc8..3b3dd813 100644 --- a/src/UglyToad.PdfPig.Tokenization/NumericTokenizer.cs +++ b/src/UglyToad.PdfPig.Tokenization/NumericTokenizer.cs @@ -57,9 +57,13 @@ switch (str) { + case "-1": + token = NumericToken.MinusOne; + return true; case "-": case ".": case "0": + case "0000": token = NumericToken.Zero; return true; case "1": @@ -92,9 +96,42 @@ case "10": token = NumericToken.Ten; return true; + case "11": + token = NumericToken.Eleven; + return true; + case "12": + token = NumericToken.Twelve; + return true; + case "13": + token = NumericToken.Thirteen; + return true; + case "14": + token = NumericToken.Fourteen; + return true; + case "15": + token = NumericToken.Fifteen; + return true; + case "16": + token = NumericToken.Sixteen; + return true; + case "17": + token = NumericToken.Seventeen; + return true; + case "18": + token = NumericToken.Eighteen; + return true; + case "19": + token = NumericToken.Nineteen; + return true; + case "20": + token = NumericToken.Twenty; + return true; case "100": token = NumericToken.OneHundred; return true; + case "500": + token = NumericToken.FiveHundred; + return true; case "1000": token = NumericToken.OneThousand; return true; diff --git a/src/UglyToad.PdfPig.Tokens/NumericToken.cs b/src/UglyToad.PdfPig.Tokens/NumericToken.cs index a5f4f20b..4f2b0015 100644 --- a/src/UglyToad.PdfPig.Tokens/NumericToken.cs +++ b/src/UglyToad.PdfPig.Tokens/NumericToken.cs @@ -10,6 +10,11 @@ /// public class NumericToken : IDataToken { + /// + /// Single instance of numeric token for -1. + /// + public static readonly NumericToken MinusOne = new NumericToken(-1); + /// /// Single instance of numeric token for 0. /// @@ -64,11 +69,66 @@ /// public static readonly NumericToken Ten = new NumericToken(10); + /// + /// Single instance of numeric token for 11. + /// + public static readonly NumericToken Eleven = new NumericToken(11); + + /// + /// Single instance of numeric token for 12. + /// + public static readonly NumericToken Twelve = new NumericToken(12); + + /// + /// Single instance of numeric token for 13. + /// + public static readonly NumericToken Thirteen = new NumericToken(13); + + /// + /// Single instance of numeric token for 14. + /// + public static readonly NumericToken Fourteen = new NumericToken(14); + + /// + /// Single instance of numeric token for 15. + /// + public static readonly NumericToken Fifteen = new NumericToken(15); + + /// + /// Single instance of numeric token for 16. + /// + public static readonly NumericToken Sixteen = new NumericToken(16); + + /// + /// Single instance of numeric token for 17. + /// + public static readonly NumericToken Seventeen = new NumericToken(17); + + /// + /// Single instance of numeric token for 18. + /// + public static readonly NumericToken Eighteen = new NumericToken(18); + + /// + /// Single instance of numeric token for 19. + /// + public static readonly NumericToken Nineteen = new NumericToken(19); + + /// + /// Single instance of numeric token for 20. + /// + public static readonly NumericToken Twenty = new NumericToken(20); + /// /// Single instance of numeric token for 100. /// public static readonly NumericToken OneHundred = new NumericToken(100); + /// + /// Single instance of numeric token for 500. + /// + public static readonly NumericToken FiveHundred = new NumericToken(500); + /// /// Single instance of numeric token for 1000. /// diff --git a/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs b/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs index 363b77da..fd7d6015 100644 --- a/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs +++ b/src/UglyToad.PdfPig/Graphics/ContentStreamProcessor.cs @@ -217,15 +217,13 @@ var boundingBox = font.GetBoundingBox(code); - var transformedGlyphBounds = rotation.Rotate(transformationMatrix) - .Transform(textMatrix - .Transform(renderingMatrix - .Transform(boundingBox.GlyphBounds))); + var rotatedTransformationMatrix = rotation.Rotate(transformationMatrix); - var transformedPdfBounds = rotation.Rotate(transformationMatrix) - .Transform(textMatrix - .Transform(renderingMatrix - .Transform(new PdfRectangle(0, 0, boundingBox.Width, 0)))); + var transformedGlyphBounds = PerformantRectangleTransformer + .Transform(renderingMatrix, textMatrix, rotatedTransformationMatrix, boundingBox.GlyphBounds); + + var transformedPdfBounds = PerformantRectangleTransformer + .Transform(renderingMatrix, textMatrix, rotatedTransformationMatrix, new PdfRectangle(0, 0, boundingBox.Width, 0)); // If the text rendering mode calls for filling, the current nonstroking color in the graphics state is used; // if it calls for stroking, the current stroking color is used. @@ -572,6 +570,7 @@ CurrentPath = null; } + public void ModifyClippingIntersect(FillingRule clippingRule) { if (CurrentPath == null) diff --git a/src/UglyToad.PdfPig/Graphics/PerformantRectangleTransformer.cs b/src/UglyToad.PdfPig/Graphics/PerformantRectangleTransformer.cs new file mode 100644 index 00000000..aed6eb30 --- /dev/null +++ b/src/UglyToad.PdfPig/Graphics/PerformantRectangleTransformer.cs @@ -0,0 +1,87 @@ +using UglyToad.PdfPig.Core; + +namespace UglyToad.PdfPig.Graphics +{ + internal static class PerformantRectangleTransformer + { + public static PdfRectangle Transform(TransformationMatrix first, TransformationMatrix second, TransformationMatrix third, PdfRectangle rectangle) + { + var mutable = new MutableRectangle(rectangle); + + mutable.Transform(first); + mutable.Transform(second); + mutable.Transform(third); + + return mutable.ToRectangle(); + } + + private struct MutableRectangle + { + private double topLeftX; + private double topLeftY; + + private double topRightX; + private double topRightY; + + private double bottomLeftX; + private double bottomLeftY; + + private double bottomRightX; + private double bottomRightY; + + public MutableRectangle(PdfRectangle rectangle) + { + topLeftX = rectangle.TopLeft.X; + topLeftY = rectangle.TopLeft.Y; + + topRightX = rectangle.TopRight.X; + topRightY = rectangle.TopRight.Y; + + bottomLeftX = rectangle.BottomLeft.X; + bottomLeftY = rectangle.BottomLeft.Y; + + bottomRightX = rectangle.BottomRight.X; + bottomRightY = rectangle.BottomRight.Y; + } + + public void Transform(TransformationMatrix matrix) + { + /* + * TransformationMatrix.Transform(PdfPoint original) + * var x = A * original.X + C * original.Y + E; + * var y = B * original.X + D * original.Y + F; + * return new PdfPoint(x, y); + * + * For a rectangle runs on TopLeft, TopRight, BottomLeft and BottomRight + * and returns a new rectangle. + */ + + var x = matrix.A * topLeftX + matrix.C * topLeftY + matrix.E; + var y = matrix.B * topLeftX + matrix.D * topLeftY + matrix.F; + topLeftX = x; + topLeftY = y; + + x = matrix.A * topRightX + matrix.C * topRightY + matrix.E; + y = matrix.B * topRightX + matrix.D * topRightY + matrix.F; + topRightX = x; + topRightY = y; + + x = matrix.A * bottomLeftX + matrix.C * bottomLeftY + matrix.E; + y = matrix.B * bottomLeftX + matrix.D * bottomLeftY + matrix.F; + bottomLeftX = x; + bottomLeftY = y; + + x = matrix.A * bottomRightX + matrix.C * bottomRightY + matrix.E; + y = matrix.B * bottomRightX + matrix.D * bottomRightY + matrix.F; + bottomRightX = x; + bottomRightY = y; + } + + public PdfRectangle ToRectangle() + { + return new PdfRectangle(new PdfPoint(topLeftX, topLeftY), new PdfPoint(topRightX, topRightY), + new PdfPoint(bottomLeftX, bottomLeftY), new PdfPoint(bottomRightX, bottomRightY)); + } + } + } +}