mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-10-14 10:55:04 +08:00
add tests to visually verify the output for glpyh bounding boxes and use advance widths for empty glyphs in truetype fonts
This commit is contained in:
Binary file not shown.
After Width: | Height: | Size: 7.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
src/UglyToad.PdfPig.Tests/Integration/Documents/Type0 Font.jpg
Normal file
BIN
src/UglyToad.PdfPig.Tests/Integration/Documents/Type0 Font.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
@@ -0,0 +1,87 @@
|
||||
namespace UglyToad.PdfPig.Tests.Integration.VisualVerification
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using Xunit;
|
||||
|
||||
public class GenerateLetterBoundingBoxImages
|
||||
{
|
||||
private const string NonLatinAcrobatDistiller = "Single Page Non Latin - from acrobat distiller";
|
||||
private const string SingleGoogleDrivePage = "Single Page Simple - from google drive";
|
||||
private const string SinglePageFormattedType0Content = "Type0 Font";
|
||||
|
||||
private static string GetFilename(string name)
|
||||
{
|
||||
var documentFolder = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..", "..", "Integration", "Documents"));
|
||||
|
||||
if (!name.EndsWith(".pdf"))
|
||||
{
|
||||
name += ".pdf";
|
||||
}
|
||||
|
||||
return Path.Combine(documentFolder, name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SinglePageNonLatinFromAcrobatDistiller()
|
||||
{
|
||||
Run(NonLatinAcrobatDistiller);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SinglePageSimpleFromGoogleDrive()
|
||||
{
|
||||
Run(SingleGoogleDrivePage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SinglePageType0Font()
|
||||
{
|
||||
Run(SinglePageFormattedType0Content);
|
||||
}
|
||||
|
||||
private static void Run(string file)
|
||||
{
|
||||
var pdfFileName = GetFilename(file);
|
||||
|
||||
using (var document = PdfDocument.Open(pdfFileName))
|
||||
using (var image = GetCorrespondingImage(pdfFileName))
|
||||
{
|
||||
var page = document.GetPage(1);
|
||||
|
||||
var redPen = new Pen(Color.BlueViolet, 1);
|
||||
|
||||
using (var bitmap = new Bitmap(image))
|
||||
using (var graphics = Graphics.FromImage(bitmap))
|
||||
{
|
||||
foreach (var word in page.Letters)
|
||||
{
|
||||
graphics.DrawRectangle(redPen, new Rectangle((int)word.Rectangle.Left,
|
||||
792 - (int)word.Rectangle.Top, (int)word.Rectangle.Width, (int)word.Rectangle.Height));
|
||||
}
|
||||
|
||||
var imageName = $"{file}.jpg";
|
||||
|
||||
if (!Directory.Exists("Images"))
|
||||
{
|
||||
Directory.CreateDirectory("Images");
|
||||
}
|
||||
|
||||
var savePath = Path.Combine("Images", imageName);
|
||||
|
||||
bitmap.Save(savePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Image GetCorrespondingImage(string filename)
|
||||
{
|
||||
var pdf = GetFilename(filename);
|
||||
|
||||
pdf = pdf.Replace(".pdf", ".jpg");
|
||||
|
||||
return Image.FromFile(pdf);
|
||||
}
|
||||
}
|
||||
}
|
@@ -31,6 +31,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="4.5.0-preview2-26406-04" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.extensibility.execution" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
|
@@ -49,7 +49,7 @@
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Rectangle} {Value} {FontName} {PointSize}";
|
||||
return $"{Value} {Rectangle} {FontName} {PointSize}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -82,8 +82,6 @@
|
||||
|
||||
var fromFont = CidFont.GetWidthFromDictionary(cid);
|
||||
|
||||
var box = GetBoundingBox(characterCode);
|
||||
|
||||
return fromFont;
|
||||
}
|
||||
|
||||
|
@@ -90,7 +90,13 @@ namespace UglyToad.PdfPig.Fonts.Simple
|
||||
|
||||
public PdfRectangle GetBoundingBox(int characterCode)
|
||||
{
|
||||
return GetFontMatrix().Transform(GetBoundingBoxInGlyphSpace(characterCode));
|
||||
var fontMatrix = GetFontMatrix();
|
||||
|
||||
var boundingBox = GetBoundingBoxInGlyphSpace(characterCode);
|
||||
|
||||
var result = fontMatrix.Transform(boundingBox);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private PdfRectangle GetBoundingBoxInGlyphSpace(int characterCode)
|
||||
@@ -138,3 +144,4 @@ namespace UglyToad.PdfPig.Fonts.Simple
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,8 @@
|
||||
|
||||
public bool IsSimple { get; }
|
||||
|
||||
public bool IsEmpty => Points.Length == 0;
|
||||
|
||||
public Glyph(bool isSimple, byte[] instructions, int[] endPointsOfContours, GlyphPoint[] points,
|
||||
PdfRectangle bounds)
|
||||
{
|
||||
|
@@ -14,6 +14,8 @@
|
||||
|
||||
GlyphPoint[] Points { get; }
|
||||
|
||||
bool IsEmpty { get; }
|
||||
|
||||
IGlyphDescription DeepClone();
|
||||
}
|
||||
|
||||
|
@@ -20,14 +20,9 @@
|
||||
|
||||
public TrueTypeFont(decimal version, IReadOnlyDictionary<string, TrueTypeHeaderTable> tableHeaders, TableRegister tableRegister)
|
||||
{
|
||||
if (tableRegister == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tableRegister));
|
||||
}
|
||||
|
||||
Version = version;
|
||||
TableHeaders = tableHeaders;
|
||||
TableRegister = tableRegister;
|
||||
TableRegister = tableRegister ?? throw new ArgumentNullException(nameof(tableRegister));
|
||||
HeaderTable = tableRegister.HeaderTable;
|
||||
CMapTable = tableRegister.CMapTable;
|
||||
GlyphTable = tableRegister.GlyphDataTable;
|
||||
@@ -38,18 +33,7 @@
|
||||
{
|
||||
boundingBox = default(PdfRectangle);
|
||||
|
||||
int index;
|
||||
|
||||
if (CMapTable == null)
|
||||
{
|
||||
if (characterIdentifierToGlyphIndex == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
index = characterIdentifierToGlyphIndex(characterCode);
|
||||
}
|
||||
else if (!CMapTable.TryGetGlyphIndex(characterCode, out index))
|
||||
if (!TryGetGlyphIndex(characterCode, characterIdentifierToGlyphIndex, out var index))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -61,8 +45,15 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
boundingBox = glyph.Bounds;
|
||||
|
||||
if (glyph.IsEmpty && TryGetBoundingAdvancedWidthByIndex(index, out var advanceWidth))
|
||||
{
|
||||
boundingBox = new PdfRectangle(0, 0, advanceWidth, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
boundingBox = glyph.Bounds;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -70,18 +61,39 @@
|
||||
{
|
||||
width = 0m;
|
||||
|
||||
if (!TryGetGlyphIndex(characterCode, null, out var index))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return TryGetBoundingAdvancedWidthByIndex(index, out width);
|
||||
}
|
||||
|
||||
private bool TryGetBoundingAdvancedWidthByIndex(int index, out decimal width)
|
||||
{
|
||||
width = TableRegister.HorizontalMetricsTable.GetAdvanceWidth(index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryGetGlyphIndex(int characterIdentifier, Func<int, int> characterIdentifierToGlyphIndex, out int glyphIndex)
|
||||
{
|
||||
glyphIndex = 0;
|
||||
|
||||
if (CMapTable == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (characterIdentifierToGlyphIndex == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CMapTable.TryGetGlyphIndex(characterCode, out var index))
|
||||
glyphIndex = characterIdentifierToGlyphIndex(characterIdentifier);
|
||||
}
|
||||
else if (!CMapTable.TryGetGlyphIndex(characterIdentifier, out glyphIndex))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
width = TableRegister.HorizontalMetricsTable.GetAdvanceWidth(index);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user