#16 change letter api to match the actual information

This commit is contained in:
Eliot Jones 2018-11-22 19:32:16 +00:00
parent 3a025052c9
commit b9c8e152c1
12 changed files with 199 additions and 40 deletions

View File

@ -1,6 +1,8 @@
namespace UglyToad.PdfPig.Tests.Integration
{
using System;
using Content;
using Xunit;
public class AssertablePositionData
{
@ -40,5 +42,17 @@
Height = height
};
}
public void AssertWithinTolerance(Letter letter, Page page, bool includeHeight = true)
{
Assert.Equal(Text, letter.Value);
Assert.Equal(FontName, letter.FontName);
Assert.Equal(X, letter.Position.X, 1);
Assert.Equal(Width, letter.Width, 1);
if (includeHeight)
{
Assert.Equal(Height, letter.GlyphRectangle.Height, 1);
}
}
}
}

View File

@ -1,7 +1,9 @@
namespace UglyToad.PdfPig.Tests.Integration
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Xunit;
public class LaTexTests
@ -47,5 +49,141 @@
Assert.Equal(8, document.NumberOfPages);
}
}
[Fact]
public void LettersHaveCorrectPositionsXfinium()
{
var positions = GetXfiniumPositionData();
using (var document = PdfDocument.Open(GetFilename()))
{
var page = document.GetPage(1);
for (var i = 0; i < page.Letters.Count; i++)
{
if (i >= positions.Count)
{
break;
}
var letter = page.Letters[i];
var expected = positions[i];
expected.AssertWithinTolerance(letter, page, false);
}
}
}
[Fact]
public void LettersHaveCorrectPositionsPdfBox()
{
var positions = GetPdfBoxPositionData();
using (var document = PdfDocument.Open(GetFilename()))
{
var page = document.GetPage(1);
for (var i = 0; i < page.Letters.Count; i++)
{
if (i >= positions.Count)
{
break;
}
var letter = page.Letters[i];
var expected = positions[i];
expected.AssertWithinTolerance(letter, page);
}
}
}
private static IReadOnlyList<AssertablePositionData> GetPdfBoxPositionData()
{
const string data = @"75.731 698.917 11.218573 T 14.346 WDKAAR+CMBX12 9.712242
85.615395 698.917 7.8472624 a 14.346 WDKAAR+CMBX12 6.584814
93.46266 698.917 7.173 c 14.346 WDKAAR+CMBX12 6.584814
100.17659 698.917 8.521524 k 14.346 WDKAAR+CMBX12 9.956124
108.698105 698.917 4.4902983 l 14.346 WDKAAR+CMBX12 9.956124
113.18841 698.917 4.4902983 i 14.346 WDKAAR+CMBX12 9.97047
117.67871 698.917 8.966249 n 14.346 WDKAAR+CMBX12 6.4557
126.64496 698.917 8.076798 g 14.346 WDKAAR+CMBX12 9.425322
140.08716 698.917 6.2835484 t 14.346 WDKAAR+CMBX12 9.195786
146.3707 698.917 8.966249 h 14.346 WDKAAR+CMBX12 9.956124
155.33694 698.917 7.359498 e 14.346 WDKAAR+CMBX12 6.584814
168.06186 698.917 11.032075 P 14.346 WDKAAR+CMBX12 9.841356
178.6492 698.917 8.076798 o 14.346 WDKAAR+CMBX12 6.584814
187.15637 698.917 8.076798 o 14.346 WDKAAR+CMBX12 6.584814
195.23318 698.917 6.584814 r 14.346 WDKAAR+CMBX12 6.4557
207.19774 698.917 12.1941 A 14.346 WDKAAR+CMBX12 10.0422
219.39185 698.917 6.3696246 s 14.346 WDKAAR+CMBX12 6.584814
225.76147 698.917 6.3696246 s 14.346 WDKAAR+CMBX12 6.584814
232.1311 698.917 8.966249 u 14.346 WDKAAR+CMBX12 6.541776
241.09735 698.917 13.456548 m 14.346 WDKAAR+CMBX12 6.4557
254.5539 698.917 8.966249 p 14.346 WDKAAR+CMBX12 9.238825
263.52014 698.917 6.2835484 t 14.346 WDKAAR+CMBX12 9.195786
269.8037 698.917 4.4902983 i 14.346 WDKAAR+CMBX12 9.97047
274.294 698.917 8.076798 o 14.346 WDKAAR+CMBX12 6.584814
282.3708 698.917 8.966249 n 14.346 WDKAAR+CMBX12 6.4557
291.33704 698.917 6.3696246 s 14.346 WDKAAR+CMBX12 6.584814
303.0434 698.917 8.076798 o 14.346 WDKAAR+CMBX12 6.584814
311.12018 698.917 4.9350243 f 14.346 WDKAAR+CMBX12 10.0422
321.43494 698.917 12.62448 N 14.346 WDKAAR+CMBX12 9.841356
334.05945 698.917 7.8472624 a 14.346 WDKAAR+CMBX12 6.584814
341.90668 698.917 4.4902983 i 14.346 WDKAAR+CMBX12 9.97047
346.39697 698.917 8.521524 v 14.346 WDKAAR+CMBX12 6.4413543
354.44507 698.917 7.359498 e 14.346 WDKAAR+CMBX12 6.584814
367.18433 698.917 11.4768 B 14.346 WDKAAR+CMBX12 9.841356
378.66113 698.917 7.8472624 a 14.346 WDKAAR+CMBX12 6.584814
386.06366 698.917 8.521524 y 14.346 WDKAAR+CMBX12 9.238825
394.1261 698.917 7.359498 e 14.346 WDKAAR+CMBX12 6.584814
401.4856 698.917 6.3696246 s 14.346 WDKAAR+CMBX12 6.584814
413.235 698.917 11.218573 T 14.346 WDKAAR+CMBX12 9.712242
423.1194 698.917 7.359498 e 14.346 WDKAAR+CMBX12 6.584814
430.47888 698.917 8.521524 x 14.346 WDKAAR+CMBX12 6.3696246
439.00043 698.917 6.2835484 t 14.346 WDKAAR+CMBX12 9.195786
450.6637 698.917 11.663298 C 14.346 WDKAAR+CMBX12 10.18566
462.32703 698.917 4.4902983 l 14.346 WDKAAR+CMBX12 9.956124
466.81732 698.917 7.8472624 a 14.346 WDKAAR+CMBX12 6.584814
474.66455 698.917 6.3696246 s 14.346 WDKAAR+CMBX12 6.584814
481.03418 698.917 6.3696246 s 14.346 WDKAAR+CMBX12 6.584814
487.4038 698.917 4.4902983 i 14.346 WDKAAR+CMBX12 9.97047
491.8941 698.917 8.966249 14.346 WDKAAR+CMBX12 10.0422
500.86035 698.917 7.359498 e 14.346 WDKAAR+CMBX12 6.584814
508.21985 698.917 6.584814 r 14.346 WDKAAR+CMBX12 6.4557
514.8047 698.917 6.3696246 s 14.346 WDKAAR+CMBX12 6.584814
55.440002 650.772 5.9180226 J 9.963 IYBKTJ+CMBX10 6.9442115
61.358025 650.772 5.5693173 a 9.963 IYBKTJ+CMBX10 4.573017
66.92734 650.772 4.5232024 s 9.963 IYBKTJ+CMBX10 4.573017
71.45055 650.772 5.7287254 o 9.963 IYBKTJ+CMBX10 4.573017
77.17927 650.772 6.366358 n 9.963 IYBKTJ+CMBX10 4.4833503
87.36145 650.772 8.787367 D 9.963 IYBKTJ+CMBX10 6.8346186
96.14882 650.772 3.1781971 . 9.963 IYBKTJ+CMBX10 1.5542281
103.1528 650.772 10.879597 M 9.963 IYBKTJ+CMBX10 6.8346186
114.0324 650.772 3.1781971 . 9.963 IYBKTJ+CMBX10 1.5542281
121.02643 650.772 8.588107 R 9.963 IYBKTJ+CMBX10 6.9442115
129.61453 650.772 5.250501 e 9.963 IYBKTJ+CMBX10 4.573017
134.86504 650.772 6.366358 n 9.963 IYBKTJ+CMBX10 4.4833503
141.23138 650.772 6.366358 n 9.963 IYBKTJ+CMBX10 4.4833503
147.59775 650.772 3.1781971 i 9.963 IYBKTJ+CMBX10 6.924286
150.77594 650.772 5.250501 e 9.963 IYBKTJ+CMBX10 4.573017";
var result = data.Split(new[] { "\r", "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries)
.Select(AssertablePositionData.Parse)
.ToList();
return result;
}
private static IReadOnlyList<AssertablePositionData> GetXfiniumPositionData()
{
const string data = @"75.731 83.12866 11.218572 T 14.346 WDKAAR+CMBX12 9.956124
85.6153934 83.123866 7.847262 a 11.218572 WDKAAR+CMBX12 9.956124
93.462656 83.123866 7.173 c 11.218572 WDKAAR+CMBX12 9.956124
100.176584 83.123866 8.521524 k 11.218572 WDKAAR+CMBX12 9.956124
108.698108 83.123866 4.490298 l 11.218572 WDKAAR+CMBX12 9.956124";
var result = data.Split(new[] { "\r", "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries)
.Select(AssertablePositionData.Parse)
.ToList();
return result;
}
}
}

View File

@ -70,7 +70,7 @@
break;
}
var myX = pageLetter.CharacterRectangle.Left;
var myX = pageLetter.Position.X;
var theirX = pdfBoxData[index].X;
var myLetter = pageLetter.Value;
@ -87,7 +87,7 @@
Assert.Equal(theirX, myX, comparer);
Assert.Equal(pdfBoxData[index].Width, pageLetter.CharacterRectangle.Width, comparer);
Assert.Equal(pdfBoxData[index].Width, pageLetter.Width, comparer);
index++;
}
@ -113,7 +113,7 @@
break;
}
var myX = pageLetter.CharacterRectangle.Left;
var myX = pageLetter.Position.X;
var theirX = positions[index].X;
var myLetter = pageLetter.Value;
@ -127,7 +127,7 @@
Assert.Equal(theirLetter, myLetter);
Assert.Equal(theirX, myX, comparer);
Assert.Equal(positions[index].Width, pageLetter.CharacterRectangle.Width, 1);
Assert.Equal(positions[index].Width, pageLetter.Width, 1);
index++;
}

