mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-10-15 19:54:52 +08:00
#9 add support for cff cid fonts, currently bounding box and width are calculated incorrectly.
This commit is contained in:
Binary file not shown.
After Width: | Height: | Size: 169 KiB |
Binary file not shown.
@@ -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);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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,
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user