rename contentstreamdictionary to pdfdictionary. add initial structure for cid fonts

This commit is contained in:
Eliot Jones
2017-12-03 15:01:17 +00:00
parent b4cddbec7b
commit 644fd3e19d
60 changed files with 1063 additions and 935 deletions

View File

@@ -22,7 +22,7 @@
[Fact]
public void NegativeIndex_Throws()
{
Action action = () => resolver.GetFilterParameters(new ContentStreamDictionary(), -1);
Action action = () => resolver.GetFilterParameters(new PdfDictionary(), -1);
Assert.Throws<ArgumentOutOfRangeException>(action);
}
@@ -30,7 +30,7 @@
[Fact]
public void EmptyDictionary_ReturnsEmptyDictionary()
{
var result = resolver.GetFilterParameters(new ContentStreamDictionary(), 0);
var result = resolver.GetFilterParameters(new PdfDictionary(), 0);
Assert.Empty(result);
}

View File

@@ -108,11 +108,11 @@
var streamBytes = BytesBetween(streamPosition.end + 1, endStreamPosition.start - 1, bytes);
var paramsDict = new ContentStreamDictionary();
var paramsDict = new PdfDictionary();
paramsDict.Set(CosName.PREDICTOR, new CosFloat("12"));
paramsDict.Set(CosName.COLUMNS, new CosFloat("4"));
var dict = new ContentStreamDictionary();
var dict = new PdfDictionary();
dict.Set(CosName.FILTER, CosName.FLATE_DECODE);
dict.Set(CosName.DECODE_PARMS, paramsDict);
var filter = new FlateFilter(new DecodeParameterResolver(null), new PngPredictor(), null);

View File

@@ -17,8 +17,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="FakeItEasy" Version="4.1.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="FakeItEasy" Version="4.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.extensibility.execution" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />

View File

