#6 fix bugs with vlineto and hlineto and decoding of charsets. dump results of type 2 path decoding to file for visual verification while debugging

This commit is contained in:
Eliot Jones
2018-11-17 20:21:59 +00:00
parent aa6f55c9ad
commit 8f5c0fc77b
8 changed files with 49 additions and 36 deletions

View File

@@ -146,7 +146,7 @@ namespace UglyToad.PdfPig.Fonts
var path = $"<path d='{glyph}' stroke='cyan' stroke-width='3'></path>"; var path = $"<path d='{glyph}' stroke='cyan' stroke-width='3'></path>";
var bboxRect = bbox.HasValue ? BboxToRect(bbox.Value, "yellow") : string.Empty; var bboxRect = bbox.HasValue ? BboxToRect(bbox.Value, "yellow") : string.Empty;
var others = string.Join(" ", bboxes.Select(x => BboxToRect(x, "gray"))); var others = string.Join(" ", bboxes.Select(x => BboxToRect(x, "gray")));
var result = $"<svg transform='scale(1, -1)' width='2000' height='2000'>{path} {bboxRect} {others}</svg>"; var result = $"<svg transform='scale(0.2, -0.2)' width='500' height='500'>{path} {bboxRect} {others}</svg>";
return result; return result;
} }

View File