View File

@ -134,12 +134,12 @@ namespace UglyToad.PdfPig.Tests.Integration
}
Assert.Equal(datum.Text, letter.Value);
Assert.Equal(datum.X, letter.CharacterRectangle.BottomLeft.X, 2);
Assert.Equal(datum.X, letter.Position.X, 2);
var transformed = page.Height - letter.CharacterRectangle.BottomLeft.Y;
var transformed = page.Height - letter.Position.Y;
Assert.Equal(datum.Y, transformed, 2);
Assert.Equal(datum.Width, letter.CharacterRectangle.Width, 2);
Assert.Equal(datum.Width, letter.Width, 2);
Assert.Equal(datum.FontName, letter.FontName);
@ -179,13 +179,13 @@ namespace UglyToad.PdfPig.Tests.Integration
}
Assert.Equal(datum.Text, letter.Value);
Assert.Equal(datum.X, letter.CharacterRectangle.BottomLeft.X, 2);
Assert.Equal(datum.X, letter.Position.X, 2);
var transformed = page.Height - letter.CharacterRectangle.BottomLeft.Y;
var transformed = page.Height - letter.Position.Y;
Assert.Equal(datum.Y, transformed, 2);
// Until we get width from glyphs we're a bit out.
Assert.True(Math.Abs(datum.Width - letter.CharacterRectangle.Width) < 0.03m);
Assert.True(Math.Abs(datum.Width - letter.Width) < 0.03m);
index++;
}