@@ -6,9 +6,9 @@
public class Catalog
{
private readonly ContentStreamDictionary catalogDictionary;
private readonly PdfDictionary catalogDictionary;
internal Catalog(ContentStreamDictionary catalogDictionary)
internal Catalog(PdfDictionary catalogDictionary)
{
this.catalogDictionary = catalogDictionary ?? throw new ArgumentNullException(nameof(catalogDictionary));
}

View File

@@ -15,7 +15,7 @@
public class Page
{
private readonly ParsingArguments parsingArguments;
private readonly ContentStreamDictionary dictionary;
private readonly PdfDictionary dictionary;
/// <summary>
/// The 1 indexed page number.
@@ -28,7 +28,7 @@
public IReadOnlyList<string> Text => Content?.Text ?? new string[0];
internal Page(int number, ContentStreamDictionary dictionary, PageTreeMembers pageTreeMembers, ParsingArguments parsingArguments)
internal Page(int number, PdfDictionary dictionary, PageTreeMembers pageTreeMembers, ParsingArguments parsingArguments)
{
if (number <= 0)
{
@@ -73,7 +73,7 @@
}
}
if (dictionary.GetItemOrDefault(CosName.RESOURCES) is ContentStreamDictionary resource)
if (dictionary.GetItemOrDefault(CosName.RESOURCES) is PdfDictionary resource)
{
parsingArguments.CachingProviders.ResourceContainer.LoadResourceDictionary(resource, parsingArguments);
}

View File

@@ -14,8 +14,8 @@
{
private readonly Catalog catalog;
private readonly ParsingArguments arguments;
private readonly ContentStreamDictionary rootPageDictionary;
private readonly Dictionary<int, ContentStreamDictionary> locatedPages = new Dictionary<int, ContentStreamDictionary>();
private readonly PdfDictionary rootPageDictionary;
private readonly Dictionary<int, PdfDictionary> locatedPages = new Dictionary<int, PdfDictionary>();
public int Count { get; }
@@ -40,7 +40,7 @@
var pageObject = arguments.Container.Get<DynamicParser>().Parse(arguments, pages, false);
if (!(pageObject is ContentStreamDictionary catalogPageDictionary))
if (!(pageObject is PdfDictionary catalogPageDictionary))
{
throw new InvalidOperationException("Could not find the root pages object: " + pages);
}
@@ -58,7 +58,7 @@
public Page GetPage(int pageNumber)
{
if (locatedPages.TryGetValue(pageNumber, out ContentStreamDictionary targetPageDictionary))
if (locatedPages.TryGetValue(pageNumber, out PdfDictionary targetPageDictionary))
{
return new Page(pageNumber, targetPageDictionary, new PageTreeMembers(), arguments);
}
@@ -91,7 +91,7 @@
return pages[pages.Count - 1] + 1;
}
public bool FindPage(ContentStreamDictionary currentPageDictionary, int soughtPageNumber, List<int> pageNumbersObserved)
public bool FindPage(PdfDictionary currentPageDictionary, int soughtPageNumber, List<int> pageNumbersObserved)
{
var type = currentPageDictionary.GetName(CosName.TYPE);
@@ -120,7 +120,7 @@
foreach (var kid in kids.OfType<CosObject>())
{
// todo: exit early
var child = arguments.Container.Get<DynamicParser>().Parse(arguments, kid, false) as ContentStreamDictionary;
var child = arguments.Container.Get<DynamicParser>().Parse(arguments, kid, false) as PdfDictionary;
var thisPageMatches = FindPage(child, soughtPageNumber, pageNumbersObserved);

View File

@@ -10,7 +10,6 @@
using Fonts.Parser;
using IO;
using Parser;
using Util.JetBrains.Annotations;
internal interface IResourceStore
{
@@ -21,15 +20,15 @@
{
private readonly Dictionary<CosName, IFont> loadedFonts = new Dictionary<CosName, IFont>();
internal void LoadResourceDictionary(ContentStreamDictionary dictionary, ParsingArguments arguments)
internal void LoadResourceDictionary(PdfDictionary dictionary, ParsingArguments arguments)
{
if (dictionary.TryGetValue(CosName.FONT, out var fontBase) && fontBase is ContentStreamDictionary fontDictionary)
if (dictionary.TryGetValue(CosName.FONT, out var fontBase) && fontBase is PdfDictionary fontDictionary)
{
LoadFontDictionary(fontDictionary, arguments);
}
}
private void LoadFontDictionary(ContentStreamDictionary fontDictionary, ParsingArguments arguments)
private void LoadFontDictionary(PdfDictionary fontDictionary, ParsingArguments arguments)
{
foreach (var pair in fontDictionary)
{
@@ -50,7 +49,7 @@
var dynamicParser = arguments.Get<DynamicParser>();
var fontObject = dynamicParser.Parse(arguments, objectKey, false) as ContentStreamDictionary;
var fontObject = dynamicParser.Parse(arguments, objectKey, false) as PdfDictionary;
if (fontObject == null)
{

View File

@@ -3,10 +3,11 @@
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using Cos;
using Util.JetBrains.Annotations;
public class ContentStreamDictionary : CosBase, IReadOnlyDictionary<CosName, CosBase>
public class PdfDictionary : CosBase, IReadOnlyDictionary<CosName, CosBase>
{
private readonly Dictionary<CosName, CosBase> inner = new Dictionary<CosName, CosBase>();
@@ -21,6 +22,13 @@
return name;
}
public bool TryGetName(CosName key, out CosName value)
{
value = GetName(key);
return value != null;
}
public bool IsType(CosName expectedType)
{
if (!inner.TryGetValue(CosName.TYPE, out CosBase obj) || obj == null)
@@ -72,6 +80,17 @@
inner[key] = value ?? throw new ArgumentNullException(nameof(value));
}
public override string ToString()
{
var builder = new StringBuilder();
foreach (var cosBase in inner)
{
builder.Append($"({cosBase.Key}, {cosBase.Value}) ");
}
return builder.ToString();
}
#region Interface Members
public int Count => inner.Count;
public CosBase this[CosName key] => inner[key];

View File

@@ -7,12 +7,12 @@
public static class DictionaryValueAccessorExtensions
{
public static long GetLongOrDefault(this ContentStreamDictionary dictionary, CosName key)
public static long GetLongOrDefault(this PdfDictionary dictionary, CosName key)
{
return dictionary.GetLongOrDefault(key, -1L);
}
public static long GetLongOrDefault(this ContentStreamDictionary dictionary, IEnumerable<string> keys, long defaultValue)
public static long GetLongOrDefault(this PdfDictionary dictionary, IEnumerable<string> keys, long defaultValue)
{
foreach (var key in keys)
{
@@ -25,12 +25,12 @@
return defaultValue;
}
public static long GetLongOrDefault(this ContentStreamDictionary dictionary, string key, long defaultValue)
public static long GetLongOrDefault(this PdfDictionary dictionary, string key, long defaultValue)
{
return dictionary.GetLongOrDefault(CosName.Create(key), defaultValue);
}
public static long GetLongOrDefault(this ContentStreamDictionary dictionary, CosName key, long defaultValue)
public static long GetLongOrDefault(this PdfDictionary dictionary, CosName key, long defaultValue)
{
if (!dictionary.TryGetValue(key, out CosBase obj) || !(obj is ICosNumber number))
{
@@ -40,12 +40,12 @@
return number.AsLong();
}
public static int GetIntOrDefault(this ContentStreamDictionary dictionary, CosName key)
public static int GetIntOrDefault(this PdfDictionary dictionary, CosName key)
{
return dictionary.GetIntOrDefault(key, -1);
}
public static int GetIntOrDefault(this ContentStreamDictionary dictionary, IEnumerable<string> keyList, int defaultValue)
public static int GetIntOrDefault(this PdfDictionary dictionary, IEnumerable<string> keyList, int defaultValue)
{
foreach (var key in keyList)
{
@@ -58,22 +58,22 @@
return defaultValue;
}
public static int GetIntOrDefault(this ContentStreamDictionary dictionary, string key, int defaultValue)
public static int GetIntOrDefault(this PdfDictionary dictionary, string key, int defaultValue)
{
return dictionary.GetIntOrDefault(CosName.Create(key), defaultValue);
}
public static int GetIntOrDefault(this ContentStreamDictionary dictionary, CosName key, int defaultValue)
public static int GetIntOrDefault(this PdfDictionary dictionary, CosName key, int defaultValue)
{
return dictionary.GetIntOrDefault(key, null, defaultValue);
}
public static int GetIntOrDefault(this ContentStreamDictionary dictionary, CosName firstKey, CosName secondKey)
public static int GetIntOrDefault(this PdfDictionary dictionary, CosName firstKey, CosName secondKey)
{
return dictionary.GetIntOrDefault(firstKey, secondKey, -1);
}
public static int GetIntOrDefault(this ContentStreamDictionary dictionary, CosName firstKey, CosName secondKey, int defaultValue)
public static int GetIntOrDefault(this PdfDictionary dictionary, CosName firstKey, CosName secondKey, int defaultValue)
{
if (dictionary.TryGetValue(firstKey, out var obj) && obj is ICosNumber number)
{
@@ -88,7 +88,17 @@
return defaultValue;
}
public static CosBase GetDictionaryObject(this ContentStreamDictionary dictionary, CosName firstKey, CosName secondKey)
public static decimal GetDecimalOrDefault(this PdfDictionary dictionary, CosName key, decimal defaultValue)
{
if (!dictionary.TryGetValue(key, out CosBase obj) || !(obj is ICosNumber number))
{
return defaultValue;
}
return (decimal)number.AsDouble();
}
public static CosBase GetDictionaryObject(this PdfDictionary dictionary, CosName firstKey, CosName secondKey)
{
CosBase result = dictionary.GetDictionaryObject(firstKey);
@@ -100,7 +110,7 @@
return result;
}
public static CosBase GetDictionaryObject(this ContentStreamDictionary dictionary, IEnumerable<string> keyList)
public static CosBase GetDictionaryObject(this PdfDictionary dictionary, IEnumerable<string> keyList)
{
foreach (var key in keyList)
{
@@ -116,7 +126,7 @@
}
[CanBeNull]
public static CosBase GetDictionaryObject(this ContentStreamDictionary dictionary, CosName key)
public static CosBase GetDictionaryObject(this PdfDictionary dictionary, CosName key)
{
dictionary.TryGetValue(key, out CosBase result);
@@ -133,7 +143,7 @@
}
[CanBeNull]
public static CosObjectKey GetObjectKey(this ContentStreamDictionary dictionary, CosName key)
public static CosObjectKey GetObjectKey(this PdfDictionary dictionary, CosName key)
{
if (!dictionary.TryGetValue(key, out var value) || !(value is CosObject obj))
{
@@ -144,7 +154,7 @@
}
[CanBeNull]
public static ContentStreamDictionary GetDictionaryOrDefault(this ContentStreamDictionary dictionary,
public static PdfDictionary GetDictionaryOrDefault(this PdfDictionary dictionary,
CosName key)
{
if (!dictionary.TryGetValue(key, out var value))
@@ -152,7 +162,7 @@
return null;
}
return value as ContentStreamDictionary;
return value as PdfDictionary;
}
}
}

View File

@@ -4,14 +4,14 @@
public static class DictionaryValueSetterExtensions
{
public static void SetLong(this ContentStreamDictionary dictionary, CosName key, long value)
public static void SetLong(this PdfDictionary dictionary, CosName key, long value)
{
var wrappedInt = CosInt.Get(value);
dictionary.Set(key, wrappedInt);
}
public static void SetInt(this ContentStreamDictionary dictionary, CosName key, int value)
public static void SetInt(this PdfDictionary dictionary, CosName key, int value)
{
var wrappedInt = CosInt.Get(value);

View File

@@ -177,5 +177,10 @@ namespace UglyToad.Pdf.Cos
{
return (long) value;
}
public decimal AsDecimal()
{
return value;
}
}
}

View File

@@ -142,5 +142,10 @@ namespace UglyToad.Pdf.Cos
{
return value;
}
public decimal AsDecimal()
{
return value;
}
}
}

View File

@@ -17,6 +17,11 @@
SetObject(obj);
}
public CosObjectKey GetObjectKey()
{
return new CosObjectKey(objectNumber, generationNumber);
}
/**
* This will get the dictionary object in this object that has the name key and
* if it is a pdfobjref then it will dereference that and return it.

View File

@@ -15,9 +15,9 @@
public IReadOnlyDictionary<CosObjectKey, long> ObjectOffsets => objectOffsets;
[NotNull]
public ContentStreamDictionary Dictionary { get; }
public PdfDictionary Dictionary { get; }
public CrossReferenceTable(CrossReferenceType type, IReadOnlyDictionary<CosObjectKey, long> objectOffsets, ContentStreamDictionary dictionary)
public CrossReferenceTable(CrossReferenceType type, IReadOnlyDictionary<CosObjectKey, long> objectOffsets, PdfDictionary dictionary)
{
if (objectOffsets == null)
{

View File

@@ -31,7 +31,7 @@
public CrossReferenceTable Build(long startXrefOffset, ILog log)
{
CrossReferenceType type = CrossReferenceType.Table;
ContentStreamDictionary trailerDictionary = new ContentStreamDictionary();
PdfDictionary trailerDictionary = new PdfDictionary();
Dictionary<CosObjectKey, long> objectOffsets = new Dictionary<CosObjectKey, long>();
List<long> xrefSeqBytePos = new List<long>();

View File

@@ -29,11 +29,11 @@
public long Previous { get; }
public ContentStreamDictionary Dictionary { get; }
public PdfDictionary Dictionary { get; }
public CrossReferenceType Type { get; }
public CrossReferenceTablePart(IReadOnlyDictionary<CosObjectKey, long> objectOffsets, long offset, long previous, ContentStreamDictionary dictionary, CrossReferenceType type)
public CrossReferenceTablePart(IReadOnlyDictionary<CosObjectKey, long> objectOffsets, long offset, long previous, PdfDictionary dictionary, CrossReferenceType type)
{
ObjectOffsets = objectOffsets;
Offset = offset;

View File

@@ -11,7 +11,7 @@
public long Previous { get; set; }
public ContentStreamDictionary Dictionary { get; set; }
public PdfDictionary Dictionary { get; set; }
public CrossReferenceType XRefType { get; set; }

View File

@@ -9,5 +9,7 @@
int AsInt();
long AsLong();
decimal AsDecimal();
}
}

View File

@@ -8,16 +8,16 @@
{
private static readonly object Lock = new object();
private readonly byte[] streamBytes;
public readonly byte[] streamBytes;
private byte[] decodedBytes;
public ContentStreamDictionary Dictionary { get; }
public PdfDictionary Dictionary { get; }
/// <summary>
/// Combines the dictionary for the stream with the raw, encoded/filtered bytes.
/// </summary>
public RawCosStream(byte[] streamBytes, ContentStreamDictionary streamDictionary)
public RawCosStream(byte[] streamBytes, PdfDictionary streamDictionary)
{
this.streamBytes = streamBytes;

View File

@@ -15,7 +15,7 @@
this.log = log;
}
public ContentStreamDictionary GetFilterParameters(ContentStreamDictionary streamDictionary, int index)
public PdfDictionary GetFilterParameters(PdfDictionary streamDictionary, int index)
{
if (streamDictionary == null)
{
@@ -34,7 +34,7 @@
switch (filter)
{
case CosName _:
if (parameters is ContentStreamDictionary dict)
if (parameters is PdfDictionary dict)
{
return dict;
}
@@ -42,7 +42,7 @@
case COSArray array:
if (parameters is COSArray arr)
{
if (index < arr.size() && array.getObject(index) is ContentStreamDictionary dictionary)
if (index < arr.size() && array.getObject(index) is PdfDictionary dictionary)
{
return dictionary;
}
@@ -56,7 +56,7 @@
break;
}
return new ContentStreamDictionary();
return new PdfDictionary();
}
}
}

View File

@@ -34,7 +34,7 @@
this.log = log;
}
public byte[] Decode(byte[] input, ContentStreamDictionary streamDictionary, int filterIndex)
public byte[] Decode(byte[] input, PdfDictionary streamDictionary, int filterIndex)
{
if (input == null)
{

View File

@@ -4,6 +4,6 @@
public interface IDecodeParameterResolver
{
ContentStreamDictionary GetFilterParameters(ContentStreamDictionary streamDictionary, int index);
PdfDictionary GetFilterParameters(PdfDictionary streamDictionary, int index);
}
}

View File

@@ -4,6 +4,6 @@
public interface IFilter
{
byte[] Decode(byte[] input, ContentStreamDictionary streamDictionary, int filterIndex);
byte[] Decode(byte[] input, PdfDictionary streamDictionary, int filterIndex);
}
}

View File

@@ -9,7 +9,7 @@
internal interface IFilterProvider
{
IReadOnlyList<IFilter> GetFilters(ContentStreamDictionary streamDictionary);
IReadOnlyList<IFilter> GetFilters(PdfDictionary streamDictionary);
IReadOnlyList<IFilter> GetAllFilters();
}
@@ -29,7 +29,7 @@
};
}
public IReadOnlyList<IFilter> GetFilters(ContentStreamDictionary streamDictionary)
public IReadOnlyList<IFilter> GetFilters(PdfDictionary streamDictionary)
{
if (streamDictionary == null)
{

View File

@@ -1,5 +1,7 @@
namespace UglyToad.Pdf.Fonts.Cmap
namespace UglyToad.Pdf.Fonts
{
using CidFonts;
/// <summary>
/// Specifies the character collection associated with the <see cref="CharacterIdentifierFont"/> (CIDFont).
/// </summary>

View File

@@ -0,0 +1,43 @@
namespace UglyToad.Pdf.Fonts.CidFonts
{
using Cmap;
using Cos;
internal class CharacterIdentifierFont
{
public const int DefaultWidthWhenUndeclared = 1000;
public CidFontType Subtype { get; }
public CosName BaseFont { get; }
public CharacterIdentifierSystemInfo SystemInfo { get; set; }
public CosObjectKey FontDescriptor { get; set; }
public int DefaultWidth { get; }
public COSArray Widths { get; set; }
public VerticalVectorComponents VerticalVectors { get; } = VerticalVectorComponents.Default;
public CharacterIdentifierToGlyphIdentifierMap CidToGidMap { get; }
public CharacterIdentifierFont(CidFontType subtype, CosName baseFont, CharacterIdentifierSystemInfo systemInfo,
CosObjectKey fontDescriptor,
int defaultWidth,
COSArray widths,
CharacterIdentifierToGlyphIdentifierMap cidToGidMap)
{
Subtype = subtype;
BaseFont = baseFont;
SystemInfo = systemInfo;
FontDescriptor = fontDescriptor;
DefaultWidth = defaultWidth;
Widths = widths;
CidToGidMap = cidToGidMap;
}
}
}

View File

@@ -0,0 +1,47 @@
namespace UglyToad.Pdf.Fonts.CidFonts
{
using System;
using System.Collections.Generic;
using Cmap;
using Cos;
internal class CharacterIdentifierFontBuilder
{
private static readonly IReadOnlyDictionary<CosName, CidFontType> NameTypeMap = new Dictionary<CosName, CidFontType>
{
{ CosName.CID_FONT_TYPE0, CidFontType.Type0 },
{ CosName.CID_FONT_TYPE2, CidFontType.Type2 }
};
private readonly CidFontType subType;
private readonly CosName baseFont;
private int defaultWidth = CharacterIdentifierFont.DefaultWidthWhenUndeclared;
private readonly CharacterIdentifierSystemInfo systemInfo;
private readonly CosObjectKey fontDescriptorKey;
public CharacterIdentifierFontBuilder(CosName subType, CosName baseFont,
CharacterIdentifierSystemInfo systemInfo,
CosObjectKey fontDescriptorKey)
{
if (!NameTypeMap.TryGetValue(subType, out var subTypeValue))
{
throw new InvalidOperationException("The subType of the CIDFont was not valid: " + subType);
}
this.subType = subTypeValue;
this.baseFont = baseFont;
this.systemInfo = systemInfo;
this.fontDescriptorKey = fontDescriptorKey;
}
public void WithDefaultWidth(int width)
{
defaultWidth = width;
}
public CharacterIdentifierFont Build()
{
return new CharacterIdentifierFont(subType, baseFont, systemInfo, fontDescriptorKey, defaultWidth, null, null);
}
}
}

View File

@@ -0,0 +1,7 @@
namespace UglyToad.Pdf.Fonts.CidFonts
{
public class CharacterIdentifierToGlyphIdentifierMap
{
}
}

View File

@@ -0,0 +1,14 @@
namespace UglyToad.Pdf.Fonts.CidFonts
{
public enum CidFontType
{
/// <summary>
/// Glyph descriptions based on Adobe Type 1 format.
/// </summary>
Type0 = 0,
/// <summary>
/// Glyph descriptions based on TrueType format.
/// </summary>
Type2 = 2
}
}

View File

@@ -0,0 +1,36 @@
namespace UglyToad.Pdf.Fonts.CidFonts
{
using Cmap;
using Cos;
/// <summary>
/// A CID font contains glyph descriptions accessed by
/// CID (character identifier) as character selectors.
/// </summary>
/// <remarks>
/// A CID font contains information about a CIDFont program but is
/// not itself a font. It can only be a descendant of a Type 0 font.
/// </remarks>
internal interface ICidFont
{
/// <summary>
/// <see cref="CosName.FONT"/>
/// </summary>
CosName Type { get; }
/// <summary>
/// Either Type0 (Adobe Type 1 font) or Type2 (TrueType font).
/// </summary>
CosName SubType { get; }
/// <summary>
/// The PostScript name of the CIDFont.
/// </summary>
CosName BaseFont { get; }
/// <summary>
/// The definition of the character collection for the font.
/// </summary>
CharacterIdentifierSystemInfo SystemInfo { get; }
}
}

View File

@@ -0,0 +1,18 @@
namespace UglyToad.Pdf.Fonts.CidFonts
{
using Cmap;
using Cos;
/// <inheritdoc/>
/// <summary>
/// Type 0 CID fonts contain glyph descriptions based on the
/// Adobe Type 1 font format.
/// </summary>
internal class Type0CidFont : ICidFont
{
public CosName Type { get; }
public CosName SubType { get; }
public CosName BaseFont { get; }
public CharacterIdentifierSystemInfo SystemInfo { get; }
}
}

View File

@@ -0,0 +1,18 @@
namespace UglyToad.Pdf.Fonts.CidFonts
{
using Cmap;
using Cos;
/// <inheritdoc />
/// <summary>
/// Type 2 CID fonts contains glyph descriptions based on
/// the TrueType font format.
/// </summary>
internal class Type2CidFont : ICidFont
{
public CosName Type { get; }
public CosName SubType { get; }
public CosName BaseFont { get; }
public CharacterIdentifierSystemInfo SystemInfo { get; }
}
}

View File

@@ -0,0 +1,20 @@
namespace UglyToad.Pdf.Fonts.CidFonts
{
/// <summary>
/// Equivalent to the DW2 array in the font dictionary for vertical fonts.
/// </summary>
public struct VerticalVectorComponents
{
public decimal Position { get; }
public decimal Displacement { get; }
public VerticalVectorComponents(decimal position, decimal displacement)
{
Position = position;
Displacement = displacement;
}
public static VerticalVectorComponents Default = new VerticalVectorComponents(800, -1000);
}
}

View File

@@ -0,0 +1,21 @@
namespace UglyToad.Pdf.Fonts.CidFonts
{
using System.Collections.Generic;
using Geometry;
internal class VerticalWritingMetrics
{
public VerticalVectorComponents DefaultVerticalWritingMetrics { get; }
public IReadOnlyDictionary<int, decimal> IndividualVerticalWritingDisplacements { get; }
public IReadOnlyDictionary<int, PdfVector> IndividualVerticalWritingPositions { get; }
public VerticalWritingMetrics(VerticalVectorComponents defaultVerticalWritingMetrics, IReadOnlyDictionary<int, decimal> individualVerticalWritingDisplacements, IReadOnlyDictionary<int, PdfVector> individualVerticalWritingPositions)
{
DefaultVerticalWritingMetrics = defaultVerticalWritingMetrics;
IndividualVerticalWritingDisplacements = individualVerticalWritingDisplacements;
IndividualVerticalWritingPositions = individualVerticalWritingPositions;
}
}
}

View File

@@ -1,129 +0,0 @@
namespace UglyToad.Pdf.Fonts
{
using System;
using System.Collections.Generic;
using Cmap;
using Cos;
//public class CompositeFont
//{
// public bool IsSimple { get; } = false;
// public CosName SubType { get; } = CosName.TYPE0;
// public CharacterIdentifierFont Descendant { get; }
//}
/// <summary>
/// Equivalent to the DW2 array in the font dictionary for vertical fonts.
/// </summary>
public struct VerticalVectorComponents
{
public decimal Position { get; }
public decimal Displacement { get; }
public VerticalVectorComponents(decimal position, decimal displacement)
{
Position = position;
Displacement = displacement;
}
public static VerticalVectorComponents Default = new VerticalVectorComponents(800, -1000);
}
public enum CidFontType
{
/// <summary>
/// Glyph descriptions based on Adobe Type 1 format.
/// </summary>
Type0 = 0,
/// <summary>
/// Glyph descriptions based on TrueType format.
/// </summary>
Type2 = 2
}
public class CharacterIdentifierFont
{
public const int DefaultWidthWhenUndeclared = 1000;
public CidFontType Subtype { get; }
public CosName BaseFont { get; }
public CharacterIdentifierSystemInfo SystemInfo { get; set; }
public CosObjectKey FontDescriptor { get; set; }
public int DefaultWidth { get; }
public COSArray Widths { get; set; }
public VerticalVectorComponents VerticalVectors { get; } = VerticalVectorComponents.Default;
public CharacterIdentifierToGlyphIdentifierMap CidToGidMap { get; }
public CharacterIdentifierFont(CidFontType subtype, CosName baseFont, CharacterIdentifierSystemInfo systemInfo,
CosObjectKey fontDescriptor,
int defaultWidth,
COSArray widths,
CharacterIdentifierToGlyphIdentifierMap cidToGidMap)
{
Subtype = subtype;
BaseFont = baseFont;
SystemInfo = systemInfo;
FontDescriptor = fontDescriptor;
DefaultWidth = defaultWidth;
Widths = widths;
CidToGidMap = cidToGidMap;
}
}
public class CharacterIdentifierFontBuilder
{
private static readonly IReadOnlyDictionary<CosName, CidFontType> NameTypeMap = new Dictionary<CosName, CidFontType>
{
{ CosName.CID_FONT_TYPE0, CidFontType.Type0 },
{ CosName.CID_FONT_TYPE2, CidFontType.Type2 }
};
private readonly CidFontType subType;
private readonly CosName baseFont;
private int defaultWidth = CharacterIdentifierFont.DefaultWidthWhenUndeclared;
private readonly CharacterIdentifierSystemInfo systemInfo;
private readonly CosObjectKey fontDescriptorKey;
public CharacterIdentifierFontBuilder(CosName subType, CosName baseFont,
CharacterIdentifierSystemInfo systemInfo,
CosObjectKey fontDescriptorKey)
{
if (!NameTypeMap.TryGetValue(subType, out var subTypeValue))
{
throw new InvalidOperationException("The subType of the CIDFont was not valid: " + subType);
}
this.subType = subTypeValue;
this.baseFont = baseFont;
this.systemInfo = systemInfo;
this.fontDescriptorKey = fontDescriptorKey;
}
public void WithDefaultWidth(int width)
{
defaultWidth = width;
}
public CharacterIdentifierFont Build()
{
return new CharacterIdentifierFont(subType, baseFont, systemInfo, fontDescriptorKey, defaultWidth, null, null);
}
}
public class CharacterIdentifierToGlyphIdentifierMap
{
}
}

View File

@@ -0,0 +1,36 @@
namespace UglyToad.Pdf.Fonts
{
using Cos;
/// <summary>
/// The bytes of the stream containing the font program.
/// </summary>
/// <remarks>
/// This can either be a Type 1 font program (FontFile - <see cref="FontFileType.Type1"/>),
/// a TrueType font program (FontFile2 - <see cref="FontFileType.TrueType"/>) or a font program
/// whose format is given by the Subtype of the stream dictionary (FontFile3 - <see cref="FontFileType.FromSubtype"/>).
/// At most only 1 of these entries is present.
/// </remarks>
internal class DescriptorFontFile
{
public CosObjectKey ObjectKey { get; }
public byte[] FileBytes { get; }
public FontFileType FileType { get; }
public DescriptorFontFile(CosObjectKey key, FontFileType fileType)
{
ObjectKey = key;
FileBytes = new byte[0];
FileType = fileType;
}
public enum FontFileType
{
Type1,
TrueType,
FromSubtype
}
}
}

View File

@@ -0,0 +1,164 @@
namespace UglyToad.Pdf.Fonts
{
using Cos;
using Geometry;
using Util.JetBrains.Annotations;
/// <summary>
/// Specifies metrics and attributes of a simple font or CID Font
/// for the whole font rather than per-glyph.
/// </summary>
/// <remarks>
/// <para>
/// Provides information to enable consumer applications to
/// find a substitute font when the font is unavailable.
/// </para>
/// <para>
/// Font descriptors are not used with Type 0 fonts.
/// </para>
/// <para>
/// A font descriptor is a dictionary used to specify various attributes.
/// </para>
/// </remarks>
internal class FontDescriptor
{
/// <summary>
/// The PostScript name for the font.
/// </summary>
/// <remarks>Required</remarks>
public CosName FontName { get; }
/// <summary>
/// The preferred font family.
/// </summary>
/// <remarks>Optional</remarks>
public string FontFamily { get; set; }
/// <summary>
/// The font stretch value.
/// </summary>
/// <remarks>Optional</remarks>
public FontStretch Stretch { get; set; } = FontStretch.Normal;
/// <summary>
/// The weight/thickness of the font.
/// </summary>
/// <remarks>
/// Possible values:
/// 100<br/>
/// 200<br/>
/// 300<br/>
/// 500 (normal)<br/>
/// 600<br/>
/// 700<br/>
/// 800<br/>
/// 900<br/>
/// Optional
/// </remarks>
public decimal FontWeight { get; set; } = 400;
/// <summary>
/// Defines various font characteristics. See <see cref="FontFlags"/>.
/// </summary>
/// <remarks>Required</remarks>
public FontFlags Flags { get; }
/// <summary>
/// A rectangle in glyph coordinates which represents the smallest
/// rectangle containing all glyphs of the font.
/// </summary>
/// <remarks>Required (Except Type 3)</remarks>
public PdfRectangle BoundingBox { get; set; }
/// <summary>
/// The angle in degrees counter-clockwise from vertical of the vertical
/// lines of the font.
/// The value is negative for fonts sloping right (italic fonts).
/// </summary>
/// <example>9 o'clock is represented by 90 degrees. 3 o'clock is -90 degrees.</example>
/// <remarks>Required</remarks>
public decimal ItalicAngle { get; set; }
/// <summary>
/// The maximum height above the baseline for any glyph from this font (except for accents).
/// </summary>
/// <remarks>Required (Except Type 3)</remarks>
public decimal Ascent { get; set; }
/// <summary>
/// The maximum depth below the baseline for any glyph in the font. This is negative.
/// </summary>
/// <remarks>Required (Except Type 3)</remarks>
public decimal Descent { get; set; }
/// <summary>
/// The spacing between consecutive lines of text. Default 0.
/// </summary>
/// <remarks>Optional</remarks>
public decimal Leading { get; set; }
/// <summary>
/// The vertical distance of the top of flat capital letters from the baseline.
/// </summary>
/// <remarks>Required (Where Latin Characters, Except Type 3)</remarks>
public decimal CapHeight { get; set; }
/// <summary>
/// The x height of the font. The vertical distance of the top of flat non-ascending
/// lowercase letters (e.g. x) from the baseline. Default 0.
/// </summary>
/// <remarks>Optional</remarks>
public decimal XHeight { get; set; }
/// <summary>
/// The horizontal thickness of vertical stems of glyphs.
/// </summary>
/// <remarks>Required (Except Type 3)</remarks>
public decimal StemVertical { get; set; }
/// <summary>
/// The vertical thickness of horizontal stems of glyphs. Default 0.
/// </summary>
/// <remarks>Optional</remarks>
public decimal StemHorizontal { get; set; }
/// <summary>
/// The average glyph width in the font. Default 0.
/// </summary>
/// <remarks>Optional</remarks>
public decimal AverageWidth { get; set; }
/// <summary>
/// The maximum glyph width in the font. Default 0.
/// </summary>
/// <remarks>Optional</remarks>
public decimal MaxWidth { get; set; }
/// <summary>
/// The width for character codes whose widths are not present in the Widths
/// array of the font dictionary. Default 0.
/// </summary>
/// <remarks>Optional</remarks>
public decimal MissingWidth { get; set; }
/// <summary>
/// The bytes of the font program.
/// </summary>
/// <remarks>Optional</remarks>
[CanBeNull]
public DescriptorFontFile FontFile { get; set; }
/// <summary>
/// The character names defined in a font subset.
/// </summary>
/// <remarks>Optional</remarks>
[CanBeNull]
public string CharSet { get; set; }
public FontDescriptor(CosName name, FontFlags flags)
{
FontName = name;
Flags = flags;
}
}
}

View File

@@ -4,7 +4,8 @@
using System.Collections.Generic;
using ContentStream;
using Cos;
using Parser;
using Parser.Handlers;
using Parser.Parts;
using Pdf.Parser;
internal class FontFactory
@@ -15,11 +16,11 @@
{
Handlers = new Dictionary<CosName, IFontHandler>
{
{CosName.TYPE0, new Type0FontHandler()}
{CosName.TYPE0, new Type0FontHandler(new CidFontFactory(new FontDescriptorFactory()))}
};
}
public IFont GetFont(ContentStreamDictionary dictionary, ParsingArguments arguments)
public IFont GetFont(PdfDictionary dictionary, ParsingArguments arguments)
{
var type = dictionary.GetName(CosName.TYPE);

View File

@@ -0,0 +1,47 @@
namespace UglyToad.Pdf.Fonts
{
using System;
[Flags]
internal enum FontFlags
{
None = 0,
/// <summary>
/// All glyphs have the same width.
/// </summary>
FixedPitch = 1,
/// <summary>
/// Glyphs have serifs.
/// </summary>
Serif = 1 << 1,
/// <summary>
/// There are glyphs outside the Adobe standard Latin set.
/// </summary>
Symbolic = 1 << 2,
/// <summary>
/// The glyphs resemble cursive handwriting.
/// </summary>
Script = 1 << 3,
/// <summary>
/// Font uses a (sub)set of the Adobe standard Latin set.
/// </summary>
/// <remarks>Cannot be set at the same time as <see cref="Symbolic"/>.</remarks>
Nonsymbolic = 1 << 5,
/// <summary>
/// Font is italic.
/// </summary>
Italic = 1 << 6,
/// <summary>
/// Font contains only uppercase letters.
/// </summary>
AllCap = 1 << 16,
/// <summary>
/// Lowercase letters are smaller versions of the uppercase equivalent.
/// </summary>
SmallCap = 1 << 17,
/// <summary>
/// Forces small bold text to be rendered bold.
/// </summary>
ForceBold = 1 << 18
}
}

View File

@@ -0,0 +1,19 @@
namespace UglyToad.Pdf.Fonts
{
/// <summary>
/// The font stretch.
/// </summary>
internal enum FontStretch
{
Unknown = -1,
UltraCondensed,
ExtraCondensed,
Condensed,
SemiCondensed,
Normal,
SemiExpanded,
Expanded,
ExtraExpanded,
UltraExpanded
}
}

View File

@@ -0,0 +1,32 @@
namespace UglyToad.Pdf.Fonts
{
using Cos;
internal static class FontStretchExtensions
{
public static FontStretch ConvertToFontStretch(this CosName name)
{
switch (name.Name)
{
case "UltraCondensed":
return FontStretch.UltraCondensed;
case "ExtraCondensed":
return FontStretch.ExtraCondensed;
case "Condensed":
return FontStretch.Condensed;
case "Normal":
return FontStretch.Normal;
case "SemiExpanded":
return FontStretch.SemiExpanded;
case "Expanded":
return FontStretch.Expanded;
case "ExtraExpanded":
return FontStretch.ExtraExpanded;
case "UltraExpanded":
return FontStretch.UltraExpanded;
default:
return FontStretch.Unknown;
}
}
}
}

View File

@@ -1,710 +0,0 @@
//using System;
//using System.Collections.Generic;
//using System.Text;
//using UglyToad.Pdf.Fonts.Cmap;
//namespace UglyToad.Pdf.Fonts.Parser
//{
// using Cmap;
// using Text;
// internal class CMapParser
// {
// private static readonly String MARK_END_OF_DICTIONARY = ">>";
// private static readonly String MARK_END_OF_ARRAY = "]";
// private readonly byte[] tokenParserByteBuffer = new byte[512];
// /**
// * Creates a new instance of CMapParser.
// */
// public CMapParser()
// {
// }
///**
// * Parses a predefined CMap.
// *
// * @param name CMap name.
// * @return The parsed predefined CMap as a java object, never null.
// * @throws IOException If the CMap could not be parsed.
// */
//public CMap parsePredefined(String name)
//{
// try (InputStream input = getExternalCMap(name))
// {
// return parse(input);
// }
//}
///**
// * This will parse the stream and create a cmap object.
// *
// * @param input The CMAP stream to parse.
// * @return The parsed stream as a java object, never null.
// * @throws IOException If there is an error parsing the stream.
// */
//public CMap parse(InputStream input)
//{
// PushbackInputStream cmapStream = new PushbackInputStream(input);
//CMap result = new CMap();
//Object previousToken = null;
//Object token;
// while ((token = parseNextToken(cmapStream)) != null)
// {
// if (token instanceof Operator)
// {
// Operator op = (Operator)token;
// if (op.op.equals("endcmap"))
// {
// // end of CMap reached, stop reading as there isn't any interesting info anymore
// break;
// }
// switch (op.op)
// {
// case "usecmap":
// parseUsecmap((LiteralName) previousToken, result);
// break;
// case "begincodespacerange":
// parseBegincodespacerange((Number) previousToken, cmapStream, result);
// break;
// case "beginbfchar":
// parseBeginbfchar((Number) previousToken, cmapStream, result);
// break;
// case "beginbfrange":
// parseBeginbfrange((Number) previousToken, cmapStream, result);
// break;
// case "begincidchar":
// parseBegincidchar((Number) previousToken, cmapStream, result);
// break;
// case "begincidrange":
// parseBegincidrange((Integer) previousToken, cmapStream, result);
// break;
// default:
// break;
// }
// }
// else if (token instanceof LiteralName)
// {
// parseLiteralName((LiteralName) token, cmapStream, result);
// }
// previousToken = token;
// }
// return result;
// }
// private void parseUsecmap(LiteralName useCmapName, CMap result)
//{
// InputStream useStream = getExternalCMap(useCmapName.name);
// CMap useCMap = parse(useStream);
// result.useCmap(useCMap);
//}
//private void parseLiteralName(LiteralName literal, PushbackInputStream cmapStream, CMap result)
//{
// switch (literal.name)
// {
// case "WMode":
// {
// Object next = parseNextToken(cmapStream);
// if (next instanceof Integer)
// {
// result.setWMode((Integer)next);
// }
// break;
// }
// case "CMapName":
// {
// Object next = parseNextToken(cmapStream);
// if (next instanceof LiteralName)
// {
// result.setName(((LiteralName)next).name);
// }
// break;
// }
// case "CMapVersion":
// {
// Object next = parseNextToken(cmapStream);
// if (next instanceof Number)
// {
// result.setVersion(next.toString());
// }
// else if (next instanceof String)
// {
// result.setVersion((String)next);
// }
// break;
// }
// case "CMapType":
// {
// Object next = parseNextToken(cmapStream);
// if (next instanceof Integer)
// {
// result.setType((Integer)next);
// }
// break;
// }
// case "Registry":
// {
// Object next = parseNextToken(cmapStream);
// if (next instanceof String)
// {
// result.setRegistry((String)next);
// }
// break;
// }
// case "Ordering":
// {
// Object next = parseNextToken(cmapStream);
// if (next instanceof String)
// {
// result.setOrdering((String)next);
// }
// break;
// }
// case "Supplement":
// {
// Object next = parseNextToken(cmapStream);
// if (next instanceof Integer)
// {
// result.setSupplement((Integer)next);
// }
// break;
// }
// default:
// break;
// }
//}
//private void parseBegincodespacerange(Number cosCount, PushbackInputStream cmapStream, CMap result)
//{
// for (int j = 0; j < cosCount.intValue(); j++)
// {
// Object nextToken = parseNextToken(cmapStream);
// if (nextToken instanceof Operator)
// {
// if (!((Operator)nextToken).op.equals("endcodespacerange"))
// {
// throw new IOException("Error : ~codespacerange contains an unexpected operator : "
// + ((Operator)nextToken).op);
// }
// break;
// }
// byte[] startRange = (byte[])nextToken;
// byte[] endRange = (byte[])parseNextToken(cmapStream);
// CodespaceRange range = new CodespaceRange();
// range.setStart(startRange);
// range.setEnd(endRange);
// result.addCodespaceRange(range);
// }
//}
//private void parseBeginbfchar(Number cosCount, PushbackInputStream cmapStream, CMap result)
//{
// for (int j = 0; j < cosCount.intValue(); j++)
// {
// Object nextToken = parseNextToken(cmapStream);
// if (nextToken instanceof Operator)
// {
// if (!((Operator)nextToken).op.equals("endbfchar"))
// {
// throw new IOException("Error : ~bfchar contains an unexpected operator : "
// + ((Operator)nextToken).op);
// }
// break;
// }
// byte[] inputCode = (byte[])nextToken;
// nextToken = parseNextToken(cmapStream);
// if (nextToken instanceof byte[])
// {
// byte[] bytes = (byte[])nextToken;
// String value = createStringFromBytes(bytes);
// result.addCharMapping(inputCode, value);
// }
// else if (nextToken instanceof LiteralName)
// {
// result.addCharMapping(inputCode, ((LiteralName)nextToken).name);
// }
// else
// {
// throw new IOException("Error parsing CMap beginbfchar, expected{COSString "
// + "or COSName} and not " + nextToken);
// }
// }
//}
//private void parseBegincidrange(int numberOfLines, PushbackInputStream cmapStream, CMap result)
//{
// for (int n = 0; n < numberOfLines; n++)
// {
// Object nextToken = parseNextToken(cmapStream);
// if (nextToken instanceof Operator)
// {
// if (!((Operator)nextToken).op.equals("endcidrange"))
// {
// throw new IOException("Error : ~cidrange contains an unexpected operator : "
// + ((Operator)nextToken).op);
// }
// break;
// }
// byte[] startCode = (byte[])nextToken;
// int start = createIntFromBytes(startCode);
// byte[] endCode = (byte[])parseNextToken(cmapStream);
// int end = createIntFromBytes(endCode);
// int mappedCode = (Integer)parseNextToken(cmapStream);
// if (startCode.length <= 2 && endCode.length <= 2)
// {
// result.addCIDRange((char)start, (char)end, mappedCode);
// }
// else
// {
// // TODO Is this even possible?
// int endOfMappings = mappedCode + end - start;
// while (mappedCode <= endOfMappings)
// {
// int mappedCID = createIntFromBytes(startCode);
// result.addCIDMapping(mappedCode++, mappedCID);
// increment(startCode);
// }
// }
// }
//}
//private void parseBegincidchar(Number cosCount, PushbackInputStream cmapStream, CMap result)
//{
// for (int j = 0; j < cosCount.intValue(); j++)
// {
// Object nextToken = parseNextToken(cmapStream);
// if (nextToken instanceof Operator)
// {
// if (!((Operator)nextToken).op.equals("endcidchar"))
// {
// throw new IOException("Error : ~cidchar contains an unexpected operator : "
// + ((Operator)nextToken).op);
// }
// break;
// }
// byte[] inputCode = (byte[])nextToken;
// int mappedCode = (Integer)parseNextToken(cmapStream);
// int mappedCID = createIntFromBytes(inputCode);
// result.addCIDMapping(mappedCode, mappedCID);
// }
//}
//private void parseBeginbfrange(Number cosCount, PushbackInputStream cmapStream, CMap result)
//{
// for (int j = 0; j < cosCount.intValue(); j++)
// {
// Object nextToken = parseNextToken(cmapStream);
// if (nextToken instanceof Operator)
// {
// if (!((Operator)nextToken).op.equals("endbfrange"))
// {
// throw new IOException("Error : ~bfrange contains an unexpected operator : "
// + ((Operator)nextToken).op);
// }
// break;
// }
// byte[] startCode = (byte[])nextToken;
// byte[] endCode = (byte[])parseNextToken(cmapStream);
// nextToken = parseNextToken(cmapStream);
// List<byte[]> array = null;
// byte[] tokenBytes;
// if (nextToken instanceof List<?>)
// {
// array = (List<byte[]>)nextToken;
// if (array.isEmpty())
// {
// continue;
// }
// tokenBytes = array.get(0);
// }
// else
// {
// tokenBytes = (byte[])nextToken;
// }
// if (tokenBytes == null || tokenBytes.length == 0)
// {
// // PDFBOX-3450: ignore <>
// // PDFBOX-3807: ignore null
// continue;
// }
// boolean done = false;
// int arrayIndex = 0;
// while (!done)
// {
// if (compare(startCode, endCode) >= 0)
// {
// done = true;
// }
// String value = createStringFromBytes(tokenBytes);
// result.addCharMapping(startCode, value);
// increment(startCode);
// if (array == null)
// {
// increment(tokenBytes);
// }
// else
// {
// arrayIndex++;
// if (arrayIndex < array.size())
// {
// tokenBytes = array.get(arrayIndex);
// }
// }
// }
// }
//}
///**
// * Returns an input stream containing the given "use" CMap.
// *
// * @param name Name of the given "use" CMap resource.
// * @throws IOException if the CMap resource doesn't exist or if there is an error opening its
// * stream.
// */
//protected InputStream getExternalCMap(String name)
//{
// URL url = getClass().getResource(name);
// if (url == null)
// {
// throw new IOException("Error: Could not find referenced cmap stream " + name);
// }
// return url.openStream();
//}
//private Object parseNextToken(PushbackInputStream is)
//{
// Object retval = null;
// int nextByte = is.read();
// // skip whitespace
// while (nextByte == 0x09 || nextByte == 0x20 || nextByte == 0x0D || nextByte == 0x0A)
// {
// nextByte = is.read();
// }
// switch (nextByte)
// {
// case '%':
// {
// // header operations, for now return the entire line
// // may need to smarter in the future
// StringBuilder buffer = new StringBuilder();
// buffer.append((char)nextByte);
// readUntilEndOfLine(is, buffer);
// retval = buffer.toString();
// break;
// }
// case '(':
// {
// StringBuilder buffer = new StringBuilder();
// int stringByte = is.read();
// while (stringByte != -1 && stringByte != ')')
// {
// buffer.append((char)stringByte);
// stringByte = is.read();
// }
// retval = buffer.toString();
// break;
// }
// case '>':
// {
// int secondCloseBrace = is.read();
// if (secondCloseBrace == '>')
// {
// retval = MARK_END_OF_DICTIONARY;
// }
// else
// {
// throw new IOException("Error: expected the end of a dictionary.");
// }
// break;
// }
// case ']':
// {
// retval = MARK_END_OF_ARRAY;
// break;
// }
// case '[':
// {
// List<Object> list = new ArrayList<>();
// Object nextToken = parseNextToken(is);
// while (nextToken != null && !MARK_END_OF_ARRAY.equals(nextToken))
// {
// list.add(nextToken);
// nextToken = parseNextToken(is);
// }
// retval = list;
// break;
// }
// case '<':
// {
// int theNextByte = is.read();
// if (theNextByte == '<')
// {
// Map<String, Object> result = new HashMap<>();
// // we are reading a dictionary
// Object key = parseNextToken(is);
// while (key instanceof LiteralName && !MARK_END_OF_DICTIONARY.equals(key))
// {
// Object value = parseNextToken(is);
// result.put(((LiteralName)key).name, value);
// key = parseNextToken(is);
// }
// retval = result;
// }
// else
// {
// // won't read more than 512 bytes
// int multiplyer = 16;
// int bufferIndex = -1;
// while (theNextByte != -1 && theNextByte != '>')
// {
// int intValue = 0;
// if (theNextByte >= '0' && theNextByte <= '9')
// {
// intValue = theNextByte - '0';
// }
// else if (theNextByte >= 'A' && theNextByte <= 'F')
// {
// intValue = 10 + theNextByte - 'A';
// }
// else if (theNextByte >= 'a' && theNextByte <= 'f')
// {
// intValue = 10 + theNextByte - 'a';
// }
// // all kind of whitespaces may occur in malformed CMap files
// // see PDFBOX-2035
// else if (isWhitespaceOrEOF(theNextByte))
// {
// // skipping whitespaces
// theNextByte = is.read();
// continue;
// }
// else
// {
// throw new IOException("Error: expected hex character and not " + (char)theNextByte + ":"
// + theNextByte);
// }
// intValue *= multiplyer;
// if (multiplyer == 16)
// {
// bufferIndex++;
// tokenParserByteBuffer[bufferIndex] = 0;
// multiplyer = 1;
// }
// else
// {
// multiplyer = 16;
// }
// tokenParserByteBuffer[bufferIndex] += intValue;
// theNextByte = is.read();
// }
// byte[] finalResult = new byte[bufferIndex + 1];
// System.arraycopy(tokenParserByteBuffer, 0, finalResult, 0, bufferIndex + 1);
// retval = finalResult;
// }
// break;
// }
// case '/':
// {
// StringBuilder buffer = new StringBuilder();
// int stringByte = is.read();
// while (!isWhitespaceOrEOF(stringByte) && !isDelimiter(stringByte))
// {
// buffer.append((char)stringByte);
// stringByte = is.read();
// }
// if (isDelimiter(stringByte))
// {
// is.unread(stringByte);
// }
// retval = new LiteralName(buffer.toString());
// break;
// }
// case -1:
// {
// // EOF returning null
// break;
// }
// case '0':
// case '1':
// case '2':
// case '3':
// case '4':
// case '5':
// case '6':
// case '7':
// case '8':
// case '9':
// {
// StringBuilder buffer = new StringBuilder();
// buffer.append((char)nextByte);
// nextByte = is.read();
// while (!isWhitespaceOrEOF(nextByte) && (Character.isDigit((char)nextByte) || nextByte == '.'))
// {
// buffer.append((char)nextByte);
// nextByte = is.read();
// }
// is.unread(nextByte);
// String value = buffer.toString();
// if (value.indexOf('.') >= 0)
// {
// retval = Double.valueOf(value);
// }
// else
// {
// retval = Integer.valueOf(value);
// }
// break;
// }
// default:
// {
// StringBuilder buffer = new StringBuilder();
// buffer.append((char)nextByte);
// nextByte = is.read();
// // newline separator may be missing in malformed CMap files
// // see PDFBOX-2035
// while (!isWhitespaceOrEOF(nextByte) && !isDelimiter(nextByte) && !Character.isDigit(nextByte))
// {
// buffer.append((char)nextByte);
// nextByte = is.read();
// }
// if (isDelimiter(nextByte) || Character.isDigit(nextByte))
// {
// is.unread(nextByte);
// }
// retval = new Operator(buffer.toString());
// break;
// }
// }
// return retval;
//}
//private void readUntilEndOfLine(InputStream is, StringBuilder buf)
//{
// int nextByte = is.read();
// while (nextByte != -1 && nextByte != 0x0D && nextByte != 0x0A)
// {
// buf.append((char)nextByte);
// nextByte = is.read();
// }
//}
//private boolean isWhitespaceOrEOF(int aByte)
//{
// return aByte == -1 || aByte == 0x20 || aByte == 0x0D || aByte == 0x0A;
//}
///** Is this a standard PDF delimiter character? */
//private boolean isDelimiter(int aByte)
//{
// switch (aByte)
// {
// case '(':
// case ')':
// case '<':
// case '>':
// case '[':
// case ']':
// case '{':
// case '}':
// case '/':
// case '%':
// return true;
// default:
// return false;
// }
//}
//private void increment(byte[] data)
//{
// increment(data, data.length - 1);
//}
//private void increment(byte[] data, int position)
//{
// if (position > 0 && (data[position] & 0xFF) == 255)
// {
// data[position] = 0;
// increment(data, position - 1);
// }
// else
// {
// data[position] = (byte)(data[position] + 1);
// }
//}
//private int createIntFromBytes(byte[] bytes)
//{
// int intValue = bytes[0] & 0xFF;
// if (bytes.length == 2)
// {
// intValue <<= 8;
// intValue += bytes[1] & 0xFF;
// }
// return intValue;
//}
//private String createStringFromBytes(byte[] bytes)
//{
// return new String(bytes, bytes.length == 1 ? Charsets.ISO_8859_1 : Charsets.UTF_16BE);
// }
// private int compare(byte[] first, byte[] second)
//{
// for (int i = 0; i < first.length; i++)
// {
// if (first[i] == second[i])
// {
// continue;
// }
// if ((first[i] & 0xFF) < (second[i] & 0xFF))
// {
// return -1;
// }
// else
// {
// return 1;
// }
// }
// return 0;
//}
///**
// * Internal class.
// */
//private static final class LiteralName
//{
// private String name;
// private LiteralName(String theName)
// {
// name = theName;
// }
//}
///**
// * Internal class.
// */
//private static final class Operator
//{
// private String op;
// private Operator(String theOp)
// {
// op = theOp;
// }
//}
// }
//}

View File

@@ -1,14 +1,14 @@
namespace UglyToad.Pdf.Fonts.Parser
{
using System;
using Cmap;
using CidFonts;
using ContentStream;
using ContentStream.TypedAccessors;
using Cos;
public class CharacterIdentifierFontParser
internal class CharacterIdentifierFontParser
{
public CharacterIdentifierFont Parse(ContentStreamDictionary dictionary, bool isLenientParsing)
public CharacterIdentifierFont Parse(PdfDictionary dictionary, bool isLenientParsing)
{
if (dictionary == null)
{

View File

@@ -0,0 +1,10 @@
namespace UglyToad.Pdf.Fonts.Parser.Handlers
{
using ContentStream;
using Pdf.Parser;
internal interface IFontHandler
{
IFont Generate(PdfDictionary dictionary, ParsingArguments parsingArguments);
}
}

View File

@@ -1,16 +1,24 @@
namespace UglyToad.Pdf.Fonts.Parser
namespace UglyToad.Pdf.Fonts.Parser.Handlers
{
using System;
using Cmap;
using ContentStream;
using Cos;
using Filters;
using IO;
using Parts;
using Pdf.Parser;
using Util.JetBrains.Annotations;
internal class Type0FontHandler : IFontHandler
{
public IFont Generate(ContentStreamDictionary dictionary, ParsingArguments arguments)
private readonly CidFontFactory cidFontFactory;
public Type0FontHandler(CidFontFactory cidFontFactory)
{
this.cidFontFactory = cidFontFactory;
}
public IFont Generate(PdfDictionary dictionary, ParsingArguments arguments)
{
var dynamicParser = arguments.Get<DynamicParser>();
@@ -19,6 +27,11 @@
if (TryGetFirstDescendant(dictionary, out var descendantObject))
{
var parsed = dynamicParser.Parse(arguments, descendantObject, false);
if (parsed is PdfDictionary descendantFontDictionary)
{
ParseDescendant(descendantFontDictionary, arguments);
}
}
CMap toUnicodeCMap = null;
@@ -46,10 +59,8 @@
return font;
}
[CanBeNull]
private bool TryGetFirstDescendant(ContentStreamDictionary dictionary, out CosObject descendant)
private static bool TryGetFirstDescendant(PdfDictionary dictionary, out CosObject descendant)
{
descendant = null;
@@ -72,10 +83,16 @@
return false;
}
}
internal interface IFontHandler
{
IFont Generate(ContentStreamDictionary dictionary, ParsingArguments parsingArguments);
private void ParseDescendant(PdfDictionary dictionary, ParsingArguments arguments)
{
var type = dictionary.GetName(CosName.TYPE);
if (!CosName.FONT.Equals(type))
{
throw new InvalidOperationException($"Expected \'Font\' dictionary but found \'{type.Name}\'");
}
cidFontFactory.Generate(dictionary, arguments, arguments.IsLenientParsing);
}
}
}

View File

@@ -0,0 +1,197 @@
namespace UglyToad.Pdf.Fonts.Parser.Parts
{
using System;
using System.Collections.Generic;
using System.IO;
using CidFonts;
using ContentStream;
using Cos;
using Filters;
using Geometry;
using Pdf.Parser;
using Util;
internal class CidFontFactory
{
private readonly FontDescriptorFactory descriptorFactory;
public CidFontFactory(FontDescriptorFactory descriptorFactory)
{
this.descriptorFactory = descriptorFactory;
}
public ICidFont Generate(PdfDictionary dictionary, ParsingArguments arguments, bool isLenientParsing)
{
var type = dictionary.GetName(CosName.TYPE);
if (!CosName.FONT.Equals(type))
{
throw new InvalidOperationException($"Expected \'Font\' dictionary but found \'{type.Name}\'");
}
var widths = ReadWidths(dictionary);
var verticalWritingMetrics = ReadVerticalDisplacements(dictionary);
FontDescriptor descriptor = null;
if (TryGetFontDescriptor(dictionary, arguments, out var descriptorDictionary))
{
descriptor = descriptorFactory.Generate(descriptorDictionary, arguments.IsLenientParsing);
}
ReadDescriptorFile(descriptor, arguments);
var subType = dictionary.GetName(CosName.SUBTYPE);
if (CosName.CID_FONT_TYPE0.Equals(subType))
{
//return new PDCIDFontType0(dictionary, parent);
}
if (CosName.CID_FONT_TYPE2.Equals(subType))
{
//return new PDCIDFontType2(dictionary, parent);
}
return null;
}
private static bool TryGetFontDescriptor(PdfDictionary dictionary, ParsingArguments arguments,
out PdfDictionary descriptorDictionary)
{
descriptorDictionary = null;
if (!dictionary.TryGetValue(CosName.FONT_DESC, out var baseValue) || !(baseValue is CosObject obj))
{
return false;
}
var descriptorObj = arguments.Get<DynamicParser>().Parse(arguments, obj, false);
if (!(descriptorObj is PdfDictionary descriptor))
{
return false;
}
descriptorDictionary = descriptor;
return true;
}
private static void ReadDescriptorFile(FontDescriptor descriptor, ParsingArguments arguments)
{
if (descriptor?.FontFile == null)
{
return;
}
var fontFileStream = arguments.Get<DynamicParser>().Parse(arguments, descriptor.FontFile.ObjectKey, false) as RawCosStream;
if (fontFileStream == null)
{
return;
}
var fontFile = fontFileStream.Decode(arguments.Get<IFilterProvider>());
}
private static IReadOnlyDictionary<int, decimal> ReadWidths(PdfDictionary dict)
{
var widths = new Dictionary<int, decimal>();
if (!dict.TryGetItemOfType(CosName.W, out COSArray widthArray))
{
return widths;
}
int size = widthArray.size();
int counter = 0;
while (counter < size)
{
var firstCode = (ICosNumber)widthArray.getObject(counter++);
var next = widthArray.getObject(counter++);
if (next is COSArray array)
{
int startRange = firstCode.AsInt();
int arraySize = array.size();
for (int i = 0; i < arraySize; i++)
{
var width = (ICosNumber)array.getObject(i);
widths[startRange + i] = width.AsDecimal();
}
}
else
{
var secondCode = (ICosNumber)next;
var rangeWidth = (ICosNumber)widthArray.getObject(counter++);
int startRange = firstCode.AsInt();
int endRange = secondCode.AsInt();
var width = rangeWidth.AsDecimal();
for (var i = startRange; i <= endRange; i++)
{
widths[i] = width;
}
}
}
return widths;
}
private VerticalWritingMetrics ReadVerticalDisplacements(PdfDictionary dict)
{
var verticalDisplacements = new Dictionary<int, decimal>();
var positionVectors = new Dictionary<int, PdfVector>();
VerticalVectorComponents dw2;
if (!dict.TryGetItemOfType(CosName.DW2, out COSArray arrayVerticalComponents))
{
dw2 = new VerticalVectorComponents(880, -1000);
}
else
{
var position = ((ICosNumber)arrayVerticalComponents.get(0)).AsDecimal();
var displacement = ((ICosNumber)arrayVerticalComponents.get(1)).AsDecimal();
dw2 = new VerticalVectorComponents(position, displacement);
}
// vertical metrics for individual CIDs.
if (dict.TryGetItemOfType(CosName.W2, out COSArray w2))
{
for (var i = 0; i < w2.size(); i++)
{
var c = (ICosNumber)w2.get(i);
var next = w2.get(++i);
if (next is COSArray array)
{
for (int j = 0; j < array.size(); j++)
{
int cid = c.AsInt() + j;
var w1y = (ICosNumber)array.get(j);
var v1x = (ICosNumber)array.get(++j);
var v1y = (ICosNumber)array.get(++j);
verticalDisplacements[cid] = w1y.AsDecimal();
positionVectors[cid] = new PdfVector(v1x.AsDecimal(), v1y.AsDecimal());
}
}
else
{
int first = c.AsInt();
int last = ((ICosNumber)next).AsInt();
var w1y = (ICosNumber)w2.get(++i);
var v1x = (ICosNumber)w2.get(++i);
var v1y = (ICosNumber)w2.get(++i);
for (var cid = first; cid <= last; cid++)
{
verticalDisplacements[cid] = w1y.AsDecimal();
positionVectors[cid] = new PdfVector(v1x.AsDecimal(), v1y.AsDecimal());
}
}
}
}
return new VerticalWritingMetrics(dw2, verticalDisplacements, positionVectors);
}
}
}

View File

@@ -0,0 +1,171 @@
namespace UglyToad.Pdf.Fonts.Parser.Parts
{
using System;
using ContentStream;
using ContentStream.TypedAccessors;
using Cos;
using Geometry;
using Util.JetBrains.Annotations;
internal class FontDescriptorFactory
{
public FontDescriptor Generate(PdfDictionary dictionary, bool isLenientParsing)
{
if (dictionary == null)
{
throw new ArgumentNullException(nameof(dictionary));
}
var name = GetFontName(dictionary, isLenientParsing);
var family = GetFontFamily(dictionary);
var stretch = GetFontStretch(dictionary);
var flags = GetFlags(dictionary, isLenientParsing);
var bounding = GetBoundingBox(dictionary);
var charSet = GetCharSet(dictionary);
var fontFile = GetFontFile(dictionary);
return new FontDescriptor(name, flags)
{
FontFamily = family,
Stretch = stretch,
FontWeight = dictionary.GetDecimalOrDefault(CosName.FONT_WEIGHT, 0),
BoundingBox = bounding,
ItalicAngle = dictionary.GetDecimalOrDefault(CosName.ITALIC_ANGLE, 0),
Ascent = dictionary.GetDecimalOrDefault(CosName.ASCENT, 0),
Descent = dictionary.GetDecimalOrDefault(CosName.DESCENT, 0),
Leading = dictionary.GetDecimalOrDefault(CosName.LEADING, 0),
CapHeight = Math.Abs(dictionary.GetDecimalOrDefault(CosName.CAP_HEIGHT, 0)),
XHeight = Math.Abs(dictionary.GetDecimalOrDefault(CosName.XHEIGHT, 0)),
StemVertical = dictionary.GetDecimalOrDefault(CosName.STEM_V, 0),
StemHorizontal = dictionary.GetDecimalOrDefault(CosName.STEM_H, 0),
AverageWidth = dictionary.GetDecimalOrDefault(CosName.AVG_WIDTH, 0),
MaxWidth = dictionary.GetDecimalOrDefault(CosName.MAX_WIDTH, 0),
MissingWidth = dictionary.GetDecimalOrDefault(CosName.MISSING_WIDTH, 0),
FontFile = fontFile,
CharSet = charSet
};
}
private static CosName GetFontName(PdfDictionary dictionary, bool isLenientParsing)
{
if (!dictionary.TryGetName(CosName.FONT_NAME, out var name))
{
if (isLenientParsing)
{
name = CosName.Create(string.Empty);
}
else
{
throw new InvalidOperationException("Could not parse the font descriptor, could not retrieve the font name. " + dictionary);
}
}
return name;
}
private static string GetFontFamily(PdfDictionary dictionary)
{
if (dictionary.TryGetItemOfType<CosString>(CosName.FONT_FAMILY, out var value))
{
return value.GetString();
}
return string.Empty;
}
private static FontStretch GetFontStretch(PdfDictionary dictionary)
{
if (!dictionary.TryGetName(CosName.FONT_STRETCH, out var stretch))
{
return FontStretch.Normal;
}
return stretch.ConvertToFontStretch();
}
private static FontFlags GetFlags(PdfDictionary dictionary, bool isLenientParsing)
{
var flags = dictionary.GetIntOrDefault(CosName.FLAGS, -1);
if (flags == -1)
{
if (isLenientParsing)
{
flags = 0;
}
else
{
throw new InvalidOperationException("Font flags were not set correctly for the font descriptor: " + dictionary);
}
}
return (FontFlags) flags;
}
private static PdfRectangle GetBoundingBox(PdfDictionary dictionary)
{
if (!dictionary.TryGetItemOfType<COSArray>(CosName.FONT_BBOX, out var box))
{
return new PdfRectangle(0, 0, 0, 0);
}
if (box.Count != 4)
{
return new PdfRectangle(0, 0, 0, 0);
}
var x1 = box.getInt(0);
var y1 = box.getInt(1);
var x2 = box.getInt(2);
var y2 = box.getInt(3);
return new PdfRectangle(x1, y1, x2, y2);
}
private static string GetCharSet(PdfDictionary dictionary)
{
if (!dictionary.TryGetName(CosName.CHAR_SET, out var set))
{
return null;
}
return set.Name;
}
[CanBeNull]
private static DescriptorFontFile GetFontFile(PdfDictionary dictionary)
{
if (dictionary.TryGetValue(CosName.FONT_FILE, out var value))
{
if (!(value is CosObject obj))
{
throw new NotSupportedException("We currently expect the FontFile to be an object reference.");
}
return new DescriptorFontFile(obj.GetObjectKey(), DescriptorFontFile.FontFileType.Type1);
}
if (dictionary.TryGetValue(CosName.FONT_FILE2, out value))
{
if (!(value is CosObject obj))
{
throw new NotSupportedException("We currently expect the FontFile2 to be an object reference.");
}
return new DescriptorFontFile(obj.GetObjectKey(), DescriptorFontFile.FontFileType.TrueType);
}
if (dictionary.TryGetValue(CosName.FONT_FILE3, out value))
{
if (!(value is CosObject obj))
{
throw new NotSupportedException("We currently expect the FontFile3 to be an object reference.");
}
return new DescriptorFontFile(obj.GetObjectKey(), DescriptorFontFile.FontFileType.FromSubtype);
}
return null;
}
}
}

View File

@@ -1,4 +1,4 @@
namespace UglyToad.Pdf.Text
namespace UglyToad.Pdf.Fonts
{
public enum TextObjectComponentType
{

View File

@@ -540,7 +540,7 @@ namespace UglyToad.Pdf.Parser
if (endObjectKey.Equals(STREAM_string))
{
source.Rewind(OtherEncodings.StringAsLatin1Bytes(endObjectKey).Length);
if (pb is ContentStreamDictionary dict)
if (pb is PdfDictionary dict)
{
RawCosStream stream = streamParser.Parse(source, dict, isLenient);

View File

@@ -164,7 +164,7 @@
bool isLenientParsing,
out string endObjectKey)
{
if (currentBase is ContentStreamDictionary dictionary)
if (currentBase is PdfDictionary dictionary)
{
RawCosStream stream = streamParser.Parse(reader, dictionary, isLenientParsing);

View File

@@ -10,7 +10,7 @@
internal class PageParser
{
public Page Parse(int number, ContentStreamDictionary dictionary, ParsingArguments arguments)
public Page Parse(int number, PdfDictionary dictionary, ParsingArguments arguments)
{
if (dictionary == null)
{
@@ -33,7 +33,7 @@
internal class FontParser
{
public Font Parse(ContentStreamDictionary dictionary, ParsingArguments arguments)
public Font Parse(PdfDictionary dictionary, ParsingArguments arguments)
{
var type = dictionary.GetName(CosName.SUBTYPE);
@@ -54,7 +54,7 @@
internal class CompositeFontParser
{
public CompositeFont Parse(ContentStreamDictionary dictionary, ParsingArguments arguments)
public CompositeFont Parse(PdfDictionary dictionary, ParsingArguments arguments)
{
var descendants = dictionary.GetItemOrDefault(CosName.DESCENDANT_FONTS) as COSArray;
@@ -95,7 +95,7 @@
internal class SimpleFontParser
{
public SimpleFont Parse(ContentStreamDictionary dictionary, ParsingArguments arguments)
public SimpleFont Parse(PdfDictionary dictionary, ParsingArguments arguments)
{
return new SimpleFont();
}

View File

@@ -51,7 +51,7 @@
}
var dictionary = arguments.Container.Get<DynamicParser>()
.Parse(arguments, key, false) as ContentStreamDictionary;
.Parse(arguments, key, false) as PdfDictionary;
if (dictionary == null)
{

View File

@@ -7,7 +7,7 @@
internal class ResourceDictionaryParser
{
public ResourceDictionary Parse(ContentStreamDictionary dictionary, ParsingArguments arguments)
public ResourceDictionary Parse(PdfDictionary dictionary, ParsingArguments arguments)
{
var fontDictionary = dictionary.GetDictionaryOrDefault(CosName.FONT);

View File

@@ -1,6 +1,7 @@
namespace UglyToad.Pdf.Parser
{
using System;
using System.Diagnostics;
using Cos;
using IO;
using Logging;
@@ -20,6 +21,7 @@
public ILog Log { get; }
[DebuggerStepThrough]
public T Get<T>() => Container.Get<T>();
public ParsingArguments(IRandomAccessRead reader, CrossReferenceTable crossReferenceTable, ParsingCachingProviders cachingProviders, IContainer container, bool isLenientParsing)

View File

@@ -34,7 +34,7 @@
this.nameParser = nameParser ?? throw new ArgumentNullException();
}
public ContentStreamDictionary Parse(IRandomAccessRead reader, CosBaseParser baseParser, CosObjectPool pool)
public PdfDictionary Parse(IRandomAccessRead reader, CosBaseParser baseParser, CosObjectPool pool)
{
if (reader == null)
{
@@ -55,7 +55,7 @@
ReadHelper.ReadExpectedChar(reader, '<');
ReadHelper.SkipSpaces(reader);
var dictionary = new ContentStreamDictionary();
var dictionary = new PdfDictionary();
var done = false;
while (!done)
@@ -81,7 +81,7 @@
default:
if (ReadUntilEnd(reader))
{
return new ContentStreamDictionary();
return new PdfDictionary();
}
break;
}

View File

@@ -32,7 +32,7 @@
this.log = log;
}
public RawCosStream Parse(IRandomAccessRead reader, ContentStreamDictionary streamDictionary, bool isLenientParsing)
public RawCosStream Parse(IRandomAccessRead reader, PdfDictionary streamDictionary, bool isLenientParsing)
{
RawCosStream result;

View File

@@ -135,7 +135,7 @@
return true;
}
private bool TryParseTrailer(IRandomAccessRead source, bool isLenientParsing, CosObjectPool pool, out ContentStreamDictionary trailer)
private bool TryParseTrailer(IRandomAccessRead source, bool isLenientParsing, CosObjectPool pool, out PdfDictionary trailer)
{
trailer = null;
// parse the last trailer.
@@ -187,7 +187,7 @@
// Acrobat reader can also deal with this.
ReadHelper.SkipSpaces(source);
ContentStreamDictionary parsedTrailer = dictionaryParser.Parse(source, baseParser, pool);
PdfDictionary parsedTrailer = dictionaryParser.Parse(source, baseParser, pool);
trailer = parsedTrailer;

View File

@@ -68,7 +68,7 @@
throw new InvalidOperationException($"Expected trailer object at position: {reader.GetPosition()}");
}
ContentStreamDictionary trailer = tableBuilder.Dictionary;
PdfDictionary trailer = tableBuilder.Dictionary;
CrossReferenceTablePart streamPart = null;
// check for a XRef stream, it may contain some object ids of compressed objects
if (trailer.ContainsKey(CosName.XREF_STM))
@@ -174,7 +174,7 @@
ReadHelper.ReadExpectedString(reader, "obj", true);
ContentStreamDictionary dict = dictionaryParser.Parse(reader, baseParser, pool);
PdfDictionary dict = dictionaryParser.Parse(reader, baseParser, pool);
RawCosStream xrefStream = streamParser.Parse(reader, dict, isLenientParsing);
CrossReferenceTablePart xrefTablePart = crossReferenceStreamParser.Parse(objByteOffset, xrefStream);

View File

@@ -276,7 +276,7 @@
ReadHelper.ReadExpectedString(source, "obj", true);
// check the dictionary to avoid false positives
ContentStreamDictionary dict = dictionaryParser.Parse(source, baseParser, pool);
PdfDictionary dict = dictionaryParser.Parse(source, baseParser, pool);
source.Seek(startXRefOffset);
if (dict.IsType(CosName.XREF))

View File

@@ -53,7 +53,7 @@
var root = ParseTrailer(reader, crossReferenceTable, dynamicParser, bruteForceSearcher, pool,
isLenientParsing);
if (!(root is ContentStreamDictionary rootDictionary))
if (!(root is PdfDictionary rootDictionary))
{
throw new InvalidOperationException("Expected root dictionary, but got this: " + root);
}