#9 add support for cff cid fonts, currently bounding box and width are calculated incorrectly.

This commit is contained in:
Eliot Jones
2019-01-07 20:52:42 +00:00
parent cdf5546a1b
commit b6a528a97d
9 changed files with 65 additions and 17 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

View File

@@ -1,6 +1,5 @@
namespace UglyToad.PdfPig.Tests.Integration
{
// using System.IO;
using Xunit;
/// <summary>
@@ -11,10 +10,6 @@
[Fact]
public void Tests()
{
//using (var document = PdfDocument.Open(File.ReadAllBytes(@"C:\Users\eliot\Downloads\Motor Insurance claim form.pdf"), new ParsingOptions { UseLenientParsing = false }))
//{
// var page1 = document.GetPage(1);
//}
}
}
}

View File

@@ -12,6 +12,7 @@
private const string SinglePageFormattedType0Content = "Type0 Font";
private const string SinglePageType1Content = "ICML03-081";
private const string SingleInkscapePage = "Single Page Simple - from inkscape";
private const string MotorInsuranceClaim = "Motor Insurance claim form";
private const string PigProduction = "Pig Production Handbook";
private static string GetFilename(string name)
@@ -80,6 +81,12 @@
Run("Multiple Page - from Mortality Statistics");
}
[Fact]
public void MotorInsuranceClaimForm()
{
Run(MotorInsuranceClaim, 841);
}
private static void Run(string file, int imageHeight = 792)
{
var pdfFileName = GetFilename(file);

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Fonts.CidFonts
{
using System.Collections.Generic;
using Core;
using Geometry;
using Tokens;
@@ -19,10 +20,11 @@
public TransformationMatrix FontMatrix { get; }
public CidFontType CidFontType => CidFontType.Type0;
public FontDescriptor Descriptor { get; }
public IReadOnlyDictionary<int, decimal> Widths { get; }
public Type0CidFont(ICidFontProgram fontProgram, NameToken type, NameToken subType, NameToken baseFont,
public Type0CidFont(ICidFontProgram fontProgram, NameToken type, NameToken subType, NameToken baseFont,
CharacterIdentifierSystemInfo systemInfo,
FontDescriptor descriptor)
FontDescriptor descriptor, IReadOnlyDictionary<int, decimal> widths)
{
this.fontProgram = fontProgram;
Type = type;
@@ -32,21 +34,28 @@
var scale = 1 / (decimal)(fontProgram?.GetFontMatrixMultiplier() ?? 1000);
FontMatrix = TransformationMatrix.FromValues(scale, 0, 0, scale, 0, 0);
Descriptor = descriptor;
Widths = widths;
}
public decimal GetWidthFromFont(int characterCode)
{
throw new System.NotImplementedException();
return GetWidthFromDictionary(characterCode);
}
public decimal GetWidthFromDictionary(int cid)
{
throw new System.NotImplementedException();
return Widths[cid];
}
public PdfRectangle GetBoundingBox(int characterIdentifier)
{
throw new System.NotImplementedException();
return new PdfRectangle(0, 0, Widths[characterIdentifier], 0);
if (fontProgram.TryGetBoundingBox(characterIdentifier, out var boundingBox))
{
return boundingBox;
}
return new PdfRectangle(0, 0, 250, 0);
}
}
}

View File

@@ -1,6 +1,7 @@
namespace UglyToad.PdfPig.Fonts.CompactFontFormat
{
using System;
using System.Collections.Generic;
using Charsets;
using CharStrings;
using Dictionaries;
@@ -34,4 +35,26 @@
return result;
}
}
internal class CompactFontFormatCidFont : CompactFontFormatFont
{
public IReadOnlyList<CompactFontFormatTopLevelDictionary> FontDictionaries { get; }
public IReadOnlyList<CompactFontFormatPrivateDictionary> PrivateDictionaries { get; }
public IReadOnlyList<CompactFontFormatIndex> LocalSubroutines { get; }
public ICompactFontFormatFdSelect FdSelect { get; }
public CompactFontFormatCidFont(CompactFontFormatTopLevelDictionary topDictionary, CompactFontFormatPrivateDictionary privateDictionary,
ICompactFontFormatCharset charset,
Union<Type1CharStrings, Type2CharStrings> charStrings,
IReadOnlyList<CompactFontFormatTopLevelDictionary> fontDictionaries,
IReadOnlyList<CompactFontFormatPrivateDictionary> privateDictionaries,
IReadOnlyList<CompactFontFormatIndex> localSubroutines,
ICompactFontFormatFdSelect fdSelect) : base(topDictionary, privateDictionary, charset, charStrings)
{
FontDictionaries = fontDictionaries;
PrivateDictionaries = privateDictionaries;
LocalSubroutines = localSubroutines;
FdSelect = fdSelect;
}
}
}

