diff --git a/src/UglyToad.PdfPig.Core/Globals.cs b/src/UglyToad.PdfPig.Core/Globals.cs new file mode 100644 index 000000000..30cd4b7b4 --- /dev/null +++ b/src/UglyToad.PdfPig.Core/Globals.cs @@ -0,0 +1,2 @@ +global using System; +global using System.Collections.Generic; \ No newline at end of file diff --git a/src/UglyToad.PdfPig.Core/TransformationMatrix.cs b/src/UglyToad.PdfPig.Core/TransformationMatrix.cs index 1496c7a3d..c21649ceb 100644 --- a/src/UglyToad.PdfPig.Core/TransformationMatrix.cs +++ b/src/UglyToad.PdfPig.Core/TransformationMatrix.cs @@ -1,9 +1,6 @@ namespace UglyToad.PdfPig.Core { - using System; - using System.Collections.Generic; using System.Diagnostics.Contracts; - using System.Linq; using static UglyToad.PdfPig.Core.PdfSubpath; /// @@ -138,53 +135,27 @@ public static TransformationMatrix GetRotationMatrix(double degreesCounterclockw throw new ArgumentOutOfRangeException(nameof(col), "Cannot access negative columns in a matrix."); } - switch (row) - { - case 0: - { - switch (col) - { - case 0: - return A; - case 1: - return B; - case 2: - return row1; - default: - throw new ArgumentOutOfRangeException($"Trying to access {row}, {col} which was not in the value array."); - } - } - case 1: - { - switch (col) - { - case 0: - return C; - case 1: - return D; - case 2: - return row2; - default: - throw new ArgumentOutOfRangeException($"Trying to access {row}, {col} which was not in the value array."); - } - } - case 2: - { - switch (col) - { - case 0: - return E; - case 1: - return F; - case 2: - return row3; - default: - throw new ArgumentOutOfRangeException($"Trying to access {row}, {col} which was not in the value array."); - } - } - default: - throw new ArgumentOutOfRangeException($"Trying to access {row}, {col} which was not in the value array."); - } + return row switch { + 0 => col switch { + 0 => A, + 1 => B, + 2 => row1, + _ => throw new ArgumentOutOfRangeException($"Trying to access {row}, {col} which was not in the value array.") + }, + 1 => col switch { + 0 => C, + 1 => D, + 2 => row2, + _ => throw new ArgumentOutOfRangeException($"Trying to access {row}, {col} which was not in the value array.") + }, + 2 => col switch { + 0 => E, + 1 => F, + 2 => row3, + _ => throw new ArgumentOutOfRangeException($"Trying to access {row}, {col} which was not in the value array.") + }, + _ => throw new ArgumentOutOfRangeException($"Trying to access {row}, {col} which was not in the value array.") + }; } } @@ -201,7 +172,7 @@ public static TransformationMatrix GetRotationMatrix(double degreesCounterclockw /// Create a new . /// /// The 9 values of the matrix. - public TransformationMatrix(double[] value) : this(value[0], value[1], value[2], value[3], value[4], value[5], value[6], value[7], value[8]) + public TransformationMatrix(ReadOnlySpan value) : this(value[0], value[1], value[2], value[3], value[4], value[5], value[6], value[7], value[8]) { } @@ -373,7 +344,7 @@ public static TransformationMatrix FromValues(double a, double b, double c, doub /// /// Either all 9 values of the matrix, 6 values in the default PDF order or the 4 values of the top left square. /// - public static TransformationMatrix FromArray(double[] values) + public static TransformationMatrix FromArray(ReadOnlySpan values) { if (values.Length == 9) { @@ -394,7 +365,7 @@ public static TransformationMatrix FromArray(double[] values) 0, 0, 1); } - throw new ArgumentException("The array must either define all 9 elements of the matrix or all 6 key elements. Instead array was: " + values); + throw new ArgumentException("The array must either define all 9 elements of the matrix or all 6 key elements. Instead array was: " + string.Join(", ", values.ToArray())); } /// @@ -403,7 +374,7 @@ public static TransformationMatrix FromArray(double[] values) /// The matrix to multiply /// The resulting matrix. [Pure] - public TransformationMatrix Multiply(TransformationMatrix matrix) + public TransformationMatrix Multiply(in TransformationMatrix matrix) { var a = (A * matrix.A) + (B * matrix.C) + (row1 * matrix.E); var b = (A * matrix.B) + (B * matrix.D) + (row1 * matrix.F); @@ -524,17 +495,19 @@ public static bool Equals(TransformationMatrix a, TransformationMatrix b) /// public override int GetHashCode() { - var hashCode = 472622392; - hashCode = hashCode * -1521134295 + row1.GetHashCode(); - hashCode = hashCode * -1521134295 + row2.GetHashCode(); - hashCode = hashCode * -1521134295 + row3.GetHashCode(); - hashCode = hashCode * -1521134295 + A.GetHashCode(); - hashCode = hashCode * -1521134295 + B.GetHashCode(); - hashCode = hashCode * -1521134295 + C.GetHashCode(); - hashCode = hashCode * -1521134295 + D.GetHashCode(); - hashCode = hashCode * -1521134295 + E.GetHashCode(); - hashCode = hashCode * -1521134295 + F.GetHashCode(); - return hashCode; + var hashCode = new HashCode(); + + hashCode.Add(row1); + hashCode.Add(row2); + hashCode.Add(row3); + hashCode.Add(A); + hashCode.Add(B); + hashCode.Add(C); + hashCode.Add(D); + hashCode.Add(E); + hashCode.Add(F); + + return hashCode.ToHashCode(); } /// diff --git a/src/UglyToad.PdfPig.DocumentLayoutAnalysis/Globals.cs b/src/UglyToad.PdfPig.DocumentLayoutAnalysis/Globals.cs new file mode 100644 index 000000000..30cd4b7b4 --- /dev/null +++ b/src/UglyToad.PdfPig.DocumentLayoutAnalysis/Globals.cs @@ -0,0 +1,2 @@ +global using System; +global using System.Collections.Generic; \ No newline at end of file diff --git a/src/UglyToad.PdfPig.Fonts/Globals.cs b/src/UglyToad.PdfPig.Fonts/Globals.cs new file mode 100644 index 000000000..30cd4b7b4 --- /dev/null +++ b/src/UglyToad.PdfPig.Fonts/Globals.cs @@ -0,0 +1,2 @@ +global using System; +global using System.Collections.Generic; \ No newline at end of file diff --git a/src/UglyToad.PdfPig.Tokenization/Globals.cs b/src/UglyToad.PdfPig.Tokenization/Globals.cs new file mode 100644 index 000000000..30cd4b7b4 --- /dev/null +++ b/src/UglyToad.PdfPig.Tokenization/Globals.cs @@ -0,0 +1,2 @@ +global using System; +global using System.Collections.Generic; \ No newline at end of file diff --git a/src/UglyToad.PdfPig.Tokens/Globals.cs b/src/UglyToad.PdfPig.Tokens/Globals.cs new file mode 100644 index 000000000..30cd4b7b4 --- /dev/null +++ b/src/UglyToad.PdfPig.Tokens/Globals.cs @@ -0,0 +1,2 @@ +global using System; +global using System.Collections.Generic; \ No newline at end of file diff --git a/src/UglyToad.PdfPig/Annotations/QuadPointsQuadrilateral.cs b/src/UglyToad.PdfPig/Annotations/QuadPointsQuadrilateral.cs index e39973be2..5dcb6f8c7 100644 --- a/src/UglyToad.PdfPig/Annotations/QuadPointsQuadrilateral.cs +++ b/src/UglyToad.PdfPig/Annotations/QuadPointsQuadrilateral.cs @@ -1,7 +1,5 @@ namespace UglyToad.PdfPig.Annotations { - using System; - using System.Collections.Generic; using Core; /// @@ -10,13 +8,15 @@ /// public readonly struct QuadPointsQuadrilateral { + private readonly PdfPoint[] points; + /// /// The 4 points defining this quadrilateral. /// The PDF specification defines these as being in anti-clockwise order starting from the lower-left corner, however /// Adobe's implementation doesn't obey the specification and points seem to go in the order: top-left, top-right, /// bottom-left, bottom-right. See: https://stackoverflow.com/questions/9855814/pdf-spec-vs-acrobat-creation-quadpoints. /// - public IReadOnlyList Points { get; } + public ReadOnlySpan Points => points; /// /// Create a new . @@ -33,7 +33,7 @@ public QuadPointsQuadrilateral(PdfPoint[] points) throw new ArgumentException($"Quadpoints quadrilateral should only contain 4 points, instead got {points.Length} points."); } - Points = points; + this.points = points; } /// diff --git a/src/UglyToad.PdfPig/Geometry/GeometryExtensions.cs b/src/UglyToad.PdfPig/Geometry/GeometryExtensions.cs index b483846ec..675776354 100644 --- a/src/UglyToad.PdfPig/Geometry/GeometryExtensions.cs +++ b/src/UglyToad.PdfPig/Geometry/GeometryExtensions.cs @@ -1,10 +1,8 @@ namespace UglyToad.PdfPig.Geometry { - using Core; - using System; - using System.Collections.Generic; using System.Linq; using System.Text; + using Core; using UglyToad.PdfPig.Geometry.ClipperLibrary; using UglyToad.PdfPig.Graphics; using static UglyToad.PdfPig.Core.PdfSubpath; @@ -83,7 +81,7 @@ private static PdfRectangle ParametricPerpendicularProjection(IReadOnlyList mrb = stackalloc double[8]; double Amin = double.PositiveInfinity; int j = 1; @@ -169,7 +167,7 @@ private static PdfRectangle ParametricPerpendicularProjection(IReadOnlyList @@ -471,10 +469,19 @@ public static bool IntersectsWith(this PdfRectangle rectangle, PdfRectangle othe /// Gets the axis-aligned rectangle that completely containing the original rectangle, with no rotation. /// /// - public static PdfRectangle Normalise(this PdfRectangle rectangle) + public static PdfRectangle Normalise(this in PdfRectangle rectangle) { - var points = new[] { rectangle.BottomLeft, rectangle.BottomRight, rectangle.TopLeft, rectangle.TopRight }; - return new PdfRectangle(points.Min(p => p.X), points.Min(p => p.Y), points.Max(p => p.X), points.Max(p => p.Y)); + var bottomLeft = rectangle.BottomLeft; + var bottomRight = rectangle.BottomRight; + var topLeft = rectangle.TopLeft; + var topRight = rectangle.TopRight; + + var minX = Math.Min(Math.Min(bottomLeft.X, bottomRight.X), Math.Min(topLeft.X, topRight.X)); + var minY = Math.Min(Math.Min(bottomLeft.Y, bottomRight.Y), Math.Min(topLeft.Y, topRight.Y)); + var maxX = Math.Max(Math.Max(bottomLeft.X, bottomRight.X), Math.Max(topLeft.X, topRight.X)); + var maxY = Math.Max(Math.Max(bottomLeft.Y, bottomRight.Y), Math.Max(topLeft.Y, topRight.Y)); + + return new PdfRectangle(minX, minY, maxX, maxY); } /// diff --git a/src/UglyToad.PdfPig/Globals.cs b/src/UglyToad.PdfPig/Globals.cs new file mode 100644 index 000000000..30cd4b7b4 --- /dev/null +++ b/src/UglyToad.PdfPig/Globals.cs @@ -0,0 +1,2 @@ +global using System; +global using System.Collections.Generic; \ No newline at end of file diff --git a/src/UglyToad.PdfPig/Images/Png/Adam7.cs b/src/UglyToad.PdfPig/Images/Png/Adam7.cs index 0d4e5d45e..ce4ac0ad3 100644 --- a/src/UglyToad.PdfPig/Images/Png/Adam7.cs +++ b/src/UglyToad.PdfPig/Images/Png/Adam7.cs @@ -1,33 +1,29 @@ namespace UglyToad.PdfPig.Images.Png { - using System.Collections.Generic; - internal static class Adam7 { /// /// For a given pass number (1 indexed) the scanline indexes of the lines included in that pass in the 8x8 grid. /// - private static readonly IReadOnlyDictionary PassToScanlineGridIndex = new Dictionary - { - { 1, [0] }, - { 2, [0] }, - { 3, [4] }, - { 4, [0, 4] }, - { 5, [2, 6] }, - { 6, [0, 2, 4, 6] }, - { 7, [1, 3, 5, 7] } - }; - - private static readonly IReadOnlyDictionary PassToScanlineColumnIndex = new Dictionary - { - { 1, [0] }, - { 2, [4] }, - { 3, [0, 4] }, - { 4, [2, 6] }, - { 5, [0, 2, 4, 6] }, - { 6, [1, 3, 5, 7] }, - { 7, [0, 1, 2, 3, 4, 5, 6, 7] } - }; + private static readonly int[][] PassToScanlineGridIndex = [ + [0], + [0], + [4], + [0, 4], + [2, 6], + [0, 2, 4, 6], + [1, 3, 5, 7] + ]; + + private static readonly int[][] PassToScanlineColumnIndex = [ + [0], + [4], + [0, 4], + [2, 6], + [0, 2, 4, 6], + [1, 3, 5, 7], + [0, 1, 2, 3, 4, 5, 6, 7] + ]; /* * To go from raw image data to interlaced: @@ -50,7 +46,7 @@ internal static class Adam7 public static int GetNumberOfScanlinesInPass(ImageHeader header, int pass) { - var indices = PassToScanlineGridIndex[pass + 1]; + var indices = PassToScanlineGridIndex[pass]; var mod = header.Height % 8; @@ -75,7 +71,7 @@ public static int GetNumberOfScanlinesInPass(ImageHeader header, int pass) public static int GetPixelsPerScanlineInPass(ImageHeader header, int pass) { - var indices = PassToScanlineColumnIndex[pass + 1]; + var indices = PassToScanlineColumnIndex[pass]; var mod = header.Width % 8; @@ -100,8 +96,8 @@ public static int GetPixelsPerScanlineInPass(ImageHeader header, int pass) public static (int x, int y) GetPixelIndexForScanlineInPass(ImageHeader header, int pass, int scanlineIndex, int indexInScanline) { - var columnIndices = PassToScanlineColumnIndex[pass + 1]; - var rows = PassToScanlineGridIndex[pass + 1]; + var columnIndices = PassToScanlineColumnIndex[pass]; + var rows = PassToScanlineGridIndex[pass]; var actualRow = scanlineIndex % rows.Length; var actualCol = indexInScanline % columnIndices.Length; diff --git a/src/UglyToad.PdfPig/Parser/Parts/CrossReference/CrossReferenceStreamParser.cs b/src/UglyToad.PdfPig/Parser/Parts/CrossReference/CrossReferenceStreamParser.cs index 19ff452f8..0e3f78df8 100644 --- a/src/UglyToad.PdfPig/Parser/Parts/CrossReference/CrossReferenceStreamParser.cs +++ b/src/UglyToad.PdfPig/Parser/Parts/CrossReference/CrossReferenceStreamParser.cs @@ -1,6 +1,5 @@ namespace UglyToad.PdfPig.Parser.Parts.CrossReference { - using System.Collections.Generic; using Core; using Filters; using PdfPig.CrossReference; @@ -45,7 +44,10 @@ public CrossReferenceTablePart Parse(long streamOffset, long? fromTableAtOffset, var objectNumbers = GetObjectNumbers(stream.StreamDictionary); var lineNumber = 0; - var lineBuffer = new byte[fieldSizes.LineLength]; + Span lineBuffer = fieldSizes.LineLength <= 64 + ? stackalloc byte[fieldSizes.LineLength] + : new byte[fieldSizes.LineLength]; + foreach (var objectNumber in objectNumbers) { if (lineNumber >= lineCount) @@ -84,7 +86,7 @@ public CrossReferenceTablePart Parse(long streamOffset, long? fromTableAtOffset, } private static void ReadNextStreamObject(int type, long objectNumber, CrossReferenceStreamFieldSize fieldSizes, - CrossReferenceTablePartBuilder builder, byte[] lineBuffer) + CrossReferenceTablePartBuilder builder, ReadOnlySpan lineBuffer) { switch (type) { diff --git a/src/UglyToad.PdfPig/Writer/NoTextTokenWriter.cs b/src/UglyToad.PdfPig/Writer/NoTextTokenWriter.cs index 712f1171f..ff8857086 100644 --- a/src/UglyToad.PdfPig/Writer/NoTextTokenWriter.cs +++ b/src/UglyToad.PdfPig/Writer/NoTextTokenWriter.cs @@ -1,13 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Linq; using UglyToad.PdfPig.Core; using UglyToad.PdfPig.Filters; -using UglyToad.PdfPig.Graphics.Operations.TextShowing; -using UglyToad.PdfPig.Graphics.Operations; using UglyToad.PdfPig.Graphics; +using UglyToad.PdfPig.Graphics.Operations; +using UglyToad.PdfPig.Graphics.Operations.TextShowing; using UglyToad.PdfPig.Logging; using UglyToad.PdfPig.Parser; using UglyToad.PdfPig.Tokens; @@ -17,7 +14,7 @@ namespace UglyToad.PdfPig.Writer /// /// Derived class of that does not write or operations in streams /// - internal class NoTextTokenWriter : TokenWriter + internal sealed class NoTextTokenWriter : TokenWriter { /// /// Set this value prior to processing page to get the right page number in log messages