Files
PdfPig/src/UglyToad.PdfPig/Util/PatternParser.cs
Jason Nelson 1ef2e127a6 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
2024-04-18 19:58:40 +01:00

137 lines
6.4 KiB
C#

namespace UglyToad.PdfPig.Util
{
using System;
using System.Linq;
using UglyToad.PdfPig.Content;
using UglyToad.PdfPig.Core;
using UglyToad.PdfPig.Filters;
using UglyToad.PdfPig.Graphics.Colors;
using UglyToad.PdfPig.Parser.Parts;
using UglyToad.PdfPig.Tokenization.Scanner;
using UglyToad.PdfPig.Tokens;
internal static class PatternParser
{
public static PatternColor Create(IToken pattern, IPdfTokenScanner scanner, IResourceStore resourceStore, ILookupFilterProvider filterProvider)
{
DictionaryToken patternDictionary;
StreamToken? patternStream = null;
if (DirectObjectFinder.TryGet(pattern, scanner, out StreamToken? fs))
{
patternDictionary = fs.StreamDictionary;
patternStream = new StreamToken(fs.StreamDictionary, fs.Decode(filterProvider, scanner));
}
else if (DirectObjectFinder.TryGet(pattern, scanner, out DictionaryToken? fd))
{
patternDictionary = fd;
}
else
{
throw new PdfDocumentFormatException($"Invalid Pattern token encountered in page resource dictionary: {pattern}.");
}
if (!patternDictionary.Data.ContainsKey(NameToken.PatternType))
{
throw new Exception("TODO");
}
int patternType = ((NumericToken)patternDictionary.Data[NameToken.PatternType]).Int;
TransformationMatrix matrix;
if ((patternDictionary.Data.ContainsKey(NameToken.Matrix) &&
DirectObjectFinder.TryGet(patternDictionary.Data[NameToken.Matrix], scanner, out ArrayToken? patternMatrix)))
{
matrix = TransformationMatrix.FromArray(patternMatrix.Data.OfType<NumericToken>().Select(n => n.Data).ToArray());
}
else
{
// optional - Default value: the identity matrix [1 0 0 1 0 0]
matrix = TransformationMatrix.FromArray([1, 0, 0, 1, 0, 0]);
}
DictionaryToken? patternExtGState = null;
if (!(patternDictionary.Data.ContainsKey(NameToken.ExtGState) &&
DirectObjectFinder.TryGet(patternDictionary.Data[NameToken.ExtGState], scanner, out patternExtGState)))
{
// optional
}
return patternType switch {
// Tiling
1 => CreateTilingPattern(patternStream!, patternExtGState!, matrix, scanner),
// Shading
2 => CreateShadingPattern(patternDictionary, patternExtGState, matrix, scanner, resourceStore, filterProvider),
_ => throw new PdfDocumentFormatException($"Invalid Pattern type encountered in page resource dictionary: {patternType}.")
};
}
private static PatternColor CreateTilingPattern(StreamToken patternStream, DictionaryToken patternExtGState,
in TransformationMatrix matrix, IPdfTokenScanner scanner)
{
if (!patternStream.StreamDictionary.TryGet<NumericToken>(NameToken.PaintType, scanner, out var paintTypeToken))
{
// 1 - Coloured tiling pattern
// 2 - Uncoloured tiling pattern
throw new PdfDocumentFormatException($"Invalid Pattern token encountered.");
}
// Coloured Tiling Patterns - This type of pattern is identified by a pattern type of 1 and a paint type of 1 in the pattern dictionary.
// Uncoloured Tiling Patterns - This type of pattern shall be identified by a pattern type of 1 and a paint type of 2 in the pattern dictionary.
if (!patternStream.StreamDictionary.TryGet<NumericToken>(NameToken.TilingType, scanner, out var tilingTypeToken))
{
// 1 - Constant spacing
// 2 - No distortion
// 3 - Constant spacing and faster tiling
throw new PdfDocumentFormatException($"Invalid Pattern token encountered.");
}
if (!patternStream.StreamDictionary.TryGet<ArrayToken>(NameToken.Bbox, scanner, out var bboxToken))
{
throw new PdfDocumentFormatException($"Invalid Pattern token encountered.");
}
if (!patternStream.StreamDictionary.TryGet<NumericToken>(NameToken.XStep, scanner, out var xStepToken))
{
throw new PdfDocumentFormatException($"Invalid Pattern token encountered.");
}
if (!patternStream.StreamDictionary.TryGet<NumericToken>(NameToken.YStep, scanner, out var yStepToken))
{
throw new PdfDocumentFormatException($"Invalid Pattern token encountered.");
}
if (!patternStream.StreamDictionary.TryGet<DictionaryToken>(NameToken.Resources, scanner, out var resourcesToken))
{
throw new PdfDocumentFormatException($"Invalid Pattern token encountered.");
}
return new TilingPatternColor(matrix, patternExtGState, patternStream, (PatternPaintType)paintTypeToken.Int,
(PatternTilingType)tilingTypeToken.Int, bboxToken.ToRectangle(scanner), xStepToken.Double, yStepToken.Double, resourcesToken,
patternStream.Data);
}
private static PatternColor CreateShadingPattern(DictionaryToken patternDictionary, DictionaryToken? patternExtGState,
in TransformationMatrix matrix, IPdfTokenScanner scanner, IResourceStore resourceStore,
ILookupFilterProvider filterProvider)
{
IToken shadingToken = patternDictionary.Data[NameToken.Shading];
Shading patternShading;
if (DirectObjectFinder.TryGet(shadingToken, scanner, out DictionaryToken? patternShadingDictionary))
{
patternShading = ShadingParser.Create(patternShadingDictionary, scanner, resourceStore, filterProvider);
}
else if (DirectObjectFinder.TryGet(shadingToken, scanner, out StreamToken? patternShadingStream))
{
patternShading = ShadingParser.Create(patternShadingStream, scanner, resourceStore, filterProvider);
}
else
{
throw new ArgumentException("TODO");
}
return new ShadingPatternColor(matrix, patternExtGState!, patternDictionary, patternShading);
}
}
}