View File

@ -12,16 +12,21 @@
/// </summary>
public string Value { get; }
/// <summary>
/// The placement position of the character in PDF space.
/// </summary>
public PdfPoint Position { get; }
/// <summary>
/// The width to advance the renderer once this character is drawn.
/// </summary>
public decimal Width { get; }
/// <summary>
/// Position of the bounding box for the glyph.
/// </summary>
public PdfRectangle GlyphRectangle { get; }
/// <summary>
/// The bounding box for the entire character.
/// </summary>
public PdfRectangle CharacterRectangle { get; }
/// <summary>
/// Size as defined in the PDF file. This is not equivalent to font size in points but is relative to other font sizes on the page.
/// </summary>
@ -40,14 +45,15 @@
/// <summary>
/// Create a new letter to represent some text drawn by the Tj operator.
/// </summary>
internal Letter(string value, PdfRectangle glyphRectangle, PdfRectangle characterRectangle, decimal fontSize, string fontName, decimal pointSize)
internal Letter(string value, PdfRectangle glyphRectangle, PdfPoint position, decimal width, decimal fontSize, string fontName, decimal pointSize)
{
Value = value;
GlyphRectangle = glyphRectangle;
FontSize = fontSize;
FontName = fontName;
PointSize = pointSize;
CharacterRectangle = characterRectangle;
Position = position;
Width = width;
}
/// <summary>

View File

@ -81,8 +81,7 @@
var width = CidFont.GetWidthFromFont(characterIdentifier);
var advanceWidth = new PdfRectangle(0, 0, width, 0);
advanceWidth = matrix.Transform(advanceWidth);
var advanceWidth = matrix.Transform(new PdfPoint(width, 0)).X;
return new CharacterBoundingBox(boundingBox, advanceWidth);
}

View File

@ -24,12 +24,12 @@
{
public PdfRectangle GlyphBounds { get; }
public PdfRectangle CharacterBounds { get; }
public decimal Width { get; }
public CharacterBoundingBox(PdfRectangle glyphBounds, PdfRectangle characterBounds)
public CharacterBoundingBox(PdfRectangle glyphBounds, decimal width)
{
GlyphBounds = glyphBounds;
CharacterBounds = characterBounds;
Width = width;
}
}
}

