mirror of
https://github.com/UglyToad/PdfPig.git
synced 2026-03-10 00:23:29 +08:00
rename contentstreamdictionary to pdfdictionary. add initial structure for cid fonts
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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];
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -177,5 +177,10 @@ namespace UglyToad.Pdf.Cos
|
||||
{
|
||||
return (long) value;
|
||||
}
|
||||
|
||||
public decimal AsDecimal()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,5 +142,10 @@ namespace UglyToad.Pdf.Cos
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public decimal AsDecimal()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
public long Previous { get; set; }
|
||||
|
||||
public ContentStreamDictionary Dictionary { get; set; }
|
||||
public PdfDictionary Dictionary { get; set; }
|
||||
|
||||
public CrossReferenceType XRefType { get; set; }
|
||||
|
||||
|
||||
@@ -9,5 +9,7 @@
|
||||
int AsInt();
|
||||
|
||||
long AsLong();
|
||||
|
||||
decimal AsDecimal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
|
||||
public interface IDecodeParameterResolver
|
||||
{
|
||||
ContentStreamDictionary GetFilterParameters(ContentStreamDictionary streamDictionary, int index);
|
||||
PdfDictionary GetFilterParameters(PdfDictionary streamDictionary, int index);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,6 @@
|
||||
|
||||
public interface IFilter
|
||||
{
|
||||
byte[] Decode(byte[] input, ContentStreamDictionary streamDictionary, int filterIndex);
|
||||
byte[] Decode(byte[] input, PdfDictionary streamDictionary, int filterIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
43
src/UglyToad.Pdf/Fonts/CidFonts/CharacterIdentifierFont.cs
Normal file
43
src/UglyToad.Pdf/Fonts/CidFonts/CharacterIdentifierFont.cs
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace UglyToad.Pdf.Fonts.CidFonts
|
||||
{
|
||||
public class CharacterIdentifierToGlyphIdentifierMap
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
14
src/UglyToad.Pdf/Fonts/CidFonts/CidFontType.cs
Normal file
14
src/UglyToad.Pdf/Fonts/CidFonts/CidFontType.cs
Normal 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
|
||||
}
|
||||
}
|
||||
36
src/UglyToad.Pdf/Fonts/CidFonts/ICidFont.cs
Normal file
36
src/UglyToad.Pdf/Fonts/CidFonts/ICidFont.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
18
src/UglyToad.Pdf/Fonts/CidFonts/Type0CidFont.cs
Normal file
18
src/UglyToad.Pdf/Fonts/CidFonts/Type0CidFont.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
18
src/UglyToad.Pdf/Fonts/CidFonts/Type2CidFont.cs
Normal file
18
src/UglyToad.Pdf/Fonts/CidFonts/Type2CidFont.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
20
src/UglyToad.Pdf/Fonts/CidFonts/VerticalVectorComponents.cs
Normal file
20
src/UglyToad.Pdf/Fonts/CidFonts/VerticalVectorComponents.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
21
src/UglyToad.Pdf/Fonts/CidFonts/VerticalWritingMetrics.cs
Normal file
21
src/UglyToad.Pdf/Fonts/CidFonts/VerticalWritingMetrics.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
36
src/UglyToad.Pdf/Fonts/DescriptorFontFile.cs
Normal file
36
src/UglyToad.Pdf/Fonts/DescriptorFontFile.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
164
src/UglyToad.Pdf/Fonts/FontDescriptor.cs
Normal file
164
src/UglyToad.Pdf/Fonts/FontDescriptor.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
47
src/UglyToad.Pdf/Fonts/FontFlags.cs
Normal file
47
src/UglyToad.Pdf/Fonts/FontFlags.cs
Normal 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
|
||||
}
|
||||
}
|
||||
19
src/UglyToad.Pdf/Fonts/FontStretch.cs
Normal file
19
src/UglyToad.Pdf/Fonts/FontStretch.cs
Normal 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
|
||||
}
|
||||
}
|
||||
32
src/UglyToad.Pdf/Fonts/FontStretchExtensions.cs
Normal file
32
src/UglyToad.Pdf/Fonts/FontStretchExtensions.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
// }
|
||||
//}
|
||||
// }
|
||||
//}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
10
src/UglyToad.Pdf/Fonts/Parser/Handlers/IFontHandler.cs
Normal file
10
src/UglyToad.Pdf/Fonts/Parser/Handlers/IFontHandler.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
197
src/UglyToad.Pdf/Fonts/Parser/Parts/CidFontFactory.cs
Normal file
197
src/UglyToad.Pdf/Fonts/Parser/Parts/CidFontFactory.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
171
src/UglyToad.Pdf/Fonts/Parser/Parts/FontDescriptorFactory.cs
Normal file
171
src/UglyToad.Pdf/Fonts/Parser/Parts/FontDescriptorFactory.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace UglyToad.Pdf.Text
|
||||
namespace UglyToad.Pdf.Fonts
|
||||
{
|
||||
public enum TextObjectComponentType
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user