@@ -2,6 +2,7 @@
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Charsets;
using Geometry; using Geometry;
using Util; using Util;
using Util.JetBrains.Annotations; using Util.JetBrains.Annotations;
@@ -118,22 +119,25 @@
*/ */
var isOdd = ctx.Stack.Length % 2 != 0; var isOdd = ctx.Stack.Length % 2 != 0;
var numberOfAdditionalLines = ctx.Stack.Length - (isOdd ? 1 : 0);
if (isOdd)
{
var dx1 = ctx.Stack.PopBottom(); var dx1 = ctx.Stack.PopBottom();
ctx.AddRelativeHorizontalLine(dx1); ctx.AddRelativeHorizontalLine(dx1);
var numberOfAdditionalLines = ctx.Stack.Length; for (var i = 0; i < numberOfAdditionalLines; i+= 2)
for (var i = 0; i < numberOfAdditionalLines; i++)
{ {
var isDeltaY = (isOdd && i % 2 == 0) || (!isOdd && i % 2 != 0); ctx.AddRelativeVerticalLine(ctx.Stack.PopBottom());
if (isDeltaY) ctx.AddRelativeHorizontalLine(ctx.Stack.PopBottom());
{ }
var dya = ctx.Stack.PopBottom();
ctx.AddRelativeVerticalLine(dya);
} }
else else
{ {
var dxa = ctx.Stack.PopBottom(); for (var i = 0; i < numberOfAdditionalLines; i+= 2)
ctx.AddRelativeHorizontalLine(dxa); {
ctx.AddRelativeHorizontalLine(ctx.Stack.PopBottom());
ctx.AddRelativeVerticalLine(ctx.Stack.PopBottom());
} }
} }
@@ -145,23 +149,25 @@
{ {
var isOdd = ctx.Stack.Length % 2 != 0; var isOdd = ctx.Stack.Length % 2 != 0;
var numberOfAdditionalLines = ctx.Stack.Length - (isOdd ? 1 : 0);
if (isOdd)
{
var dy1 = ctx.Stack.PopBottom(); var dy1 = ctx.Stack.PopBottom();
ctx.AddRelativeVerticalLine(dy1); ctx.AddRelativeVerticalLine(dy1);
var numberOfAdditionalLines = ctx.Stack.Length; for (var i = 0; i < numberOfAdditionalLines; i+=2)
for (var i = 0; i < numberOfAdditionalLines; i++)
{ {
var isDeltaY = (isOdd && i % 2 != 0) || (!isOdd && i % 2 == 0); ctx.AddRelativeHorizontalLine(ctx.Stack.PopBottom());
ctx.AddRelativeVerticalLine(ctx.Stack.PopBottom());
if (isDeltaY) }
{
var dya = ctx.Stack.PopBottom();
ctx.AddRelativeVerticalLine(dya);
} }
else else
{ {
var dxa = ctx.Stack.PopBottom(); for (var i = 0; i < numberOfAdditionalLines; i+=2)
ctx.AddRelativeHorizontalLine(dxa); {
ctx.AddRelativeVerticalLine(ctx.Stack.PopBottom());
ctx.AddRelativeHorizontalLine(ctx.Stack.PopBottom());
} }
} }
@@ -673,7 +679,7 @@
public static Type2CharStrings Parse([NotNull] IReadOnlyList<IReadOnlyList<byte>> charStringBytes, public static Type2CharStrings Parse([NotNull] IReadOnlyList<IReadOnlyList<byte>> charStringBytes,
[NotNull] CompactFontFormatIndex localSubroutines, [NotNull] CompactFontFormatIndex localSubroutines,
[NotNull] CompactFontFormatIndex globalSubroutines) [NotNull] CompactFontFormatIndex globalSubroutines, ICompactFontFormatCharset charset)
{ {
if (charStringBytes == null) if (charStringBytes == null)
{ {
@@ -690,12 +696,12 @@
throw new ArgumentNullException(nameof(globalSubroutines)); throw new ArgumentNullException(nameof(globalSubroutines));
} }
var charStrings = new Dictionary<int, Type2CharStrings.CommandSequence>(); var charStrings = new Dictionary<string, Type2CharStrings.CommandSequence>();
for (var i = 0; i < charStringBytes.Count; i++) for (var i = 0; i < charStringBytes.Count; i++)
{ {
var charString = charStringBytes[i]; var charString = charStringBytes[i];
var sequence = ParseSingle(charString); var sequence = ParseSingle(charString);
charStrings[i] = new Type2CharStrings.CommandSequence(sequence); charStrings[charset.GetNameByGlyphId(i)] = new Type2CharStrings.CommandSequence(sequence);
} }
return new Type2CharStrings(charStrings, new Dictionary<int, Type2CharStrings.CommandSequence>()); return new Type2CharStrings(charStrings, new Dictionary<int, Type2CharStrings.CommandSequence>());

View File

@@ -10,11 +10,11 @@
private readonly object locker = new object(); private readonly object locker = new object();
private readonly Dictionary<string, CharacterPath> glyphs = new Dictionary<string, CharacterPath>(); private readonly Dictionary<string, CharacterPath> glyphs = new Dictionary<string, CharacterPath>();
public IReadOnlyDictionary<int, CommandSequence> CharStrings { get; } public IReadOnlyDictionary<string, CommandSequence> CharStrings { get; }
public IReadOnlyDictionary<int, CommandSequence> Subroutines { get; } public IReadOnlyDictionary<int, CommandSequence> Subroutines { get; }
public Type2CharStrings(IReadOnlyDictionary<int, CommandSequence> charStrings, IReadOnlyDictionary<int, CommandSequence> subroutines) public Type2CharStrings(IReadOnlyDictionary<string, CommandSequence> charStrings, IReadOnlyDictionary<int, CommandSequence> subroutines)
{ {
CharStrings = charStrings ?? throw new ArgumentNullException(nameof(charStrings)); CharStrings = charStrings ?? throw new ArgumentNullException(nameof(charStrings));
Subroutines = subroutines ?? throw new ArgumentNullException(nameof(subroutines)); Subroutines = subroutines ?? throw new ArgumentNullException(nameof(subroutines));
@@ -30,7 +30,7 @@
return result; return result;
} }
if (!CharStrings.TryGetValue(0, out var sequence)) if (!CharStrings.TryGetValue(name, out var sequence))
{ {
throw new InvalidOperationException($"No charstring sequence with the name /{name} in this font."); throw new InvalidOperationException($"No charstring sequence with the name /{name} in this font.");
} }

View File

@@ -29,7 +29,7 @@
public virtual string GetNameByGlyphId(int glyphId) public virtual string GetNameByGlyphId(int glyphId)
{ {
throw new NotImplementedException(); return GlyphIdToStringIdAndName[glyphId].name;
} }
public virtual string GetNameByStringId(int stringId) public virtual string GetNameByStringId(int stringId)

View File

@@ -195,7 +195,7 @@
public string GetNameByGlyphId(int glyphId) public string GetNameByGlyphId(int glyphId)
{ {
throw new System.NotImplementedException(); return characterIdToStringIdAndName[glyphId].Value;
} }
public string GetNameByStringId(int stringId) public string GetNameByStringId(int stringId)

View File

@@ -116,7 +116,7 @@
public string GetNameByGlyphId(int glyphId) public string GetNameByGlyphId(int glyphId)
{ {
throw new System.NotImplementedException(); return characterIdToStringIdAndName[glyphId].Value;
} }
public string GetNameByStringId(int stringId) public string GetNameByStringId(int stringId)

View File

@@ -258,7 +258,7 @@
public string GetNameByGlyphId(int glyphId) public string GetNameByGlyphId(int glyphId)
{ {
throw new System.NotImplementedException(); return characterIdToStringIdAndName[glyphId].Value;
} }
public string GetNameByStringId(int stringId) public string GetNameByStringId(int stringId)

View File

@@ -3,7 +3,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using Charsets; using Charsets;
using CharStrings; using CharStrings;
using Dictionaries; using Dictionaries;
@@ -108,12 +110,11 @@
var numberInRange = format == 1 ? data.ReadCard8() : data.ReadCard16(); var numberInRange = format == 1 ? data.ReadCard8() : data.ReadCard16();
glyphToNamesAndStringId.Add((glyphId, firstSid, ReadString(firstSid, stringIndex))); glyphToNamesAndStringId.Add((glyphId, firstSid, ReadString(firstSid, stringIndex)));
glyphId++;
for (var i = 0; i < numberInRange; i++) for (var i = 0; i < numberInRange; i++)
{ {
glyphId++;
var sid = firstSid + i + 1; var sid = firstSid + i + 1;
glyphToNamesAndStringId.Add((glyphId, sid, ReadString(sid, stringIndex))); glyphToNamesAndStringId.Add((glyphId, sid, ReadString(sid, stringIndex)));
glyphId++;
} }
} }
@@ -142,7 +143,7 @@
case CompactFontFormatCharStringType.Type1: case CompactFontFormatCharStringType.Type1:
throw new NotImplementedException(); throw new NotImplementedException();
case CompactFontFormatCharStringType.Type2: case CompactFontFormatCharStringType.Type2:
charStrings = Type2CharStringParser.Parse(charStringIndex, localSubroutines, globalSubroutineIndex); charStrings = Type2CharStringParser.Parse(charStringIndex, localSubroutines, globalSubroutineIndex, charset);
break; break;
default: default:
throw new ArgumentOutOfRangeException($"Unexpected CharString type in CFF font: {topDictionary.CharStringType}."); throw new ArgumentOutOfRangeException($"Unexpected CharString type in CFF font: {topDictionary.CharStringType}.");
@@ -150,11 +151,17 @@
if (Debugger.IsAttached) if (Debugger.IsAttached)
{ {
var builder = new StringBuilder("<!DOCTYPE html><html><head></head><body>");
foreach (var pair in charStrings.CharStrings) foreach (var pair in charStrings.CharStrings)
{ {
var path = Type2CharStrings.Run(pair.Value); var path = Type2CharStrings.Run(pair.Value);
var svg = path.ToFullSvg(); var svg = path.ToFullSvg();
builder.AppendLine(svg);
} }
builder.Append("</body></html>");
File.WriteAllText(@"C:\git\index.html", builder.ToString());
} }
return new CompactFontFormatFont(topDictionary, privateDictionary, charset, Union<Type1CharStrings, Type2CharStrings>.Two(charStrings)); return new CompactFontFormatFont(topDictionary, privateDictionary, charset, Union<Type1CharStrings, Type2CharStrings>.Two(charStrings));