mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-08-20 09:21:57 +08:00
Merge pull request #240 from BobLd/type1-flex
Correct letter bbox for Type1 font/flexpoints - Fix #217
This commit is contained in:
commit
1d36098ec5
@ -3,6 +3,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using UglyToad.PdfPig.Core;
|
||||
using UglyToad.PdfPig.Fonts.Type1.CharStrings.Commands.PathConstruction;
|
||||
|
||||
/// <summary>
|
||||
/// Call other subroutine command. Arguments are pushed onto the PostScript interpreter operand stack then
|
||||
@ -23,13 +25,13 @@
|
||||
|
||||
public static bool TakeFromStackBottom { get; } = false;
|
||||
public static bool ClearsOperandStack { get; } = false;
|
||||
|
||||
|
||||
public static LazyType1Command Lazy { get; } = new LazyType1Command(Name, Run);
|
||||
|
||||
public static void Run(Type1BuildCharContext context)
|
||||
{
|
||||
var index = (int) context.Stack.PopTop();
|
||||
|
||||
var index = (int)context.Stack.PopTop();
|
||||
|
||||
// What it should do
|
||||
var numberOfArguments = (int)context.Stack.PopTop();
|
||||
var otherSubroutineArguments = new List<double>(numberOfArguments);
|
||||
@ -42,17 +44,44 @@
|
||||
{
|
||||
// Other subrs 0-2 implement flex
|
||||
case FlexEnd:
|
||||
{
|
||||
context.IsFlexing = false;
|
||||
// TODO: I don't really care about flexpoints, but we should probably handle them... one day.
|
||||
//if (context.FlexPoints.Count < 7)
|
||||
//{
|
||||
// throw new NotSupportedException("There must be at least 7 flex points defined by an other subroutine.");
|
||||
//}
|
||||
{
|
||||
// https://github.com/apache/pdfbox/blob/2c23d8b4e3ad61852f0b6ee2b95b907eefba1fcf/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharString.java#L339
|
||||
context.IsFlexing = false;
|
||||
if (context.FlexPoints.Count < 7)
|
||||
{
|
||||
throw new NotSupportedException("There must be at least 7 flex points defined by an other subroutine.");
|
||||
}
|
||||
|
||||
context.ClearFlexPoints();
|
||||
break;
|
||||
}
|
||||
// reference point is relative to start point
|
||||
PdfPoint reference = context.FlexPoints[0];
|
||||
reference = reference.Translate(context.CurrentPosition.X, context.CurrentPosition.Y);
|
||||
|
||||
// first point is relative to reference point
|
||||
PdfPoint first = context.FlexPoints[1];
|
||||
first = first.Translate(reference.X, reference.Y);
|
||||
|
||||
// make the first point relative to the start point
|
||||
first = first.Translate(-context.CurrentPosition.X, -context.CurrentPosition.Y);
|
||||
|
||||
context.Stack.Push(first.X);
|
||||
context.Stack.Push(first.Y);
|
||||
context.Stack.Push(context.FlexPoints[2].X);
|
||||
context.Stack.Push(context.FlexPoints[2].Y);
|
||||
context.Stack.Push(context.FlexPoints[3].X);
|
||||
context.Stack.Push(context.FlexPoints[3].Y);
|
||||
RelativeRCurveToCommand.Run(context);
|
||||
|
||||
context.Stack.Push(context.FlexPoints[4].X);
|
||||
context.Stack.Push(context.FlexPoints[4].Y);
|
||||
context.Stack.Push(context.FlexPoints[5].X);
|
||||
context.Stack.Push(context.FlexPoints[5].Y);
|
||||
context.Stack.Push(context.FlexPoints[6].X);
|
||||
context.Stack.Push(context.FlexPoints[6].Y);
|
||||
RelativeRCurveToCommand.Run(context);
|
||||
|
||||
context.ClearFlexPoints();
|
||||
break;
|
||||
}
|
||||
case FlexBegin:
|
||||
Debug.Assert(otherSubroutineArguments.Count == 0, "Flex begin should have no arguments.");
|
||||
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current point to (x, y) in absolute character space coordinates without performing a charstring moveto command.
|
||||
/// <para>This establishes the current point for a subsequent relative path building command.
|
||||
/// The 'setcurrentpoint' command is used only in conjunction with results from 'OtherSubrs' procedures.</para>
|
||||
/// </summary>
|
||||
internal static class SetCurrentPointCommand
|
||||
{
|
||||
@ -22,8 +24,8 @@
|
||||
var x = context.Stack.PopBottom();
|
||||
var y = context.Stack.PopBottom();
|
||||
|
||||
context.CurrentPosition = new PdfPoint(x, y);
|
||||
|
||||
//context.CurrentPosition = new PdfPoint(x, y);
|
||||
// TODO: need to investigate why odd behavior when the current point is actualy set.
|
||||
context.Stack.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,19 +19,19 @@
|
||||
|
||||
public static void Run(Type1BuildCharContext context)
|
||||
{
|
||||
var x = context.Stack.PopBottom();
|
||||
|
||||
var actualX = context.CurrentPosition.X + x;
|
||||
var y = context.CurrentPosition.Y;
|
||||
var deltaX = context.Stack.PopBottom();
|
||||
|
||||
if (context.IsFlexing)
|
||||
{
|
||||
// TODO: flex support
|
||||
// not in the Type 1 spec, but exists in some fonts
|
||||
context.AddFlexPoint(new PdfPoint(deltaX, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
context.CurrentPosition = new PdfPoint(actualX, y);
|
||||
context.Path.MoveTo(actualX, y);
|
||||
var x = context.CurrentPosition.X + deltaX;
|
||||
var y = context.CurrentPosition.Y;
|
||||
context.CurrentPosition = new PdfPoint(x, y);
|
||||
context.Path.MoveTo(x, y);
|
||||
}
|
||||
|
||||
context.Stack.Clear();
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
|
||||
if (context.IsFlexing)
|
||||
{
|
||||
|
||||
context.AddFlexPoint(new PdfPoint(deltaX, deltaY));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
namespace UglyToad.PdfPig.Fonts.Type1.CharStrings.Commands.PathConstruction
|
||||
{
|
||||
using Core;
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Vertical move to. Moves relative to the current point.
|
||||
@ -23,7 +24,8 @@
|
||||
|
||||
if (context.IsFlexing)
|
||||
{
|
||||
// TODO: flex commands
|
||||
// not in the Type 1 spec, but exists in some fonts
|
||||
context.AddFlexPoint(new PdfPoint(0, deltaY));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
/// Sets left sidebearing and the character width vector.
|
||||
/// This command also sets the current point to(sbx, sby), but does not place the point in the character path.
|
||||
/// </summary>
|
||||
internal class SbwCommand
|
||||
internal static class SbwCommand
|
||||
{
|
||||
public const string Name = "sbw";
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
public CharStringStack PostscriptStack { get; } = new CharStringStack();
|
||||
|
||||
public IReadOnlyList<PdfPoint> FlexPoints { get; }
|
||||
public List<PdfPoint> FlexPoints { get; } = new List<PdfPoint>();
|
||||
|
||||
public Type1BuildCharContext(IReadOnlyDictionary<int, Type1CharStrings.CommandSequence> subroutines,
|
||||
Func<int, PdfSubpath> characterByIndexFactory,
|
||||
@ -41,7 +41,7 @@
|
||||
|
||||
public void AddFlexPoint(PdfPoint point)
|
||||
{
|
||||
|
||||
FlexPoints.Add(point);
|
||||
}
|
||||
|
||||
public PdfSubpath GetCharacter(int characterCode)
|
||||
@ -61,7 +61,7 @@
|
||||
|
||||
public void ClearFlexPoints()
|
||||
{
|
||||
|
||||
FlexPoints.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UglyToad.PdfPig.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace UglyToad.PdfPig.Tests.Fonts.Type1
|
||||
{
|
||||
public class Type1CharStringParserTests
|
||||
{
|
||||
[Fact]
|
||||
public void CorrectBoundingBoxesFlexPoints()
|
||||
{
|
||||
PointComparer pointComparer = new PointComparer(new DoubleComparer(3));
|
||||
|
||||
var documentFolder = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..", "..", "Integration", "Documents"));
|
||||
|
||||
var filePath = Path.Combine(documentFolder, "data.pdf");
|
||||
|
||||
using (var doc = PdfDocument.Open(filePath))
|
||||
{
|
||||
var page = doc.GetPage(1);
|
||||
|
||||
var letters = page.Letters;
|
||||
|
||||
// check 'm'
|
||||
var m = letters[0];
|
||||
Assert.Equal("m", m.Value);
|
||||
Assert.Equal(new PdfPoint(253.4458, 658.431), m.GlyphRectangle.BottomLeft, pointComparer);
|
||||
Assert.Equal(new PdfPoint(261.22659, 662.83446), m.GlyphRectangle.TopRight, pointComparer);
|
||||
|
||||
// check 'p'
|
||||
var p = letters[1];
|
||||
Assert.Equal("p", p.Value);
|
||||
Assert.Equal(new PdfPoint(261.70778, 656.49825), p.GlyphRectangle.BottomLeft, pointComparer);
|
||||
Assert.Equal(new PdfPoint(266.6193, 662.83446), p.GlyphRectangle.TopRight, pointComparer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
src/UglyToad.PdfPig.Tests/Integration/Documents/data.pdf
Normal file
BIN
src/UglyToad.PdfPig.Tests/Integration/Documents/data.pdf
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user