mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-04-05 20:55:01 +08:00
Improve Code Quality (#831)
* Introduce globals * Spanify TransformationMatrix.FromArray * Eliminate allocation in GeometryExtensions.ParametricPerpendicularProjection * Eliminate allocation in CrossReferenceTablePart.Parse * Optimize Adam7 (eliminate virtual calls) * Spanify QuadPointsQuadrilateral.Points to eliminate virtual calls * Eliminate allocation in PdfRectangle.Normalize * Format TransformMatrix * Pass TransformationMatrix by reference in TransformationMatrix.Multiply * Seal NoTextTokenWriter
This commit is contained in:
parent
b6e0305a1c
commit
c6a7a2d0a2
2
src/UglyToad.PdfPig.Core/Globals.cs
Normal file
2
src/UglyToad.PdfPig.Core/Globals.cs
Normal file
@ -0,0 +1,2 @@
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
@ -138,53 +135,27 @@
|
||||
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 @@
|
||||
/// Create a new <see cref="TransformationMatrix"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">The 9 values of the matrix.</param>
|
||||
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<double> value) : this(value[0], value[1], value[2], value[3], value[4], value[5], value[6], value[7], value[8])
|
||||
{
|
||||
}
|
||||
|
||||
@ -373,7 +344,7 @@
|
||||
/// </summary>
|
||||
/// <param name="values">Either all 9 values of the matrix, 6 values in the default PDF order or the 4 values of the top left square.</param>
|
||||
/// <returns></returns>
|
||||
public static TransformationMatrix FromArray(double[] values)
|
||||
public static TransformationMatrix FromArray(ReadOnlySpan<double> values)
|
||||
{
|
||||
if (values.Length == 9)
|
||||
{
|
||||
@ -394,7 +365,7 @@
|
||||
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()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -403,7 +374,7 @@
|
||||
/// <param name="matrix">The matrix to multiply</param>
|
||||
/// <returns>The resulting matrix.</returns>
|
||||
[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 @@
|
||||
/// <inheritdoc />
|
||||
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();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
2
src/UglyToad.PdfPig.DocumentLayoutAnalysis/Globals.cs
Normal file
2
src/UglyToad.PdfPig.DocumentLayoutAnalysis/Globals.cs
Normal file
@ -0,0 +1,2 @@
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
2
src/UglyToad.PdfPig.Fonts/Globals.cs
Normal file
2
src/UglyToad.PdfPig.Fonts/Globals.cs
Normal file
@ -0,0 +1,2 @@
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
2
src/UglyToad.PdfPig.Tokenization/Globals.cs
Normal file
2
src/UglyToad.PdfPig.Tokenization/Globals.cs
Normal file
@ -0,0 +1,2 @@
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
2
src/UglyToad.PdfPig.Tokens/Globals.cs
Normal file
2
src/UglyToad.PdfPig.Tokens/Globals.cs
Normal file
@ -0,0 +1,2 @@
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
@ -1,7 +1,5 @@
|
||||
namespace UglyToad.PdfPig.Annotations
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Core;
|
||||
|
||||
/// <summary>
|
||||
@ -10,13 +8,15 @@
|
||||
/// </summary>
|
||||
public readonly struct QuadPointsQuadrilateral
|
||||
{
|
||||
private readonly PdfPoint[] points;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public IReadOnlyList<PdfPoint> Points { get; }
|
||||
public ReadOnlySpan<PdfPoint> Points => points;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="QuadPointsQuadrilateral"/>.
|
||||
@ -33,7 +33,7 @@
|
||||
throw new ArgumentException($"Quadpoints quadrilateral should only contain 4 points, instead got {points.Length} points.");
|
||||
}
|
||||
|
||||
Points = points;
|
||||
this.points = points;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -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 @@
|
||||
return new PdfRectangle(polygon[0], polygon[1]);
|
||||
}
|
||||
|
||||
double[] MBR = new double[8];
|
||||
Span<double> mrb = stackalloc double[8];
|
||||
|
||||
double Amin = double.PositiveInfinity;
|
||||
int j = 1;
|
||||
@ -169,7 +167,7 @@
|
||||
if (A < Amin)
|
||||
{
|
||||
Amin = A;
|
||||
MBR = [R0X, R0Y, R1X, R1Y, R2X, R2Y, R3X, R3Y];
|
||||
mrb = [R0X, R0Y, R1X, R1Y, R2X, R2Y, R3X, R3Y];
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,10 +178,10 @@
|
||||
if (k == polygon.Count) break;
|
||||
}
|
||||
|
||||
return new PdfRectangle(new PdfPoint(MBR[4], MBR[5]),
|
||||
new PdfPoint(MBR[6], MBR[7]),
|
||||
new PdfPoint(MBR[2], MBR[3]),
|
||||
new PdfPoint(MBR[0], MBR[1]));
|
||||
return new PdfRectangle(new PdfPoint(mrb[4], mrb[5]),
|
||||
new PdfPoint(mrb[6], mrb[7]),
|
||||
new PdfPoint(mrb[2], mrb[3]),
|
||||
new PdfPoint(mrb[0], mrb[1]));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -471,10 +469,19 @@
|
||||
/// Gets the axis-aligned rectangle that completely containing the original rectangle, with no rotation.
|
||||
/// </summary>
|
||||
/// <param name="rectangle"></param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
2
src/UglyToad.PdfPig/Globals.cs
Normal file
2
src/UglyToad.PdfPig/Globals.cs
Normal file
@ -0,0 +1,2 @@
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
@ -1,33 +1,29 @@
|
||||
namespace UglyToad.PdfPig.Images.Png
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
internal static class Adam7
|
||||
{
|
||||
/// <summary>
|
||||
/// For a given pass number (1 indexed) the scanline indexes of the lines included in that pass in the 8x8 grid.
|
||||
/// </summary>
|
||||
private static readonly IReadOnlyDictionary<int, int[]> PassToScanlineGridIndex = new Dictionary<int, int[]>
|
||||
{
|
||||
{ 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 int[][] PassToScanlineGridIndex = [
|
||||
[0],
|
||||
[0],
|
||||
[4],
|
||||
[0, 4],
|
||||
[2, 6],
|
||||
[0, 2, 4, 6],
|
||||
[1, 3, 5, 7]
|
||||
];
|
||||
|
||||
private static readonly IReadOnlyDictionary<int, int[]> PassToScanlineColumnIndex = new Dictionary<int, int[]>
|
||||
{
|
||||
{ 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[][] 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 @@
|
||||
|
||||
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 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 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;
|
||||
|
@ -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 @@
|
||||
var objectNumbers = GetObjectNumbers(stream.StreamDictionary);
|
||||
|
||||
var lineNumber = 0;
|
||||
var lineBuffer = new byte[fieldSizes.LineLength];
|
||||
Span<byte> lineBuffer = fieldSizes.LineLength <= 64
|
||||
? stackalloc byte[fieldSizes.LineLength]
|
||||
: new byte[fieldSizes.LineLength];
|
||||
|
||||
foreach (var objectNumber in objectNumbers)
|
||||
{
|
||||
if (lineNumber >= lineCount)
|
||||
@ -84,7 +86,7 @@
|
||||
}
|
||||
|
||||
private static void ReadNextStreamObject(int type, long objectNumber, CrossReferenceStreamFieldSize fieldSizes,
|
||||
CrossReferenceTablePartBuilder builder, byte[] lineBuffer)
|
||||
CrossReferenceTablePartBuilder builder, ReadOnlySpan<byte> lineBuffer)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
|
@ -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
|
||||
/// <summary>
|
||||
/// Derived class of <see cref="TokenWriter"/> that does not write <see cref="ShowText"/> or <see cref="ShowTextsWithPositioning"/> operations in streams
|
||||
/// </summary>
|
||||
internal class NoTextTokenWriter : TokenWriter
|
||||
internal sealed class NoTextTokenWriter : TokenWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// Set this value prior to processing page to get the right page number in log messages
|
||||
|
Loading…
Reference in New Issue
Block a user