mirror of
https://github.com/UglyToad/PdfPig.git
synced 2026-03-10 00:23:29 +08:00
Improve Code Quality (#818)
* Make AdobeFontMetricsLigature a struct * Make AdobeFontMetricsCharacterSize a struct * Eliminate allocation in CompactFontFormatData * Pass TransformationMatrix by reference * Seal Encoding classes * Make SubTableHeaderEntry a readonly struct * Introduce StringSplitter and eliminate various allocations in GlyphListFactory * Eliminate a few substring allocations * Use char overload on StringBuilder * Eliminate virtual calls on stringIndex * Optimize ReadHelper ReadLong and ReadInt methods * Add additional readonly annotations to PdfRectangle * Optimize NameTokenizer * Eliminate allocation in TrueTypeGlyphTableSubsetter * Use empty arrays * Eliminate allocations in OperationWriteHelper.WriteHex * Use simplified DecryptCbc method on .NET 6+ * Fix windows-1252 encoding not working on net6.0 and 8.0 * Update int buffers to exact unsigned max length and eliminate additional byte allocation * Fix typo * Remove unused constant
This commit is contained in:
@@ -16,22 +16,22 @@
|
||||
/// <summary>
|
||||
/// Top left point of the rectangle.
|
||||
/// </summary>
|
||||
public PdfPoint TopLeft { get; }
|
||||
public readonly PdfPoint TopLeft { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Top right point of the rectangle.
|
||||
/// </summary>
|
||||
public PdfPoint TopRight { get; }
|
||||
public readonly PdfPoint TopRight { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Bottom right point of the rectangle.
|
||||
/// </summary>
|
||||
public PdfPoint BottomRight { get; }
|
||||
public readonly PdfPoint BottomRight { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Bottom left point of the rectangle.
|
||||
/// </summary>
|
||||
public PdfPoint BottomLeft { get; }
|
||||
public readonly PdfPoint BottomLeft { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Centroid point of the rectangle.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
namespace UglyToad.PdfPig.Core
|
||||
{
|
||||
using System;
|
||||
using System.Buffers.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
@@ -41,8 +41,6 @@
|
||||
'\f'
|
||||
];
|
||||
|
||||
private static readonly int MaximumNumberStringLength = long.MaxValue.ToString("D").Length;
|
||||
|
||||
/// <summary>
|
||||
/// Read a string from the input until a newline.
|
||||
/// </summary>
|
||||
@@ -134,7 +132,7 @@
|
||||
/// </remarks>
|
||||
public static bool IsWhitespace(byte c)
|
||||
{
|
||||
return c == 0 || c == 32 || c == AsciiLineFeed || c == AsciiCarriageReturn || c == 9 || c == 12;
|
||||
return c is 0 or 32 or AsciiLineFeed or AsciiCarriageReturn or 9 or 12;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -198,25 +196,24 @@
|
||||
public static long ReadLong(IInputBytes bytes)
|
||||
{
|
||||
SkipSpaces(bytes);
|
||||
long retval;
|
||||
|
||||
StringBuilder longBuffer = ReadStringNumber(bytes);
|
||||
Span<byte> buffer = stackalloc byte[19]; // max formatted uint64 length
|
||||
|
||||
try
|
||||
ReadNumberAsUtf8Bytes(bytes, buffer, out int bytesRead);
|
||||
|
||||
ReadOnlySpan<byte> longBytes = buffer.Slice(0, bytesRead);
|
||||
|
||||
if (Utf8Parser.TryParse(longBytes, out long result, out _))
|
||||
{
|
||||
retval = long.Parse(longBuffer.ToString(), CultureInfo.InvariantCulture);
|
||||
return result;
|
||||
}
|
||||
catch (FormatException e)
|
||||
else
|
||||
{
|
||||
var bytesToReverse = OtherEncodings.StringAsLatin1Bytes(longBuffer.ToString());
|
||||
bytes.Seek(bytes.CurrentOffset - bytesToReverse.Length);
|
||||
bytes.Seek(bytes.CurrentOffset - bytesRead);
|
||||
|
||||
throw new InvalidOperationException($"Error: Expected a long type at offset {bytes.CurrentOffset}, instead got \'{longBuffer}\'", e);
|
||||
throw new InvalidOperationException($"Error: Expected a long type at offset {bytes.CurrentOffset}, instead got \'{OtherEncodings.BytesAsLatin1String(longBytes)}\'");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Whether the given value is a digit or not.
|
||||
@@ -231,28 +228,29 @@
|
||||
/// </summary>
|
||||
public static int ReadInt(IInputBytes bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
if (bytes is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(bytes));
|
||||
}
|
||||
|
||||
SkipSpaces(bytes);
|
||||
int result;
|
||||
|
||||
var intBuffer = ReadStringNumber(bytes);
|
||||
Span<byte> buffer = stackalloc byte[10]; // max formatted uint32 length
|
||||
|
||||
try
|
||||
ReadNumberAsUtf8Bytes(bytes, buffer, out int bytesRead);
|
||||
|
||||
var intBytes = buffer.Slice(0, bytesRead);
|
||||
|
||||
if (Utf8Parser.TryParse(intBytes, out int result, out _))
|
||||
{
|
||||
result = int.Parse(intBuffer.ToString(), CultureInfo.InvariantCulture);
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
else
|
||||
{
|
||||
bytes.Seek(bytes.CurrentOffset - OtherEncodings.StringAsLatin1Bytes(intBuffer.ToString()).Length);
|
||||
|
||||
throw new PdfDocumentFormatException($"Error: Expected an integer type at offset {bytes.CurrentOffset}", e);
|
||||
bytes.Seek(bytes.CurrentOffset - bytesRead);
|
||||
|
||||
throw new PdfDocumentFormatException($"Error: Expected an integer type at offset {bytes.CurrentOffset}, instead got \'{OtherEncodings.BytesAsLatin1String(intBytes)}\'");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -304,25 +302,26 @@
|
||||
#endif
|
||||
}
|
||||
|
||||
private static StringBuilder ReadStringNumber(IInputBytes reader)
|
||||
private static void ReadNumberAsUtf8Bytes(IInputBytes reader, scoped Span<byte> buffer, out int bytesRead)
|
||||
{
|
||||
byte lastByte;
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
int position = 0;
|
||||
|
||||
byte lastByte;
|
||||
|
||||
while (reader.MoveNext() && (lastByte = reader.CurrentByte) != ' ' &&
|
||||
lastByte != AsciiLineFeed &&
|
||||
lastByte != AsciiCarriageReturn &&
|
||||
lastByte != 60 && //see sourceforge bug 1714707
|
||||
lastByte != 60 && // see sourceforge bug 1714707
|
||||
lastByte != '[' && // PDFBOX-1845
|
||||
lastByte != '(' && // PDFBOX-2579
|
||||
lastByte != 0)
|
||||
{
|
||||
buffer.Append((char)lastByte);
|
||||
|
||||
if (buffer.Length > MaximumNumberStringLength)
|
||||
if (position >= buffer.Length)
|
||||
{
|
||||
throw new InvalidOperationException($"Number \'{buffer}\' is getting too long, stop reading at offset {reader.CurrentOffset}");
|
||||
throw new InvalidOperationException($"Number \'{OtherEncodings.BytesAsLatin1String(buffer.Slice(0, position))}\' is getting too long, stop reading at offset {reader.CurrentOffset}");
|
||||
}
|
||||
|
||||
buffer[position++] = lastByte;
|
||||
}
|
||||
|
||||
if (!reader.IsAtEnd())
|
||||
@@ -330,7 +329,7 @@
|
||||
reader.Seek(reader.CurrentOffset - 1);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
bytesRead = position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/// The x and y components of the width vector of the font's characters.
|
||||
/// Presence implies that IsFixedPitch is true.
|
||||
/// </summary>
|
||||
public class AdobeFontMetricsCharacterSize
|
||||
public readonly struct AdobeFontMetricsCharacterSize
|
||||
{
|
||||
/// <summary>
|
||||
/// The horizontal width.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// A ligature in an Adobe Font Metrics individual character.
|
||||
/// </summary>
|
||||
public class AdobeFontMetricsLigature
|
||||
public readonly struct AdobeFontMetricsLigature
|
||||
{
|
||||
/// <summary>
|
||||
/// The character to join with to form a ligature.
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
namespace UglyToad.PdfPig.Fonts.CompactFontFormat
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Core;
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to the raw bytes of this Compact Font Format file with utility methods for reading data types from it.
|
||||
@@ -37,14 +35,7 @@
|
||||
/// </summary>
|
||||
public string ReadString(int length, Encoding encoding)
|
||||
{
|
||||
var bytes = new byte[length];
|
||||
|
||||
for (var i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
bytes[i] = ReadByte();
|
||||
}
|
||||
|
||||
return encoding.GetString(bytes);
|
||||
return encoding.GetString(ReadSpan(length));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -86,6 +77,20 @@
|
||||
return value;
|
||||
}
|
||||
|
||||
internal ReadOnlySpan<byte> ReadSpan(int count)
|
||||
{
|
||||
if (Position + count >= dataBytes.Length)
|
||||
{
|
||||
throw new IndexOutOfRangeException($"Cannot read past end of data. Attempted to read to {Position + count} when the underlying data is {dataBytes.Length} bytes long.");
|
||||
}
|
||||
|
||||
var result = dataBytes.Span.Slice(Position + 1, count);
|
||||
|
||||
Position += count;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read byte.
|
||||
/// </summary>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
internal static class CompactFontFormatEncodingReader
|
||||
{
|
||||
public static Encoding ReadEncoding(CompactFontFormatData data, ICompactFontFormatCharset charset, IReadOnlyList<string> stringIndex)
|
||||
public static Encoding ReadEncoding(CompactFontFormatData data, ICompactFontFormatCharset charset, ReadOnlySpan<string> stringIndex)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
@@ -32,7 +32,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
private static CompactFontFormatFormat0Encoding ReadFormat0Encoding(CompactFontFormatData data, ICompactFontFormatCharset charset, IReadOnlyList<string> stringIndex, byte format)
|
||||
private static CompactFontFormatFormat0Encoding ReadFormat0Encoding(CompactFontFormatData data, ICompactFontFormatCharset charset, ReadOnlySpan<string> stringIndex, byte format)
|
||||
{
|
||||
var numberOfCodes = data.ReadCard8();
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
values.Add((code, sid, str));
|
||||
}
|
||||
|
||||
IReadOnlyList<CompactFontFormatBuiltInEncoding.Supplement> supplements = new List<CompactFontFormatBuiltInEncoding.Supplement>();
|
||||
IReadOnlyList<CompactFontFormatBuiltInEncoding.Supplement> supplements = [];
|
||||
if (HasSupplement(format))
|
||||
{
|
||||
supplements = ReadSupplement(data, stringIndex);
|
||||
@@ -54,7 +54,7 @@
|
||||
return new CompactFontFormatFormat0Encoding(values, supplements);
|
||||
}
|
||||
|
||||
private static CompactFontFormatFormat1Encoding ReadFormat1Encoding(CompactFontFormatData data, ICompactFontFormatCharset charset, IReadOnlyList<string> stringIndex, byte format)
|
||||
private static CompactFontFormatFormat1Encoding ReadFormat1Encoding(CompactFontFormatData data, ICompactFontFormatCharset charset, ReadOnlySpan<string> stringIndex, byte format)
|
||||
{
|
||||
var numberOfRanges = data.ReadCard8();
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
}
|
||||
|
||||
private static IReadOnlyList<CompactFontFormatBuiltInEncoding.Supplement> ReadSupplement(CompactFontFormatData dataInput,
|
||||
IReadOnlyList<string> stringIndex)
|
||||
ReadOnlySpan<string> stringIndex)
|
||||
{
|
||||
var numberOfSupplements = dataInput.ReadCard8();
|
||||
var supplements = new CompactFontFormatBuiltInEncoding.Supplement[numberOfSupplements];
|
||||
@@ -101,13 +101,13 @@
|
||||
return supplements;
|
||||
}
|
||||
|
||||
private static string ReadString(int index, IReadOnlyList<string> stringIndex)
|
||||
private static string ReadString(int index, ReadOnlySpan<string> stringIndex)
|
||||
{
|
||||
if (index >= 0 && index <= 390)
|
||||
{
|
||||
return CompactFontFormatStandardStrings.GetName(index);
|
||||
}
|
||||
if (index - 391 < stringIndex.Count)
|
||||
if (index - 391 < stringIndex.Length)
|
||||
{
|
||||
return stringIndex[index - 391];
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Charsets;
|
||||
using CharStrings;
|
||||
using Core;
|
||||
@@ -23,7 +22,7 @@
|
||||
this.privateDictionaryReader = privateDictionaryReader;
|
||||
}
|
||||
|
||||
public CompactFontFormatFont Parse(CompactFontFormatData data, string name, ReadOnlySpan<byte> topDictionaryIndex, IReadOnlyList<string> stringIndex,
|
||||
public CompactFontFormatFont Parse(CompactFontFormatData data, string name, ReadOnlySpan<byte> topDictionaryIndex, ReadOnlySpan<string> stringIndex,
|
||||
CompactFontFormatIndex globalSubroutineIndex)
|
||||
{
|
||||
var individualData = new CompactFontFormatData(topDictionaryIndex.ToArray());
|
||||
@@ -127,8 +126,10 @@
|
||||
return new CompactFontFormatFont(topDictionary, privateDictionary, charset, Union<Type1CharStrings, Type2CharStrings>.Two(charStrings), fontEncoding);
|
||||
}
|
||||
|
||||
private static ICompactFontFormatCharset ReadCharset(CompactFontFormatData data, CompactFontFormatTopLevelDictionary topDictionary,
|
||||
CompactFontFormatIndex charStringIndex, IReadOnlyList<string> stringIndex)
|
||||
private static ICompactFontFormatCharset ReadCharset(CompactFontFormatData data,
|
||||
CompactFontFormatTopLevelDictionary topDictionary,
|
||||
CompactFontFormatIndex charStringIndex,
|
||||
ReadOnlySpan<string> stringIndex)
|
||||
{
|
||||
data.Seek(topDictionary.CharSetOffset);
|
||||
|
||||
@@ -180,13 +181,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
private static string ReadString(int index, IReadOnlyList<string> stringIndex)
|
||||
private static string ReadString(int index, ReadOnlySpan<string> stringIndex)
|
||||
{
|
||||
if (index >= 0 && index <= 390)
|
||||
{
|
||||
return CompactFontFormatStandardStrings.GetName(index);
|
||||
}
|
||||
if (index - 391 < stringIndex.Count)
|
||||
if (index - 391 < stringIndex.Length)
|
||||
{
|
||||
return stringIndex[index - 391];
|
||||
}
|
||||
@@ -213,9 +214,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
private CompactFontFormatCidFont ReadCidFont(CompactFontFormatData data, CompactFontFormatTopLevelDictionary topLevelDictionary,
|
||||
private CompactFontFormatCidFont ReadCidFont(CompactFontFormatData data,
|
||||
CompactFontFormatTopLevelDictionary topLevelDictionary,
|
||||
int numberOfGlyphs,
|
||||
IReadOnlyList<string> stringIndex,
|
||||
ReadOnlySpan<string> stringIndex,
|
||||
CompactFontFormatPrivateDictionary privateDictionary,
|
||||
ICompactFontFormatCharset charset,
|
||||
CompactFontFormatIndex globalSubroutines,
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
{
|
||||
private readonly List<Operand> operands = new List<Operand>();
|
||||
|
||||
public abstract TResult Read(CompactFontFormatData data, IReadOnlyList<string> stringIndex);
|
||||
public abstract TResult Read(CompactFontFormatData data, ReadOnlySpan<string> stringIndex);
|
||||
|
||||
protected TBuilder ReadDictionary(TBuilder builder, CompactFontFormatData data, IReadOnlyList<string> stringIndex)
|
||||
protected TBuilder ReadDictionary(TBuilder builder, CompactFontFormatData data, ReadOnlySpan<string> stringIndex)
|
||||
{
|
||||
while (data.CanRead())
|
||||
{
|
||||
@@ -124,7 +124,7 @@
|
||||
exponentMissing = false;
|
||||
break;
|
||||
case 0xa:
|
||||
sb.Append(".");
|
||||
sb.Append('.');
|
||||
break;
|
||||
case 0xb:
|
||||
if (hasExponent)
|
||||
@@ -132,7 +132,7 @@
|
||||
// avoid duplicates
|
||||
break;
|
||||
}
|
||||
sb.Append("E");
|
||||
sb.Append('E');
|
||||
exponentMissing = true;
|
||||
hasExponent = true;
|
||||
break;
|
||||
@@ -149,7 +149,7 @@
|
||||
case 0xd:
|
||||
break;
|
||||
case 0xe:
|
||||
sb.Append("-");
|
||||
sb.Append('-');
|
||||
break;
|
||||
case 0xf:
|
||||
done = true;
|
||||
@@ -165,7 +165,7 @@
|
||||
// the exponent is missing, just append "0" to avoid an exception
|
||||
// not sure if 0 is the correct value, but it seems to fit
|
||||
// see PDFBOX-1522
|
||||
sb.Append("0");
|
||||
sb.Append('0');
|
||||
}
|
||||
|
||||
if (sb.Length == 0)
|
||||
@@ -176,9 +176,9 @@
|
||||
return hasExponent ? double.Parse(sb.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture) : double.Parse(sb.ToString(), CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
protected abstract void ApplyOperation(TBuilder builder, List<Operand> operands, OperandKey operandKey, IReadOnlyList<string> stringIndex);
|
||||
protected abstract void ApplyOperation(TBuilder builder, List<Operand> operands, OperandKey operandKey, ReadOnlySpan<string> stringIndex);
|
||||
|
||||
protected static string GetString(List<Operand> operands, IReadOnlyList<string> stringIndex)
|
||||
protected static string GetString(List<Operand> operands, ReadOnlySpan<string> stringIndex)
|
||||
{
|
||||
if (operands.Count == 0)
|
||||
{
|
||||
@@ -198,7 +198,7 @@
|
||||
}
|
||||
|
||||
var stringIndexIndex = index - 391;
|
||||
if (stringIndexIndex >= 0 && stringIndexIndex < stringIndex.Count)
|
||||
if (stringIndexIndex >= 0 && stringIndexIndex < stringIndex.Length)
|
||||
{
|
||||
return stringIndex[stringIndexIndex];
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
internal class CompactFontFormatPrivateDictionaryReader : CompactFontFormatDictionaryReader<CompactFontFormatPrivateDictionary, CompactFontFormatPrivateDictionary.Builder>
|
||||
{
|
||||
public override CompactFontFormatPrivateDictionary Read(CompactFontFormatData data, IReadOnlyList<string> stringIndex)
|
||||
public override CompactFontFormatPrivateDictionary Read(CompactFontFormatData data, ReadOnlySpan<string> stringIndex)
|
||||
{
|
||||
var builder = new CompactFontFormatPrivateDictionary.Builder();
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
protected override void ApplyOperation(CompactFontFormatPrivateDictionary.Builder dictionary, List<Operand> operands, OperandKey operandKey, IReadOnlyList<string> stringIndex)
|
||||
protected override void ApplyOperation(CompactFontFormatPrivateDictionary.Builder dictionary, List<Operand> operands, OperandKey operandKey, ReadOnlySpan<string> stringIndex)
|
||||
{
|
||||
switch (operandKey.Byte0)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
internal class CompactFontFormatTopLevelDictionaryReader : CompactFontFormatDictionaryReader<CompactFontFormatTopLevelDictionary, CompactFontFormatTopLevelDictionary>
|
||||
{
|
||||
public override CompactFontFormatTopLevelDictionary Read(CompactFontFormatData data, IReadOnlyList<string> stringIndex)
|
||||
public override CompactFontFormatTopLevelDictionary Read(CompactFontFormatData data, ReadOnlySpan<string> stringIndex)
|
||||
{
|
||||
var dictionary = new CompactFontFormatTopLevelDictionary();
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
protected override void ApplyOperation(CompactFontFormatTopLevelDictionary dictionary, List<Operand> operands, OperandKey key, IReadOnlyList<string> stringIndex)
|
||||
protected override void ApplyOperation(CompactFontFormatTopLevelDictionary dictionary, List<Operand> operands, OperandKey key, ReadOnlySpan<string> stringIndex)
|
||||
{
|
||||
switch (key.Byte0)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
/// <summary>
|
||||
/// Created by combining a base encoding with the differences.
|
||||
/// </summary>
|
||||
public class DifferenceBasedEncoding : Encoding
|
||||
public sealed class DifferenceBasedEncoding : Encoding
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override string EncodingName { get; } = "Difference Encoding";
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
namespace UglyToad.PdfPig.Fonts.Encodings
|
||||
{
|
||||
using Core;
|
||||
|
||||
internal class MacExpertEncoding : Encoding
|
||||
internal sealed class MacExpertEncoding : Encoding
|
||||
{
|
||||
/// <summary>
|
||||
/// Table of octal character codes and their corresponding names.
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
namespace UglyToad.PdfPig.Fonts.Encodings
|
||||
{
|
||||
using Core;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Similar to the <see cref="T:UglyToad.PdfPig.Fonts.Encodings.MacRomanEncoding" /> with 15 additional entries.
|
||||
/// </summary>
|
||||
public class MacOsRomanEncoding : MacRomanEncoding
|
||||
public sealed class MacOsRomanEncoding : MacRomanEncoding
|
||||
{
|
||||
private static readonly (int, string)[] EncodingTable =
|
||||
{
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
namespace UglyToad.PdfPig.Fonts.Encodings
|
||||
{
|
||||
using Core;
|
||||
using System.Diagnostics;
|
||||
|
||||
{
|
||||
/// <summary>
|
||||
/// The Mac Roman encoding.
|
||||
/// </summary>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// The standard PDF encoding.
|
||||
/// </summary>
|
||||
public class StandardEncoding : Encoding
|
||||
public sealed class StandardEncoding : Encoding
|
||||
{
|
||||
private static readonly (int, string)[] EncodingTable =
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// Symbol encoding.
|
||||
/// </summary>
|
||||
public class SymbolEncoding : Encoding
|
||||
public sealed class SymbolEncoding : Encoding
|
||||
{
|
||||
/// <summary>
|
||||
/// EncodingTable for Symbol
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// Windows ANSI encoding.
|
||||
/// </summary>
|
||||
public class WinAnsiEncoding : Encoding
|
||||
public sealed class WinAnsiEncoding : Encoding
|
||||
{
|
||||
/// <summary>
|
||||
/// The encoding table is taken from the Appendix of the specification.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// Zapf Dingbats encoding.
|
||||
/// </summary>
|
||||
public class ZapfDingbatsEncoding : Encoding
|
||||
public sealed class ZapfDingbatsEncoding : Encoding
|
||||
{
|
||||
/// <summary>
|
||||
/// EncodingTable for ZapfDingbats
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Encodings;
|
||||
using UglyToad.PdfPig.Util;
|
||||
|
||||
/// <summary>
|
||||
/// A list which maps PostScript glyph names to unicode values.
|
||||
@@ -117,7 +118,7 @@
|
||||
var foundUnicode = true;
|
||||
for (int chPos = 3; chPos + 4 <= nameLength; chPos += 4)
|
||||
{
|
||||
if (!int.TryParse(name.Substring(chPos, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var codePoint))
|
||||
if (!int.TryParse(name.AsSpanOrSubstring(chPos, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var codePoint))
|
||||
{
|
||||
foundUnicode = false;
|
||||
break;
|
||||
@@ -138,10 +139,10 @@
|
||||
|
||||
unicode = uniStr.ToString();
|
||||
}
|
||||
else if (name.StartsWith("u") && name.Length == 5)
|
||||
else if (name.StartsWith("u", StringComparison.Ordinal) && name.Length == 5)
|
||||
{
|
||||
// test for an alternate Unicode name representation uXXXX
|
||||
var codePoint = int.Parse(name.Substring(1), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
||||
var codePoint = int.Parse(name.AsSpanOrSubstring(1), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
||||
|
||||
if (codePoint > 0xD7FF && codePoint < 0xE000)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using Util;
|
||||
|
||||
internal class GlyphListFactory
|
||||
{
|
||||
@@ -34,6 +35,8 @@
|
||||
return ReadInternal(stream);
|
||||
}
|
||||
|
||||
private static readonly char[] Semicolon = [';'];
|
||||
|
||||
private static GlyphList ReadInternal(Stream stream, int? defaultDictionaryCapacity = 0)
|
||||
{
|
||||
if (stream == null)
|
||||
@@ -41,8 +44,8 @@
|
||||
throw new ArgumentNullException(nameof(stream));
|
||||
}
|
||||
|
||||
var result = defaultDictionaryCapacity.HasValue ? new Dictionary<string, string>(defaultDictionaryCapacity.Value)
|
||||
: new Dictionary<string, string>();
|
||||
var result = defaultDictionaryCapacity.HasValue ? new Dictionary<string, string>(defaultDictionaryCapacity.Value) : [];
|
||||
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
@@ -60,7 +63,7 @@
|
||||
continue;
|
||||
}
|
||||
|
||||
var parts = line.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var parts = line.Split(Semicolon, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
@@ -70,13 +73,16 @@
|
||||
|
||||
var key = parts[0];
|
||||
|
||||
var values = parts[1].Split(' ');
|
||||
|
||||
var valueReader = new StringSplitter(parts[1].AsSpan(), ' ');
|
||||
var value = string.Empty;
|
||||
foreach (var s in values)
|
||||
{
|
||||
var code = int.Parse(s, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
||||
|
||||
while (valueReader.TryRead(out var s))
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
var code = int.Parse(s, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
||||
#else
|
||||
var code = int.Parse(s.ToString(), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
||||
#endif
|
||||
value += char.ConvertFromUtf32(code);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
public static IGlyphDescription Empty(PdfRectangle bounds)
|
||||
{
|
||||
return new Glyph(true, new byte[0], new ushort[0], new GlyphPoint[0], bounds);
|
||||
return new Glyph(true, [], [], [], bounds);
|
||||
}
|
||||
|
||||
public IGlyphDescription DeepClone()
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
return new CMapTable(tableVersionNumber, header, tables);
|
||||
}
|
||||
|
||||
private class SubTableHeaderEntry
|
||||
private readonly struct SubTableHeaderEntry
|
||||
{
|
||||
public TrueTypeCMapPlatform PlatformId { get; }
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
var compositeIndicesToReplace = new List<(uint offset, ushort newIndex)>();
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
using (var writer = new ArrayPoolBufferWriter<byte>())
|
||||
{
|
||||
for (var i = 0; i < glyphsToCopy.Count; i++)
|
||||
{
|
||||
@@ -102,7 +102,7 @@
|
||||
}
|
||||
|
||||
// Record the glyph location.
|
||||
glyphLocations.Add((uint)stream.Position);
|
||||
glyphLocations.Add((uint)writer.WrittenCount);
|
||||
|
||||
var advanceWidth = advanceWidthTable.HorizontalMetrics[glyphsToCopyOriginalIndex[i]];
|
||||
advanceWidths.Add(advanceWidth);
|
||||
@@ -123,19 +123,19 @@
|
||||
glyphBytes[offset] = (byte)(newIndex >> 8);
|
||||
glyphBytes[offset + 1] = (byte)newIndex;
|
||||
}
|
||||
|
||||
stream.Write(glyphBytes, 0, glyphBytes.Length);
|
||||
|
||||
writer.Write(glyphBytes);
|
||||
|
||||
// Each glyph description must start at a 4 byte boundary.
|
||||
var remainder = glyphBytes.Length % 4;
|
||||
var bytesToPad = remainder == 0 ? 0 : 4 - remainder;
|
||||
for (var j = 0; j < bytesToPad; j++)
|
||||
{
|
||||
stream.WriteByte(0);
|
||||
writer.Write(0);
|
||||
}
|
||||
}
|
||||
|
||||
var output = stream.ToArray();
|
||||
var output = writer.WrittenSpan.ToArray();
|
||||
|
||||
glyphLocations.Add((uint)output.Length);
|
||||
var offsets = glyphLocations.ToArray();
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
switch (c1)
|
||||
{
|
||||
case 'n':
|
||||
case 'r': stringBuffer.Append("\n"); break;
|
||||
case 'r': stringBuffer.Append('\n'); break;
|
||||
case 't': stringBuffer.Append('\t'); break;
|
||||
case 'b': stringBuffer.Append('\b'); break;
|
||||
case 'f': stringBuffer.Append('\f'); break;
|
||||
@@ -180,14 +180,14 @@
|
||||
// octal \ddd
|
||||
if (char.IsDigit(c1))
|
||||
{
|
||||
var rawOctal = new string(new[] { c1, GetNext(), GetNext() });
|
||||
var rawOctal = new string([c1, GetNext(), GetNext()]);
|
||||
var code = Convert.ToInt32(rawOctal, 8);
|
||||
stringBuffer.Append((char)code);
|
||||
}
|
||||
break;
|
||||
case '\r':
|
||||
case '\n':
|
||||
stringBuffer.Append("\n");
|
||||
stringBuffer.Append('\n');
|
||||
break;
|
||||
default:
|
||||
stringBuffer.Append(c);
|
||||
|
||||
28
src/UglyToad.PdfPig.Fonts/Util/StringExtensions.cs
Normal file
28
src/UglyToad.PdfPig.Fonts/Util/StringExtensions.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace UglyToad.PdfPig.Util;
|
||||
|
||||
internal static class StringExtensions
|
||||
{
|
||||
#if NET
|
||||
public static ReadOnlySpan<char> AsSpanOrSubstring(this string text, int start)
|
||||
{
|
||||
return text.AsSpan(start);
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<char> AsSpanOrSubstring(this string text, int start, int length)
|
||||
{
|
||||
return text.AsSpan(start, length);
|
||||
}
|
||||
#else
|
||||
public static string AsSpanOrSubstring(this string text, int start)
|
||||
{
|
||||
return text.Substring(start);
|
||||
}
|
||||
|
||||
public static string AsSpanOrSubstring(this string text, int start, int length)
|
||||
{
|
||||
return text.Substring(start, length);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
70
src/UglyToad.PdfPig.Fonts/Util/StringSplitter.cs
Normal file
70
src/UglyToad.PdfPig.Fonts/Util/StringSplitter.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace UglyToad.PdfPig.Util;
|
||||
|
||||
internal ref struct StringSplitter(ReadOnlySpan<char> text, char separator)
|
||||
{
|
||||
private readonly ReadOnlySpan<char> text = text;
|
||||
private readonly char separator = separator;
|
||||
private int position = 0;
|
||||
|
||||
public bool TryRead(out ReadOnlySpan<char> result)
|
||||
{
|
||||
if (IsEof)
|
||||
{
|
||||
result = default;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int separatorIndex = text.Slice(position).IndexOf(separator);
|
||||
|
||||
if (separatorIndex > -1)
|
||||
{
|
||||
result = text.Slice(position, separatorIndex);
|
||||
|
||||
position += separatorIndex + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = text.Slice(position);
|
||||
|
||||
position = text.Length;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public ReadOnlySpan<char> Read()
|
||||
{
|
||||
if (IsEof)
|
||||
{
|
||||
ThrowEof();
|
||||
}
|
||||
|
||||
int start = position;
|
||||
|
||||
int separatorIndex = text.Slice(position).IndexOf(separator);
|
||||
|
||||
if (separatorIndex > -1)
|
||||
{
|
||||
position += separatorIndex + 1;
|
||||
|
||||
return text.Slice(start, separatorIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
position = text.Length;
|
||||
|
||||
return text.Slice(start);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly bool IsEof => position == text.Length;
|
||||
|
||||
private static void ThrowEof()
|
||||
{
|
||||
throw new EndOfStreamException();
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -5,6 +5,22 @@
|
||||
|
||||
public class EncodingsTests
|
||||
{
|
||||
[Fact]
|
||||
public void Windows1252Encoding()
|
||||
{
|
||||
string path = IntegrationHelpers.GetDocumentPath("GHOSTSCRIPT-698363-0.pdf");
|
||||
using (var document = PdfDocument.Open(path))
|
||||
{
|
||||
var page = document.GetPage(1);
|
||||
string actual = string.Concat(page.Letters.Select(l => l.Value));
|
||||
|
||||
// The expected string value is just here to make sure we have the same results across net versions.
|
||||
// Feel free to correct/update it if chars are not actually correct.
|
||||
string expected = "ҘҹЧѥЧКጹѝঐܮ̂ҥ҇ҁӃ࿋\u0c0dҀғҊ˺෨ཌආр෨ཌ̂ҘҹЧѥЧКጹѝঐܮ̂ҥ҇ҁӃ࿋\u0c0dҀғҊ˺෨ཌආр෨ཌ̂ݰႺംࢥ༢࣭\u089aѽ̔ҫһҐ̔ݰႺംࢥ༢࣭\u089aѽ̔ҫһҐ̔";
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Issue688()
|
||||
{
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
public class IntegrationDocumentTests
|
||||
{
|
||||
private static readonly Lazy<string> DocumentFolder = new Lazy<string>(() => Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..", "..", "Integration", "Documents")));
|
||||
private static readonly HashSet<string> _documentsToIgnore = new HashSet<string>()
|
||||
{
|
||||
"issue_671.pdf"
|
||||
};
|
||||
private static readonly HashSet<string> _documentsToIgnore =
|
||||
[
|
||||
"issue_671.pdf",
|
||||
"GHOSTSCRIPT-698363-0.pdf"
|
||||
];
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(GetAllDocuments))]
|
||||
|
||||
@@ -148,9 +148,9 @@
|
||||
int code,
|
||||
string unicode,
|
||||
long currentOffset,
|
||||
TransformationMatrix renderingMatrix,
|
||||
TransformationMatrix textMatrix,
|
||||
TransformationMatrix transformationMatrix,
|
||||
in TransformationMatrix renderingMatrix,
|
||||
in TransformationMatrix textMatrix,
|
||||
in TransformationMatrix transformationMatrix,
|
||||
CharacterBoundingBox characterBoundingBox)
|
||||
{
|
||||
_letters.Add(unicode);
|
||||
|
||||
@@ -69,9 +69,9 @@
|
||||
int code,
|
||||
string unicode,
|
||||
long currentOffset,
|
||||
TransformationMatrix renderingMatrix,
|
||||
TransformationMatrix textMatrix,
|
||||
TransformationMatrix transformationMatrix,
|
||||
in TransformationMatrix renderingMatrix,
|
||||
in TransformationMatrix textMatrix,
|
||||
in TransformationMatrix transformationMatrix,
|
||||
CharacterBoundingBox characterBoundingBox)
|
||||
{
|
||||
if (textRenderingMode == TextRenderingMode.Neither)
|
||||
@@ -98,9 +98,9 @@
|
||||
IColor strokingColor,
|
||||
IColor nonStrokingColor,
|
||||
TextRenderingMode textRenderingMode,
|
||||
TransformationMatrix renderingMatrix,
|
||||
TransformationMatrix textMatrix,
|
||||
TransformationMatrix transformationMatrix)
|
||||
in TransformationMatrix renderingMatrix,
|
||||
in TransformationMatrix textMatrix,
|
||||
in TransformationMatrix transformationMatrix)
|
||||
{
|
||||
var transformMatrix = renderingMatrix.ToSKMatrix()
|
||||
.PostConcat(textMatrix.ToSKMatrix())
|
||||
|
||||
@@ -5,9 +5,18 @@
|
||||
using Core;
|
||||
using Tokens;
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
using System.Text.Unicode;
|
||||
#endif
|
||||
|
||||
internal class NameTokenizer : ITokenizer
|
||||
{
|
||||
private static readonly ListPool<byte> ListPool = new ListPool<byte>(10);
|
||||
static NameTokenizer()
|
||||
{
|
||||
#if NET6_0_OR_GREATER
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool ReadsNextByte { get; } = true;
|
||||
|
||||
@@ -20,11 +29,11 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
var bytes = ListPool.Borrow();
|
||||
using var bytes = new ArrayPoolBufferWriter<byte>();
|
||||
|
||||
bool escapeActive = false;
|
||||
int postEscapeRead = 0;
|
||||
var escapedChars = new char[2];
|
||||
Span<char> escapedChars = stackalloc char[2];
|
||||
|
||||
while (inputBytes.MoveNext())
|
||||
{
|
||||
@@ -43,10 +52,12 @@
|
||||
|
||||
if (postEscapeRead == 2)
|
||||
{
|
||||
var hex = new string(escapedChars);
|
||||
int high = escapedChars[0] <= '9' ? escapedChars[0] - '0' : char.ToUpper(escapedChars[0]) - 'A' + 10;
|
||||
int low = escapedChars[1] <= '9' ? escapedChars[1] - '0' : char.ToUpper(escapedChars[1]) - 'A' + 10;
|
||||
|
||||
var characterToWrite = (byte)Convert.ToInt32(hex, 16);
|
||||
bytes.Add(characterToWrite);
|
||||
byte characterToWrite = (byte)(high * 16 + low);
|
||||
|
||||
bytes.Write(characterToWrite);
|
||||
|
||||
escapeActive = false;
|
||||
postEscapeRead = 0;
|
||||
@@ -54,11 +65,11 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes.Add((byte)'#');
|
||||
bytes.Write((byte)'#');
|
||||
|
||||
if (postEscapeRead == 1)
|
||||
{
|
||||
bytes.Add((byte)escapedChars[0]);
|
||||
bytes.Write((byte)escapedChars[0]);
|
||||
}
|
||||
|
||||
if (ReadHelper.IsEndOfName(b))
|
||||
@@ -75,7 +86,7 @@
|
||||
continue;
|
||||
}
|
||||
|
||||
bytes.Add(b);
|
||||
bytes.Write(b);
|
||||
escapeActive = false;
|
||||
postEscapeRead = 0;
|
||||
}
|
||||
@@ -87,18 +98,22 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes.Add(b);
|
||||
bytes.Write(b);
|
||||
}
|
||||
}
|
||||
|
||||
var byteArray = bytes.ToArray();
|
||||
#if NET8_0_OR_GREATER
|
||||
var byteArray = bytes.WrittenSpan;
|
||||
bool isValidUtf8 = Utf8.IsValid(byteArray);
|
||||
#else
|
||||
var byteArray = bytes.WrittenSpan.ToArray();
|
||||
bool isValidUtf8 = ReadHelper.IsValidUtf8(byteArray);
|
||||
#endif
|
||||
|
||||
ListPool.Return(bytes);
|
||||
|
||||
var str = ReadHelper.IsValidUtf8(byteArray)
|
||||
var str = isValidUtf8
|
||||
? Encoding.UTF8.GetString(byteArray)
|
||||
: Encoding.GetEncoding("windows-1252").GetString(byteArray);
|
||||
|
||||
|
||||
token = NameToken.Create(str);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
CropBox cropBox,
|
||||
UserSpaceUnit userSpaceUnit,
|
||||
PageRotationDegrees rotation,
|
||||
TransformationMatrix initialMatrix,
|
||||
in TransformationMatrix initialMatrix,
|
||||
ReadOnlyMemory<byte> contentBytes)
|
||||
{
|
||||
IReadOnlyList<IGraphicsStateOperation> operations;
|
||||
@@ -315,7 +315,7 @@
|
||||
/// <param name="transformationMatrix"></param>
|
||||
/// <param name="mediaBox"></param>
|
||||
/// <param name="cropBox"></param>
|
||||
protected static void ApplyTransformNormalise(TransformationMatrix transformationMatrix, ref MediaBox mediaBox, ref CropBox cropBox)
|
||||
protected static void ApplyTransformNormalise(in TransformationMatrix transformationMatrix, ref MediaBox mediaBox, ref CropBox cropBox)
|
||||
{
|
||||
if (transformationMatrix != TransformationMatrix.Identity)
|
||||
{
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
aes.Key = finalKey;
|
||||
aes.IV = iv;
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
return aes.DecryptCbc(data.AsSpan(iv.Length), iv, PaddingMode.PKCS7);
|
||||
#else
|
||||
var buffer = new byte[256];
|
||||
|
||||
using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
|
||||
@@ -49,6 +52,7 @@
|
||||
return output.ToArray();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
CropBox cropBox,
|
||||
UserSpaceUnit userSpaceUnit,
|
||||
PageRotationDegrees rotation,
|
||||
TransformationMatrix initialMatrix,
|
||||
in TransformationMatrix initialMatrix,
|
||||
ParsingOptions parsingOptions)
|
||||
{
|
||||
this.PageNumber = pageNumber;
|
||||
@@ -325,9 +325,9 @@
|
||||
int code,
|
||||
string unicode,
|
||||
long currentOffset,
|
||||
TransformationMatrix renderingMatrix,
|
||||
TransformationMatrix textMatrix,
|
||||
TransformationMatrix transformationMatrix,
|
||||
in TransformationMatrix renderingMatrix,
|
||||
in TransformationMatrix textMatrix,
|
||||
in TransformationMatrix transformationMatrix,
|
||||
CharacterBoundingBox characterBoundingBox);
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -95,9 +95,9 @@ namespace UglyToad.PdfPig.Graphics
|
||||
int code,
|
||||
string unicode,
|
||||
long currentOffset,
|
||||
TransformationMatrix renderingMatrix,
|
||||
TransformationMatrix textMatrix,
|
||||
TransformationMatrix transformationMatrix,
|
||||
in TransformationMatrix renderingMatrix,
|
||||
in TransformationMatrix textMatrix,
|
||||
in TransformationMatrix transformationMatrix,
|
||||
CharacterBoundingBox characterBoundingBox)
|
||||
{
|
||||
var transformedGlyphBounds = PerformantRectangleTransformer
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
/// </summary>
|
||||
public ReadOnlyMemory<byte> Bytes { get; internal set; }
|
||||
|
||||
internal InlineImage CreateInlineImage(TransformationMatrix transformationMatrix,
|
||||
internal InlineImage CreateInlineImage(
|
||||
in TransformationMatrix transformationMatrix,
|
||||
ILookupFilterProvider filterProvider,
|
||||
IPdfTokenScanner tokenScanner,
|
||||
RenderingIntent defaultRenderingIntent,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
namespace UglyToad.PdfPig.Graphics.Operations
|
||||
{
|
||||
using PdfPig.Core;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using UglyToad.PdfPig.Util;
|
||||
using PdfPig.Core;
|
||||
using Util;
|
||||
|
||||
internal static class OperationWriteHelper
|
||||
{
|
||||
@@ -23,9 +23,15 @@
|
||||
|
||||
public static void WriteHex(this Stream stream, ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
var text = Hex.GetString(bytes);
|
||||
Span<byte> hex = bytes.Length <= 64
|
||||
? stackalloc byte[bytes.Length * 2]
|
||||
: new byte[bytes.Length * 2];
|
||||
|
||||
stream.WriteText($"<{text}>");
|
||||
Hex.GetUtf8Chars(bytes, hex);
|
||||
|
||||
stream.WriteByte((byte)'<');
|
||||
stream.Write(hex);
|
||||
stream.WriteByte((byte)'>');
|
||||
}
|
||||
|
||||
public static void WriteWhiteSpace(this Stream stream)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
/// <summary>
|
||||
/// Transform the rectangle using the matrices.
|
||||
/// </summary>
|
||||
public static PdfRectangle Transform(TransformationMatrix first, TransformationMatrix second, TransformationMatrix third, PdfRectangle rectangle)
|
||||
public static PdfRectangle Transform(in TransformationMatrix first, in TransformationMatrix second, in TransformationMatrix third, PdfRectangle rectangle)
|
||||
{
|
||||
var tl = rectangle.TopLeft;
|
||||
var tr = rectangle.TopRight;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace UglyToad.PdfPig.Util
|
||||
{
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
/**
|
||||
* Utility functions for hex encoding.
|
||||
@@ -17,7 +16,18 @@
|
||||
*
|
||||
*/
|
||||
private static readonly char[] HexChars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
|
||||
|
||||
|
||||
public static void GetUtf8Chars(ReadOnlySpan<byte> bytes, Span<byte> utf8Chars)
|
||||
{
|
||||
int position = 0;
|
||||
|
||||
foreach (var b in bytes)
|
||||
{
|
||||
utf8Chars[position++] = (byte)HexChars[GetHighNibble(b)];
|
||||
utf8Chars[position++] = (byte)HexChars[GetLowNibble(b)];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hex string for the given byte array.
|
||||
/// </summary>
|
||||
@@ -26,14 +36,16 @@
|
||||
#if NET6_0_OR_GREATER
|
||||
return Convert.ToHexString(bytes);
|
||||
#else
|
||||
var stringBuilder = new StringBuilder(bytes.Length * 2);
|
||||
var chars = new char[bytes.Length * 2];
|
||||
int position = 0;
|
||||
|
||||
foreach (var b in bytes)
|
||||
{
|
||||
stringBuilder.Append(HexChars[GetHighNibble(b)]).Append(HexChars[GetLowNibble(b)]);
|
||||
chars[position++] = HexChars[GetHighNibble(b)];
|
||||
chars[position++] = HexChars[GetLowNibble(b)];
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
return new string(chars);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
}
|
||||
|
||||
private static PatternColor CreateTilingPattern(StreamToken patternStream, DictionaryToken patternExtGState,
|
||||
TransformationMatrix matrix, IPdfTokenScanner scanner)
|
||||
in TransformationMatrix matrix, IPdfTokenScanner scanner)
|
||||
{
|
||||
if (!patternStream.StreamDictionary.TryGet<NumericToken>(NameToken.PaintType, scanner, out var paintTypeToken))
|
||||
{
|
||||
@@ -113,7 +113,7 @@
|
||||
}
|
||||
|
||||
private static PatternColor CreateShadingPattern(DictionaryToken patternDictionary, DictionaryToken? patternExtGState,
|
||||
TransformationMatrix matrix, IPdfTokenScanner scanner, IResourceStore resourceStore,
|
||||
in TransformationMatrix matrix, IPdfTokenScanner scanner, IResourceStore resourceStore,
|
||||
ILookupFilterProvider filterProvider)
|
||||
{
|
||||
IToken shadingToken = patternDictionary.Data[NameToken.Shading];
|
||||
|
||||
@@ -989,7 +989,7 @@
|
||||
return this;
|
||||
}
|
||||
|
||||
private List<Letter> DrawLetters(NameToken? name, string text, IWritingFont font, TransformationMatrix fontMatrix, double fontSize, TransformationMatrix textMatrix)
|
||||
private List<Letter> DrawLetters(NameToken? name, string text, IWritingFont font, in TransformationMatrix fontMatrix, double fontSize, TransformationMatrix textMatrix)
|
||||
{
|
||||
var horizontalScaling = 1;
|
||||
var rise = 0;
|
||||
|
||||
Reference in New Issue
Block a user