View File

@@ -62,7 +62,8 @@
public bool TryGetBoundingBox(int characterIdentifier, out PdfRectangle boundingBox)
{
throw new NotImplementedException();
boundingBox = new PdfRectangle(0, 0, 250, 0);
return true;
}
public bool TryGetBoundingBox(int characterIdentifier, Func<int, int> characterIdentifierToGlyphIndex, out PdfRectangle boundingBox)

View File

@@ -110,7 +110,7 @@
if (topDictionary.IsCidFont)
{
ReadCidFont(data, topDictionary, charStringIndex.Count, stringIndex);
return ReadCidFont(data, topDictionary, charStringIndex.Count, stringIndex, privateDictionary, charset, Union<Type1CharStrings, Type2CharStrings>.Two(charStrings));
}
return new CompactFontFormatFont(topDictionary, privateDictionary, charset, Union<Type1CharStrings, Type2CharStrings>.Two(charStrings));
@@ -184,9 +184,12 @@
return "SID" + index;
}
private void ReadCidFont(CompactFontFormatData data, CompactFontFormatTopLevelDictionary topLevelDictionary,
private CompactFontFormatCidFont ReadCidFont(CompactFontFormatData data, CompactFontFormatTopLevelDictionary topLevelDictionary,
int numberOfGlyphs,
IReadOnlyList<string> stringIndex)
IReadOnlyList<string> stringIndex,
CompactFontFormatPrivateDictionary privateDictionary,
ICompactFontFormatCharset charset,
Union<Type1CharStrings, Type2CharStrings> charstrings)
{
var offset = topLevelDictionary.CidFontOperators.FontDictionaryArray;
@@ -194,6 +197,9 @@
var fontDict = indexReader.ReadDictionaryData(data);
var privateDictionaries = new List<CompactFontFormatPrivateDictionary>();
var fontDictionaries = new List<CompactFontFormatTopLevelDictionary>();
var fontLocalSubroutines = new List<CompactFontFormatIndex>();
foreach (var index in fontDict)
{
var topLevelDictionaryCid = topLevelDictionaryReader.Read(new CompactFontFormatData(index), stringIndex);
@@ -206,14 +212,18 @@
var privateDictionaryBytes = data.SnapshotPortion(topLevelDictionaryCid.PrivateDictionaryLocation.Value.Offset,
topLevelDictionaryCid.PrivateDictionaryLocation.Value.Size);
var privateDictionaryCid = privateDictionaryReader.Read(data, stringIndex);
var privateDictionaryCid = privateDictionaryReader.Read(privateDictionaryBytes, stringIndex);
// CFFParser.java line 625 - read the local subroutines.
if (privateDictionaryCid.LocalSubroutineOffset.HasValue && privateDictionaryCid.LocalSubroutineOffset.Value > 0)
{
data.Seek(topLevelDictionaryCid.PrivateDictionaryLocation.Value.Offset + privateDictionaryCid.LocalSubroutineOffset.Value);
var localSubroutines = indexReader.ReadDictionaryData(data);
fontLocalSubroutines.Add(localSubroutines);
}
fontDictionaries.Add(topLevelDictionaryCid);
privateDictionaries.Add(privateDictionaryCid);
}
data.Seek(topLevelDictionary.CidFontOperators.FontDictionarySelect);
@@ -236,6 +246,9 @@
default:
throw new InvalidFontFormatException($"Invalid Font Dictionary Select format: {format}.");
}
return new CompactFontFormatCidFont(topLevelDictionary, privateDictionary, charset, charstrings,
fontDictionaries, privateDictionaries, fontLocalSubroutines, fdSelect);
}
private static CompactFontFormat0FdSelect ReadFormat0FdSelect(CompactFontFormatData data, int numberOfGlyphs,

View File

@@ -61,7 +61,7 @@
var subType = dictionary.GetNameOrDefault(NameToken.Subtype);
if (NameToken.CidFontType0.Equals(subType))
{
return new Type0CidFont(fontProgram, type, subType, baseFont, systemInfo, descriptor);
return new Type0CidFont(fontProgram, type, subType, baseFont, systemInfo, descriptor, widths);
}
if (NameToken.CidFontType2.Equals(subType))
@@ -127,7 +127,7 @@
{
var bytes = str.Decode(filterProvider);
var font = compactFontFormatParser.Parse(new CompactFontFormatData(bytes));
throw new NotSupportedException($"Unsupported subtype for CID font {subtypeName}. Font: {font}");
return font;
}
if (subtypeName == NameToken.Type1C)