View File

@ -120,18 +120,16 @@
}
}
var advancedRectangle = new PdfRectangle(0, 0, width, 0);
if (fromFont)
{
advancedRectangle = fontMatrix.Transform(advancedRectangle);
width = fontMatrix.Transform(new PdfVector(width, 0)).X;
}
else
{
advancedRectangle = DefaultTransformation.Transform(advancedRectangle);
width = DefaultTransformation.Transform(new PdfVector(width, 0)).X;
}
return new CharacterBoundingBox(boundingBox, advancedRectangle);
return new CharacterBoundingBox(boundingBox, width);
}
private PdfRectangle GetBoundingBoxInGlyphSpace(int characterCode, out bool fromFont)

View File

@ -113,7 +113,9 @@
boundingBox = matrix.Transform(boundingBox);
return new CharacterBoundingBox(boundingBox, boundingBox);
var width = matrix.Transform(new PdfVector(widths[characterCode - firstChar], 0)).X;
return new CharacterBoundingBox(boundingBox, width);
}
private TransformationMatrix GetFontMatrixInternal()

View File

@ -50,7 +50,7 @@
boundingBox = fontMatrix.Transform(boundingBox);
return new CharacterBoundingBox(boundingBox, boundingBox);
return new CharacterBoundingBox(boundingBox, boundingBox.Width);
}
private PdfRectangle GetBoundingBoxInGlyphSpace(int characterCode)
@ -62,7 +62,7 @@
return new PdfRectangle(0, 0, 250, 0);
}
return new PdfRectangle(0, 0, metrics.WidthX, 0);
return new PdfRectangle(0, 0, metrics.WidthX, metrics.WidthY);
}
public TransformationMatrix GetFontMatrix()

View File

@ -65,11 +65,13 @@
public CharacterBoundingBox GetBoundingBox(int characterCode)
{
var boundingBox = GetBoundingBoxInGlyphSpace(characterCode);
var characterBoundingBox = GetBoundingBoxInGlyphSpace(characterCode);
boundingBox = fontMatrix.Transform(boundingBox);
characterBoundingBox = fontMatrix.Transform(characterBoundingBox);
return new CharacterBoundingBox(boundingBox, boundingBox);
var width = fontMatrix.Transform(new PdfVector(widths[characterCode - firstChar], 0)).X;
return new CharacterBoundingBox(characterBoundingBox, width);
}
private PdfRectangle GetBoundingBoxInGlyphSpace(int characterCode)

View File

@ -144,21 +144,21 @@
.Transform(TextMatrices.TextMatrix
.Transform(renderingMatrix
.Transform(boundingBox.GlyphBounds)));
var transformedGlyphOrigin = transformationMatrix
var transformedPdfBounds = transformationMatrix
.Transform(TextMatrices.TextMatrix
.Transform(renderingMatrix.Transform(boundingBox.CharacterBounds)));
.Transform(renderingMatrix.Transform(new PdfRectangle(0, 0, boundingBox.Width, 0))));
ShowGlyph(font, transformedGlyphBounds, transformedGlyphOrigin, unicode, fontSize, pointSize);
ShowGlyph(font, transformedGlyphBounds, transformedPdfBounds.BottomLeft, transformedPdfBounds.Width, unicode, fontSize, pointSize);
decimal tx, ty;
if (font.IsVertical)
{
tx = 0;
ty = boundingBox.CharacterBounds.Height * fontSize + characterSpacing + wordSpacing;
ty = boundingBox.GlyphBounds.Height * fontSize + characterSpacing + wordSpacing;
}
else
{
tx = (boundingBox.CharacterBounds.Width * fontSize + characterSpacing + wordSpacing) * horizontalScaling;
tx = (boundingBox.Width * fontSize + characterSpacing + wordSpacing) * horizontalScaling;
ty = 0;
}
@ -254,9 +254,9 @@
TextMatrices.TextMatrix = newMatrix;
}
private void ShowGlyph(IFont font, PdfRectangle glyphRectangle, PdfRectangle characterRectangle, string unicode, decimal fontSize, decimal pointSize)
private void ShowGlyph(IFont font, PdfRectangle glyphRectangle, PdfPoint position, decimal width, string unicode, decimal fontSize, decimal pointSize)
{
var letter = new Letter(unicode, glyphRectangle, characterRectangle, fontSize, font.Name.Data, pointSize);
var letter = new Letter(unicode, glyphRectangle, position, width, fontSize, font.Name.Data, pointSize);
Letters.Add(letter);
}