2018-07-24 21:32:02 +10:00
|
|
|
|
/*
|
|
|
|
|
* This file is subject to the terms and conditions defined in
|
|
|
|
|
* file 'LICENSE.md', which is part of this source code package.
|
|
|
|
|
*/
|
|
|
|
|
|
2018-07-09 18:01:22 +10:00
|
|
|
|
package model_test
|
2018-06-27 12:25:59 +10:00
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
2018-07-17 17:43:11 +10:00
|
|
|
|
"fmt"
|
2018-07-18 14:30:43 +10:00
|
|
|
|
"io/ioutil"
|
2018-11-01 21:33:51 +11:00
|
|
|
|
"strings"
|
2018-06-27 12:25:59 +10:00
|
|
|
|
"testing"
|
|
|
|
|
|
2018-07-19 10:28:23 +10:00
|
|
|
|
"github.com/unidoc/unidoc/common"
|
2018-07-15 17:29:27 +10:00
|
|
|
|
"github.com/unidoc/unidoc/pdf/core"
|
2018-11-01 21:33:51 +11:00
|
|
|
|
"github.com/unidoc/unidoc/pdf/internal/testutils"
|
|
|
|
|
"github.com/unidoc/unidoc/pdf/internal/textencoding"
|
2018-07-09 18:01:22 +10:00
|
|
|
|
"github.com/unidoc/unidoc/pdf/model"
|
|
|
|
|
"github.com/unidoc/unidoc/pdf/model/fonts"
|
2018-06-27 12:25:59 +10:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func init() {
|
2018-11-12 11:04:09 +11:00
|
|
|
|
common.SetLogger(common.NewConsoleLogger(common.LogLevelDebug))
|
2018-06-27 12:25:59 +10:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-28 11:06:23 +10:00
|
|
|
|
var simpleFontDicts = []string{
|
2018-10-16 14:50:43 +11:00
|
|
|
|
`<< /Type /Font
|
|
|
|
|
/BaseFont /Courier-BoldOblique
|
|
|
|
|
/Subtype /Type1
|
|
|
|
|
>>`,
|
2018-06-27 12:25:59 +10:00
|
|
|
|
`<< /Type /Font
|
|
|
|
|
/BaseFont /Helvetica
|
|
|
|
|
/Subtype /Type1
|
|
|
|
|
/Encoding /WinAnsiEncoding
|
|
|
|
|
>>`,
|
2018-11-01 21:33:51 +11:00
|
|
|
|
`<< /Type /Font
|
|
|
|
|
/BaseFont /Courier
|
|
|
|
|
/Subtype /Type1
|
|
|
|
|
/Encoding /WinAnsiEncoding
|
|
|
|
|
>>`,
|
2018-06-27 12:25:59 +10:00
|
|
|
|
`<< /Type /Font
|
|
|
|
|
/BaseFont /Helvetica-Oblique
|
|
|
|
|
/Subtype /Type1
|
|
|
|
|
/Encoding /WinAnsiEncoding
|
|
|
|
|
>>`,
|
|
|
|
|
`<< /Type /Font
|
|
|
|
|
/Subtype /Type1
|
|
|
|
|
/FirstChar 71
|
|
|
|
|
/LastChar 79
|
|
|
|
|
/Widths [ 778 722 278 500 667 556 833 722 778 ]
|
|
|
|
|
/Encoding /WinAnsiEncoding
|
|
|
|
|
/BaseFont /AOMFKK+Helvetica
|
|
|
|
|
>>`,
|
|
|
|
|
`<< /Type /Font
|
|
|
|
|
/Subtype /Type1
|
|
|
|
|
/FirstChar 71
|
|
|
|
|
/LastChar 79
|
|
|
|
|
/Widths [ 778 722 278 500 667 556 833 722 778 ]
|
|
|
|
|
/Encoding /WinAnsiEncoding
|
|
|
|
|
/BaseFont /PETER+Helvetica
|
|
|
|
|
/FontDescriptor <<
|
|
|
|
|
/Type /FontDescriptor
|
|
|
|
|
/Ascent 718
|
|
|
|
|
/CapHeight 718
|
|
|
|
|
/Descent -207
|
|
|
|
|
/Flags 32
|
|
|
|
|
/FontBBox [ -166 -225 1000 931 ]
|
|
|
|
|
/FontName /PETER+Helvetica
|
|
|
|
|
/ItalicAngle 0
|
|
|
|
|
/StemV 88
|
|
|
|
|
/XHeight 523
|
|
|
|
|
/StemH 88
|
|
|
|
|
/CharSet (/G/O)
|
|
|
|
|
%/FontFile3 19 0 R
|
|
|
|
|
>>
|
|
|
|
|
>>`,
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-29 18:09:44 +10:00
|
|
|
|
var compositeFontDicts = []string{
|
|
|
|
|
`<< /Type /Font
|
|
|
|
|
/Subtype /Type0
|
|
|
|
|
/Encoding /Identity-H
|
|
|
|
|
/DescendantFonts [<<
|
|
|
|
|
/Type /Font
|
|
|
|
|
/Subtype /CIDFontType2
|
|
|
|
|
/BaseFont /FLDOLC+PingFangSC-Regular
|
|
|
|
|
/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
|
|
|
|
|
/W [ ]
|
|
|
|
|
/DW 1000
|
|
|
|
|
/FontDescriptor <<
|
|
|
|
|
/Type /FontDescriptor
|
|
|
|
|
/FontName /FLDOLC+PingFangSC-Regular
|
|
|
|
|
/Flags 4
|
|
|
|
|
/FontBBox [-123 -263 1177 1003]
|
|
|
|
|
/ItalicAngle 0
|
|
|
|
|
/Ascent 972
|
|
|
|
|
/Descent -232
|
|
|
|
|
/CapHeight 864
|
|
|
|
|
/StemV 70
|
|
|
|
|
/XHeight 648
|
|
|
|
|
/StemH 64
|
|
|
|
|
/AvgWidth 1000
|
|
|
|
|
/MaxWidth 1300
|
|
|
|
|
% /FontFile3 182 0 R
|
|
|
|
|
>>
|
|
|
|
|
>>]
|
|
|
|
|
/BaseFont /FLDOLC+PingFangSC-Regular
|
|
|
|
|
>>`,
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-09 18:10:38 +10:00
|
|
|
|
func TestNewStandard14Font(t *testing.T) {
|
2018-07-09 18:01:22 +10:00
|
|
|
|
type expect struct {
|
|
|
|
|
subtype string
|
|
|
|
|
basefont string
|
|
|
|
|
fonts.CharMetrics
|
|
|
|
|
}
|
2018-12-19 16:55:27 +05:00
|
|
|
|
tests := map[fonts.StdFontName]expect{
|
2018-12-09 19:30:13 +02:00
|
|
|
|
"Courier": {
|
2018-07-09 18:01:22 +10:00
|
|
|
|
subtype: "Type1",
|
|
|
|
|
basefont: "Courier",
|
2018-12-26 19:03:15 +02:00
|
|
|
|
CharMetrics: fonts.CharMetrics{Wx: 600}},
|
2018-07-09 18:01:22 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for in, expect := range tests {
|
2018-07-09 18:10:38 +10:00
|
|
|
|
font, err := model.NewStandard14Font(in)
|
2018-07-09 18:01:22 +10:00
|
|
|
|
if err != nil {
|
2018-07-09 18:10:38 +10:00
|
|
|
|
t.Fatalf("%s: %v", in, err)
|
2018-07-09 18:01:22 +10:00
|
|
|
|
}
|
2018-07-09 18:10:38 +10:00
|
|
|
|
if font.Subtype() != expect.subtype || font.BaseFont() != expect.basefont {
|
|
|
|
|
t.Fatalf("%s: expected BaseFont=%s SubType=%s, but got BaseFont=%s SubType=%s",
|
|
|
|
|
in, expect.basefont, expect.subtype, font.BaseFont(), font.Subtype())
|
2018-07-09 18:01:22 +10:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-28 01:38:48 +02:00
|
|
|
|
metrics, ok := font.GetRuneMetrics(' ')
|
2018-07-09 18:01:22 +10:00
|
|
|
|
if !ok {
|
2018-07-09 18:10:38 +10:00
|
|
|
|
t.Fatalf("%s: failed to get glyph metric", in)
|
2018-07-09 18:01:22 +10:00
|
|
|
|
}
|
|
|
|
|
if metrics.Wx != expect.Wx || metrics.Wy != expect.Wy {
|
2018-07-10 08:57:16 +10:00
|
|
|
|
t.Fatalf("%s: expected glyph metrics is Wx=%f Wy=%f, but got Wx=%f Wy=%f",
|
2018-07-09 18:01:22 +10:00
|
|
|
|
in, expect.Wx, expect.Wy, metrics.Wx, metrics.Wy)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-28 11:06:23 +10:00
|
|
|
|
// TestSimpleFonts checks that we correctly recreate simple fonts that we parse.
|
2018-06-27 12:25:59 +10:00
|
|
|
|
func TestSimpleFonts(t *testing.T) {
|
2018-06-28 11:06:23 +10:00
|
|
|
|
for _, d := range simpleFontDicts {
|
2018-12-27 12:37:32 +02:00
|
|
|
|
t.Run("", func(t *testing.T) {
|
|
|
|
|
objFontObj(t, d)
|
|
|
|
|
})
|
2018-06-27 12:25:59 +10:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-01 21:33:51 +11:00
|
|
|
|
// TestStandardFontDict tests PDF object output of standard font.
|
|
|
|
|
// Importantly, this test makes sure that the output dictionary does not have an `Encoding`
|
|
|
|
|
// key and uses the encoding of the standard font (ZapfEncoding in this case).
|
|
|
|
|
func TestStandardFontOutputDict(t *testing.T) {
|
2018-12-19 13:43:09 +05:00
|
|
|
|
zapfdb, err := model.NewStandard14Font(fonts.ZapfDingbatsName)
|
2018-11-01 21:33:51 +11:00
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dict, ok := core.GetDict(zapfdb.ToPdfObject())
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("not a dict")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(dict.Keys()) != 3 {
|
2018-12-27 12:37:32 +02:00
|
|
|
|
t.Fatalf("Incorrect number of keys (%d): %v", len(dict.Keys()), dict.Keys())
|
2018-11-01 21:33:51 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ntype, ok := core.GetName(dict.Get("Type"))
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("invalid Type")
|
|
|
|
|
}
|
|
|
|
|
if ntype.String() != "Font" {
|
|
|
|
|
t.Fatalf("Type != Font (%s)", ntype.String())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
basef, ok := core.GetName(dict.Get("BaseFont"))
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("Invalid BaseFont")
|
|
|
|
|
}
|
|
|
|
|
if basef.String() != "ZapfDingbats" {
|
|
|
|
|
t.Fatalf("BaseFont != ZapfDingbats (%s)", basef.String())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
subtype, ok := core.GetName(dict.Get("Subtype"))
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("Invalid Subtype")
|
|
|
|
|
}
|
|
|
|
|
if subtype.String() != "Type1" {
|
|
|
|
|
t.Fatalf("Subtype != Type1 (%s)", subtype.String())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test loading a standard font from object and check the encoding and glyph metrics.
|
|
|
|
|
func TestLoadStandardFontEncodings(t *testing.T) {
|
|
|
|
|
raw := `
|
|
|
|
|
1 0 obj
|
|
|
|
|
<< /Type /Font
|
|
|
|
|
/BaseFont /Courier
|
|
|
|
|
/Subtype /Type1
|
|
|
|
|
>>
|
|
|
|
|
endobj
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
r := model.NewReaderForText(raw)
|
|
|
|
|
|
|
|
|
|
err := r.ParseIndObjSeries()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Failed loading indirect object series: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load the field from object number 1.
|
|
|
|
|
obj, err := r.GetIndirectObjectByNumber(1)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Failed to parse indirect obj (%s)", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
font, err := model.NewPdfFontFromPdfObject(obj)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
str := "Aabcdefg0123456790*"
|
|
|
|
|
for _, r := range str {
|
2018-12-28 01:38:48 +02:00
|
|
|
|
_, has := font.GetRuneMetrics(r)
|
2018-11-01 21:33:51 +11:00
|
|
|
|
if !has {
|
2018-12-28 01:38:48 +02:00
|
|
|
|
t.Fatalf("Loaded simple font not having glyph char metrics for %v", r)
|
2018-11-01 21:33:51 +11:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-29 18:09:44 +10:00
|
|
|
|
// TestCompositeFonts checks that we correctly recreate composite fonts that we parse.
|
|
|
|
|
func TestCompositeFonts(t *testing.T) {
|
|
|
|
|
for _, d := range compositeFontDicts {
|
|
|
|
|
objFontObj(t, d)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-18 14:30:43 +10:00
|
|
|
|
// TestCharcodeBytesToUnicode checks that CharcodeBytesToUnicode is working for the tests in
|
2018-07-17 17:43:11 +10:00
|
|
|
|
// ToUnicode cmap.
|
2018-07-18 14:30:43 +10:00
|
|
|
|
func TestCharcodeBytesToUnicode(t *testing.T) {
|
|
|
|
|
for _, test := range charcodeBytesToUnicodeTest {
|
2018-12-27 12:37:32 +02:00
|
|
|
|
t.Run(test.description, func(t *testing.T) {
|
|
|
|
|
test.check(t)
|
|
|
|
|
})
|
2018-07-18 14:30:43 +10:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-18 21:12:15 +11:00
|
|
|
|
// TestFontDescriptor checks that the builtin standard 14 font descriptors are working.
|
|
|
|
|
func TestFontDescriptor(t *testing.T) {
|
|
|
|
|
type params struct {
|
|
|
|
|
FontName string
|
|
|
|
|
FontFamily string
|
|
|
|
|
Flags uint
|
|
|
|
|
FontBBox [4]float64
|
|
|
|
|
CapHeight float64
|
|
|
|
|
XHeight float64
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-27 12:17:28 +02:00
|
|
|
|
tests := map[fonts.StdFontName]params{
|
2018-10-18 21:12:15 +11:00
|
|
|
|
"Courier": params{
|
|
|
|
|
FontName: "Courier",
|
|
|
|
|
FontFamily: "Courier",
|
|
|
|
|
Flags: 0x0021,
|
|
|
|
|
FontBBox: [4]float64{-23, -250, 715, 805},
|
|
|
|
|
CapHeight: 562,
|
|
|
|
|
XHeight: 426,
|
|
|
|
|
},
|
|
|
|
|
"ZapfDingbats": params{
|
|
|
|
|
FontName: "ZapfDingbats",
|
|
|
|
|
FontFamily: "ZapfDingbats",
|
|
|
|
|
Flags: 0x0004,
|
|
|
|
|
FontBBox: [4]float64{-1, -143, 981, 820},
|
2018-10-23 10:36:38 +11:00
|
|
|
|
CapHeight: 0,
|
2018-10-18 21:12:15 +11:00
|
|
|
|
XHeight: 0,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for fontName, expect := range tests {
|
2018-12-27 12:37:32 +02:00
|
|
|
|
t.Run(string(fontName), func(t *testing.T) {
|
|
|
|
|
font := model.NewStandard14FontMustCompile(fontName)
|
2018-10-18 21:12:15 +11:00
|
|
|
|
|
2018-12-27 12:37:32 +02:00
|
|
|
|
descriptor := font.FontDescriptor()
|
|
|
|
|
if descriptor == nil {
|
|
|
|
|
t.Fatalf("%#q: No descriptor.", fontName)
|
|
|
|
|
}
|
|
|
|
|
actualFontName, ok := core.GetNameVal(descriptor.FontName)
|
2018-10-18 21:12:15 +11:00
|
|
|
|
if !ok {
|
2018-12-27 12:37:32 +02:00
|
|
|
|
t.Fatalf("%#q: No FontName. descriptor=%+v", fontName, descriptor)
|
|
|
|
|
}
|
|
|
|
|
fontFamily, ok := core.GetNameVal(descriptor.FontFamily)
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("%#q: No FontFamily. descriptor=%+v", fontName, descriptor)
|
|
|
|
|
}
|
|
|
|
|
flags, ok := core.GetIntVal(descriptor.Flags)
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("%#q: No Flags. descriptor=%+v", fontName, descriptor)
|
|
|
|
|
}
|
|
|
|
|
arr, ok := core.GetArray(descriptor.FontBBox)
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("%#q: No FontBBox. descriptor=%+v", fontName, descriptor)
|
|
|
|
|
}
|
|
|
|
|
fontBBox := [4]float64{}
|
|
|
|
|
for i := 0; i < 4; i++ {
|
|
|
|
|
x, ok := core.GetFloatVal(arr.Get(i))
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("%#q: Bad FontBBox. descriptor=%+v", fontName, descriptor)
|
|
|
|
|
}
|
|
|
|
|
fontBBox[i] = x
|
2018-10-18 21:12:15 +11:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-27 12:37:32 +02:00
|
|
|
|
capHeight, ok := core.GetFloatVal(descriptor.CapHeight)
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("%#q: No CapHeight. descriptor=%+v", fontName, descriptor)
|
|
|
|
|
}
|
|
|
|
|
xHeight, ok := core.GetFloatVal(descriptor.XHeight)
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("%#q: No XHeight. descriptor=%+v", fontName, descriptor)
|
|
|
|
|
}
|
2018-10-18 21:12:15 +11:00
|
|
|
|
|
2018-12-27 12:37:32 +02:00
|
|
|
|
actual := params{
|
|
|
|
|
FontName: actualFontName,
|
|
|
|
|
FontFamily: fontFamily,
|
|
|
|
|
Flags: uint(flags),
|
|
|
|
|
FontBBox: fontBBox,
|
|
|
|
|
CapHeight: capHeight,
|
|
|
|
|
XHeight: xHeight,
|
|
|
|
|
}
|
2018-10-18 21:12:15 +11:00
|
|
|
|
|
2018-12-27 12:37:32 +02:00
|
|
|
|
if actual.FontName != expect.FontName ||
|
|
|
|
|
actual.FontFamily != expect.FontFamily ||
|
|
|
|
|
actual.Flags != expect.Flags ||
|
|
|
|
|
actual.FontBBox != expect.FontBBox ||
|
|
|
|
|
actual.CapHeight != expect.CapHeight {
|
|
|
|
|
t.Fatalf("%s:\n\texpect=%+v\n\tactual=%+v", fontName, expect, actual)
|
|
|
|
|
}
|
|
|
|
|
})
|
2018-10-18 21:12:15 +11:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-18 14:30:43 +10:00
|
|
|
|
var charcodeBytesToUnicodeTest = []fontFragmentTest{
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"Helvetica built-in",
|
2018-08-03 11:01:39 +00:00
|
|
|
|
"./testdata/font/simple.txt", 1,
|
2018-07-20 22:18:18 +10:00
|
|
|
|
[]byte{32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
|
|
|
|
|
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
|
|
|
|
|
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
|
|
|
|
|
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
|
|
|
|
|
115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 130, 131, 132, 133,
|
|
|
|
|
134, 135, 136, 137, 138, 139, 140, 142, 145, 146, 147, 148, 149, 150, 151, 152, 153,
|
|
|
|
|
154, 155, 156, 158, 159, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172,
|
|
|
|
|
174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190,
|
|
|
|
|
191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
|
|
|
|
|
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
|
|
|
|
|
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
|
|
|
|
|
242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255},
|
|
|
|
|
" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" +
|
|
|
|
|
"abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹OEŽ‘’“”•–—˜™š›oežŸ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·" +
|
2018-11-10 08:56:47 +11:00
|
|
|
|
"¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞfzàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ",
|
2018-07-20 22:18:18 +10:00
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"Symbol built-in",
|
2018-08-03 11:01:39 +00:00
|
|
|
|
"./testdata/font/simple.txt", 3,
|
2018-07-20 22:18:18 +10:00
|
|
|
|
[]byte{32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
|
|
|
|
|
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
|
|
|
|
|
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 97,
|
|
|
|
|
98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
|
|
|
|
|
116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 160, 161, 162, 163, 164, 165, 166,
|
|
|
|
|
167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
|
|
|
|
|
185, 186, 187, 188, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204,
|
|
|
|
|
205, 206, 207, 208, 209, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225,
|
|
|
|
|
229, 241, 242, 243, 245},
|
2018-08-15 17:15:27 +10:00
|
|
|
|
" !∀#∃%&∋()∗+,−./0123456789:;<=>?≅ΑΒΧ∆ΕΦΓΗΙϑΚΛΜΝΟΠΘΡΣΤΥςΩΞΨΖ[∴]⊥_αβχδεφγηιϕκλµνοπθρστυϖω" +
|
2018-07-20 22:18:18 +10:00
|
|
|
|
"ξψζ{|}∼€ϒ′≤⁄∞ƒ♣♦♥♠↔←↑→↓°±″≥×∝∂•÷≠≡≈…↵ℵℑℜ℘⊗⊕∅∩∪⊃⊇⊄⊂⊆∈∉∠∇∏√⋅¬∧∨⇔⇐⇑⇒⇓◊〈∑〉∫⌠⌡",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"ZapfDingbats built-in",
|
2018-08-03 11:01:39 +00:00
|
|
|
|
"./testdata/font/simple.txt", 4,
|
2018-07-20 22:18:18 +10:00
|
|
|
|
[]byte{32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
|
|
|
|
|
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
|
|
|
|
|
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
|
|
|
|
|
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
|
|
|
|
|
115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 161, 162, 163, 164, 165,
|
|
|
|
|
166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
|
|
|
|
|
184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201,
|
|
|
|
|
202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
|
|
|
|
|
220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237,
|
|
|
|
|
238, 239, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254},
|
|
|
|
|
" ✁✂✃✄☎✆✇✈✉☛☞✌✍✎✏✐✑✒✓✔✕✖✗✘✙✚✛✜✝✞✟✠✡✢✣✤✥✦✧★✩✪✫✬✭✮✯✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋●❍■❏❐❑❒▲▼◆❖◗" +
|
|
|
|
|
"❘❙❚❛❜❝❞❡❢❣❤❥❦❧♣♦♥♠①②③④⑤⑥⑦⑧⑨⑩❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏➐➑➒➓➔→↔↕" +
|
|
|
|
|
"➘➙➚➛➜➝➞➟➠➡➢➣➤➥➦➧➨➩➪➫➬➭➮➯➱➲➳➴➵➶➷➸➹➺➻➼➽➾",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"MacRoman encoding",
|
2018-08-03 11:01:39 +00:00
|
|
|
|
"./testdata/font/axes.txt", 10,
|
2018-07-20 22:18:18 +10:00
|
|
|
|
[]byte{32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
|
|
|
|
|
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
|
|
|
|
|
75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
|
|
|
|
|
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
|
|
|
|
|
115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 129, 130, 131, 132, 133,
|
|
|
|
|
134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151,
|
|
|
|
|
152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
|
|
|
|
|
170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187,
|
|
|
|
|
188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 203, 204, 205, 206,
|
|
|
|
|
207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
|
|
|
|
|
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 241, 242, 243,
|
|
|
|
|
244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255},
|
|
|
|
|
" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" +
|
2018-11-10 08:56:47 +11:00
|
|
|
|
"abcdefghijklmnopqrstuvwxyz{|}~ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶fz®©™´¨≠ÆØ∞" +
|
|
|
|
|
"±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»…ÀÃÕOEoe–—“”‘’÷◊ÿŸ⁄€‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ",
|
2018-07-20 22:18:18 +10:00
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"Test beginbfchar and beginbfrange cmap entries",
|
2018-08-03 11:01:39 +00:00
|
|
|
|
"./testdata/font/Yemeni.txt", 470,
|
2018-07-20 11:39:41 +10:00
|
|
|
|
[]byte{0x1, 0xa8, 0x1, 0xb3, 0x1, 0xc2, 0x1, 0xcc, 0x1, 0xe7, 0x1, 0xef, 0x1, 0xf3, 0x0,
|
|
|
|
|
0x20, 0x1, 0xa2, 0x1, 0xfc, 0x2, 0x8, 0x1, 0xa6, 0x1, 0xe7, 0x0, 0x20, 0x2, 0xb, 0x0,
|
|
|
|
|
0x20, 0x2, 0xf, 0x0, 0x20, 0x0, 0x20, 0x1, 0xdd, 0x0, 0x20, 0x0, 0xcd, 0x0, 0xce, 0x0,
|
|
|
|
|
0xcf, 0x0, 0xd0, 0x0, 0xd1, 0x1, 0xa1, 0x0, 0x20, 0x1, 0xa9, 0x2, 0x1},
|
|
|
|
|
"ﺔﺟﺮﺸﻓﻛﻟ ﺎﻨﻴﺒﻓ ﻷ ﻻ ﻉ ٠١٢٣٤ﺍ ﺕﻭ",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"TrueType font with ToUnicode cmap",
|
2018-08-03 11:01:39 +00:00
|
|
|
|
"./testdata/font/print_alerts.txt", 9,
|
2018-07-18 14:30:43 +10:00
|
|
|
|
[]byte{43, 40, 41, 34, 37, 42, 38, 49, 36, 38, 48, 34, 35, 36, 37, 35, 36, 58},
|
|
|
|
|
"Alerts on printing",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"Type0 font with ToUnicode cmap",
|
2018-08-03 11:01:39 +00:00
|
|
|
|
"./testdata/font/CollazoBio.txt", 7,
|
2018-07-19 10:28:23 +10:00
|
|
|
|
[]byte{255, 50, 255, 65, 255, 78, 255, 68, 255, 79, 255, 77, 0, 32, 0, 32, 255, 77, 255, 65,
|
|
|
|
|
255, 84, 255, 82, 255, 73, 255, 67, 255, 69, 255, 83, 0, 46},
|
|
|
|
|
"Random matrices.",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"Type1 font with FontFile entry",
|
2018-08-03 11:01:39 +00:00
|
|
|
|
"./testdata/font/lm.txt", 7,
|
2018-07-18 14:30:43 +10:00
|
|
|
|
[]byte{102, 65, 106, 66, 103},
|
|
|
|
|
"{A|B}",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"Type1 font with /Encoding with /Differences",
|
2018-08-03 11:01:39 +00:00
|
|
|
|
"./testdata/font/noise-invariant.txt", 102,
|
2018-07-20 14:15:41 +10:00
|
|
|
|
[]byte{96, 247, 39, 32, 147, 231, 148, 32, 232, 32, 193, 111, 180, 32, 105, 116,
|
2018-11-22 22:01:04 +11:00
|
|
|
|
169, 115, 32, 204, 195, 196, 197, 198, 199, 168, 202, 206, 226, 234, 172, 245, 173, 151,
|
2018-07-20 14:15:41 +10:00
|
|
|
|
177, 151, 178, 179, 183, 185, 188, 205, 184, 189},
|
|
|
|
|
"‘ł’ “Ł” Ø `o´ it's ˝ˆ˜¯˘˙¨˚ˇªº‹ı›—–—†‡•„…˛¸‰",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"base glyphs′",
|
2018-08-23 21:51:32 +10:00
|
|
|
|
"./testdata/font/cover.txt", 11,
|
2018-08-14 21:28:57 +10:00
|
|
|
|
[]byte{44, 45, 46, 48, 49, 50, 51, 53, 54, 55, 56, 58, 59,
|
|
|
|
|
65, 66, 67, 68, 69, 70, 71, 72,
|
|
|
|
|
84, 85,
|
|
|
|
|
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111,
|
|
|
|
|
114, 115, 116, 117},
|
|
|
|
|
",-.01235678:;ABCDEFGHTUabcdefghijlmnorstu",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"tex glyphs 48->′",
|
2018-08-23 21:51:32 +10:00
|
|
|
|
"./testdata/font/noise-contrast.txt", 36,
|
2018-08-14 21:28:57 +10:00
|
|
|
|
[]byte{33, 48, 65, 104, 149, 253},
|
|
|
|
|
"!′Ah•ý",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"tex2 glyphs ",
|
2018-08-23 21:51:32 +10:00
|
|
|
|
"./testdata/font/Weil.txt", 30,
|
2018-08-14 21:28:57 +10:00
|
|
|
|
[]byte{55, 0, 1, 2, 20, 24, 33, 50, 102, 103, 104, 105},
|
|
|
|
|
"↦−·×≤∼→∈{}⟨⟩",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"additional glyphs",
|
2018-08-23 21:51:32 +10:00
|
|
|
|
"./testdata/font/noise-contrast.txt", 34,
|
2018-08-14 21:28:57 +10:00
|
|
|
|
[]byte{32, 40, 48, 64, 80, 88, 65, 104, 149, 253},
|
|
|
|
|
"({∑∑h•ý",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{".notdef glyphs",
|
2018-08-23 21:51:32 +10:00
|
|
|
|
"./testdata/font/lec10.txt", 6,
|
2018-08-14 21:28:57 +10:00
|
|
|
|
[]byte{59, 66},
|
|
|
|
|
string([]rune{textencoding.MissingCodeRune, textencoding.MissingCodeRune}),
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"Numbered glyphs pattern 1",
|
2018-08-23 21:51:32 +10:00
|
|
|
|
"./testdata/font/v14.txt", 14,
|
2018-08-14 21:28:57 +10:00
|
|
|
|
[]byte{24, 25, 26, 27, 29},
|
|
|
|
|
" ffifflfffi",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"Glyph aliases",
|
2018-08-23 21:51:32 +10:00
|
|
|
|
"./testdata/font/townes.txt", 10,
|
2018-08-14 21:28:57 +10:00
|
|
|
|
[]byte{2, 3, 4, 5, 6, 7, 1, 8, 9, 5, 1, 10, 9, 5, 48},
|
|
|
|
|
"Townes van Zan…",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"Glyph `.` extensions. e.g. `integral.disp`",
|
2018-08-23 21:51:32 +10:00
|
|
|
|
"./testdata/font/preview.txt", 156,
|
2018-08-14 21:28:57 +10:00
|
|
|
|
[]byte{83, 0, 4, 67, 62, 64, 100, 65},
|
|
|
|
|
"∫=≈≥∈<d>",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"A potpourri of glyph naming conventions",
|
2018-08-23 21:51:32 +10:00
|
|
|
|
"./testdata/font/Ingmar.txt", 144,
|
2018-07-30 18:09:28 +10:00
|
|
|
|
[]byte{18, 20, 10, 11, 13, 14, 15, 16, 21, 22, 23, 25, 26, 27, 28, 29, 30,
|
|
|
|
|
31, 33, 12, 17, 19, 24},
|
|
|
|
|
"ʼ8ČŽĆřćĐĭűőftffiflfffičž!fbfkffl\u00a0",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"Zapf Dingbats",
|
2018-08-23 21:51:32 +10:00
|
|
|
|
"./testdata/font/estimation.txt", 122,
|
2018-08-14 11:56:09 +10:00
|
|
|
|
[]byte{2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14},
|
|
|
|
|
"✏✮✁☛❄❍❥❇◆✟✙",
|
2018-07-30 18:09:28 +10:00
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"Found these by trial and error",
|
2018-08-23 21:51:32 +10:00
|
|
|
|
"./testdata/font/helminths.txt", 19,
|
2018-07-30 18:09:28 +10:00
|
|
|
|
[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
|
|
|
|
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
|
|
|
|
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
|
|
|
|
|
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
|
|
|
|
|
75, 76, 77},
|
|
|
|
|
" *ﺏﻁﻝﺍﺔﻴﻠﻜ،ﺕﺭﺘﻌﻤﺎﺠﻲﻨﻘﺩﻬ/ﻙﻭﻕﺃﻡﻋﻓﺴ٢٠٣ﻯﻥﺒﺸﺌﺱﻷ,ﺯﺤﺄﻀـﺓﺫ.)٤(٩ل٥٧٨ﻸﻰ%١ﺇ٦ﺡﻫﻱﻅﻐﺼﻑﺨﺀﻊLM",
|
|
|
|
|
},
|
2018-12-09 19:30:13 +02:00
|
|
|
|
{"Tesseract",
|
2018-09-24 18:02:02 +10:00
|
|
|
|
"./testdata/font/tesseract.txt", 3,
|
|
|
|
|
[]byte{0, 65, 0, 97,
|
|
|
|
|
1, 2, 1, 65, 1, 97,
|
|
|
|
|
12, 2, 12, 65, 12, 97,
|
|
|
|
|
20, 65, 20, 97, 20, 255,
|
|
|
|
|
42, 2, 42, 65, 42, 97,
|
|
|
|
|
65, 66, 67, 255},
|
|
|
|
|
"AaĂŁšంుౡᑁᑡᓿ⨂⩁⩡䅂䏿",
|
|
|
|
|
},
|
2018-07-18 14:30:43 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type fontFragmentTest struct {
|
|
|
|
|
description string
|
|
|
|
|
filename string
|
2018-11-30 23:01:04 +00:00
|
|
|
|
objNum int64
|
2018-07-18 14:30:43 +10:00
|
|
|
|
data []byte
|
|
|
|
|
expected string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *fontFragmentTest) String() string {
|
2018-07-20 22:18:18 +10:00
|
|
|
|
return fmt.Sprintf("TEST{%q file=%q obj=%d}", f.description, f.filename, f.objNum)
|
2018-07-18 14:30:43 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check loads the font in PDF fragment `filename`, object number `objNum`, runs
|
|
|
|
|
// CharcodeBytesToUnicode on `data` and checks that output equals `expected`.
|
|
|
|
|
func (f *fontFragmentTest) check(t *testing.T) {
|
|
|
|
|
numObj, err := parsePdfFragment(f.filename)
|
2018-07-17 17:43:11 +10:00
|
|
|
|
if err != nil {
|
2018-07-18 14:30:43 +10:00
|
|
|
|
t.Errorf("Failed to parse. %s err=%v", f, err)
|
2018-07-17 17:43:11 +10:00
|
|
|
|
return
|
|
|
|
|
}
|
2018-07-20 22:18:18 +10:00
|
|
|
|
fontObj, ok := numObj[f.objNum]
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Errorf("fontFragmentTest: %s. Unknown object. %d", f, f.objNum)
|
|
|
|
|
return
|
|
|
|
|
}
|
2018-07-17 17:43:11 +10:00
|
|
|
|
font, err := model.NewPdfFontFromPdfObject(fontObj)
|
|
|
|
|
if err != nil {
|
2018-07-20 22:18:18 +10:00
|
|
|
|
t.Errorf("fontFragmentTest: %s. Failed to create font. err=%v", f, err)
|
2018-07-17 17:43:11 +10:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-18 14:30:43 +10:00
|
|
|
|
actualText, numChars, numMisses := font.CharcodeBytesToUnicode(f.data)
|
2018-07-17 17:43:11 +10:00
|
|
|
|
if numMisses != 0 {
|
2018-11-22 22:01:04 +11:00
|
|
|
|
t.Errorf("Some codes not decoded %s. font=%s numMisses=%d", f, font, numMisses)
|
2018-07-17 17:43:11 +10:00
|
|
|
|
return
|
|
|
|
|
}
|
2018-07-18 14:30:43 +10:00
|
|
|
|
if actualText != f.expected {
|
2018-11-22 22:01:04 +11:00
|
|
|
|
t.Errorf("Incorrect decoding. %s encoding=%s\nexpected=%q\n actual=%q",
|
|
|
|
|
f, font.Encoder(), f.expected, actualText)
|
2018-08-15 17:15:27 +10:00
|
|
|
|
act, exp := []rune(actualText), []rune(f.expected)
|
|
|
|
|
if len(act) != len(exp) {
|
|
|
|
|
t.Errorf("\texpected=%d actual=%d", len(exp), len(act))
|
|
|
|
|
} else {
|
|
|
|
|
for i, a := range act {
|
|
|
|
|
e := exp[i]
|
|
|
|
|
if a != e {
|
|
|
|
|
t.Errorf("\ti=%d expected=0x%04x=%c actual=0x%04x=%c", i, e, e, a, a)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-07-17 17:43:11 +10:00
|
|
|
|
}
|
2018-07-19 10:28:23 +10:00
|
|
|
|
if numChars != len([]rune(actualText)) {
|
2018-07-20 22:18:18 +10:00
|
|
|
|
t.Errorf("Incorrect numChars. %s numChars=%d expected=%d\n%+v\n%c",
|
|
|
|
|
f, numChars, len([]rune(actualText)), []rune(actualText), []rune(actualText))
|
2018-07-17 17:43:11 +10:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-27 12:25:59 +10:00
|
|
|
|
// objFontObj parses `fontDict` to a make a Font, creates a PDF object from the Font and checks that
|
|
|
|
|
// the new PDF object is the same as the input object
|
|
|
|
|
func objFontObj(t *testing.T, fontDict string) error {
|
2018-07-15 17:29:27 +10:00
|
|
|
|
parser := core.NewParserFromString(fontDict)
|
2018-06-27 12:25:59 +10:00
|
|
|
|
obj, err := parser.ParseDict()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("objFontObj: Failed to parse dict obj. fontDict=%q err=%v", fontDict, err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
2018-07-09 18:01:22 +10:00
|
|
|
|
font, err := model.NewPdfFontFromPdfObject(obj)
|
2018-06-27 12:25:59 +10:00
|
|
|
|
if err != nil {
|
|
|
|
|
t.Errorf("Failed to parse font object. obj=%s err=%v", obj, err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Resolve all the indirect references in the font objects so we can compare their contents.
|
2018-07-15 17:29:27 +10:00
|
|
|
|
obj1 := core.FlattenObject(obj)
|
|
|
|
|
obj2 := core.FlattenObject(font.ToPdfObject())
|
2018-06-27 12:25:59 +10:00
|
|
|
|
|
2018-06-28 11:06:23 +10:00
|
|
|
|
// Check that the reconstituted font is the same as the original.
|
2018-07-15 17:29:27 +10:00
|
|
|
|
if !core.EqualObjects(obj1, obj2) {
|
2018-06-27 12:25:59 +10:00
|
|
|
|
t.Errorf("Different objects.\nobj1=%s\nobj2=%s\nfont=%s", obj1, obj2, font)
|
|
|
|
|
return errors.New("different objects")
|
|
|
|
|
}
|
2018-06-28 11:06:23 +10:00
|
|
|
|
|
2018-06-27 12:25:59 +10:00
|
|
|
|
return nil
|
|
|
|
|
}
|
2018-07-17 17:43:11 +10:00
|
|
|
|
|
2018-07-18 14:50:52 +10:00
|
|
|
|
// parsePdfFragment parses a file containing fragments of a PDF `filename` (see
|
|
|
|
|
// charcodeBytesToUnicodeTest) and returns a map of {object number: object} with indirect objects
|
|
|
|
|
// replaced by their values if they are in `filename`.
|
2018-11-30 23:01:04 +00:00
|
|
|
|
func parsePdfFragment(filename string) (map[int64]core.PdfObject, error) {
|
2018-07-18 14:30:43 +10:00
|
|
|
|
data, err := ioutil.ReadFile(filename)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-07-19 10:28:23 +10:00
|
|
|
|
|
2018-11-30 23:01:04 +00:00
|
|
|
|
return testutils.ParseIndirectObjects(string(data))
|
2018-07-17 17:43:11 +10:00
|
|
|
|
}
|
2018-11-01 21:33:51 +11:00
|
|
|
|
|
|
|
|
|
// TestLoadedSimpleFontEncoding tests loading a simple font with a Differences encoding.
|
2018-11-30 23:01:04 +00:00
|
|
|
|
// It checks if the loaded font encoding has the expected characteristics.
|
2018-11-01 21:33:51 +11:00
|
|
|
|
func TestLoadedSimpleFontEncoding(t *testing.T) {
|
|
|
|
|
rawpdf := `
|
|
|
|
|
59 0 obj
|
|
|
|
|
<</BaseFont /Helvetica/Encoding 60 0 R/Name /Helv/Subtype /Type1/Type /Font>>
|
|
|
|
|
endobj
|
|
|
|
|
60 0 obj
|
|
|
|
|
<</Differences [24 /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde 39 /quotesingle 96 /grave 128 /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction /guilsinglleft /guilsinglright /minus /perthousand /quotedblbase /quotedblleft /quotedblright /quoteleft /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron /Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron 160 /Euro 164 /currency 166 /brokenbar 168 /dieresis /copyright /ordfeminine 172 /logicalnot /.notdef /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu 183 /periodcentered /cedilla /onesuperior /ordmasculine 188 /onequarter /onehalf /threequarters 192 /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis]/Type /Encoding>>
|
|
|
|
|
endobj
|
|
|
|
|
`
|
|
|
|
|
|
|
|
|
|
objects, err := testutils.ParseIndirectObjects(rawpdf)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
font, err := model.NewPdfFontFromPdfObject(objects[59])
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The expected encoding is StandardEncoding with the applied differences.
|
|
|
|
|
baseEncoding := newStandandTextEncoder(t)
|
|
|
|
|
|
2018-11-29 23:24:40 +02:00
|
|
|
|
differencesMap := map[textencoding.CharCode]textencoding.GlyphName{
|
2018-11-01 21:33:51 +11:00
|
|
|
|
24: `/breve`,
|
|
|
|
|
25: `/caron`,
|
|
|
|
|
26: `/circumflex`,
|
|
|
|
|
27: `/dotaccent`,
|
|
|
|
|
28: `/hungarumlaut`,
|
|
|
|
|
29: `/ogonek`,
|
|
|
|
|
30: `/ring`,
|
|
|
|
|
31: `/tilde`,
|
|
|
|
|
39: `/quotesingle`,
|
|
|
|
|
96: `/grave`,
|
|
|
|
|
128: `/bullet`,
|
|
|
|
|
129: `/dagger`,
|
|
|
|
|
130: `/daggerdbl`,
|
|
|
|
|
131: `/ellipsis`,
|
|
|
|
|
132: `/emdash`,
|
|
|
|
|
133: `/endash`,
|
|
|
|
|
134: `/florin`,
|
|
|
|
|
135: `/fraction`,
|
|
|
|
|
136: `/guilsinglleft`,
|
|
|
|
|
137: `/guilsinglright`,
|
|
|
|
|
138: `/minus`,
|
|
|
|
|
139: `/perthousand`,
|
|
|
|
|
140: `/quotedblbase`,
|
|
|
|
|
141: `/quotedblleft`,
|
|
|
|
|
142: `/quotedblright`,
|
|
|
|
|
143: `/quoteleft`,
|
|
|
|
|
144: `/quoteright`,
|
|
|
|
|
145: `/quotesinglbase`,
|
|
|
|
|
146: `/trademark`,
|
|
|
|
|
147: `/fi`,
|
|
|
|
|
148: `/fl`,
|
|
|
|
|
149: `/Lslash`,
|
|
|
|
|
150: `/OE`,
|
|
|
|
|
151: `/Scaron`,
|
|
|
|
|
152: `/Ydieresis`,
|
|
|
|
|
153: `/Zcaron`,
|
|
|
|
|
154: `/dotlessi`,
|
|
|
|
|
155: `/lslash`,
|
|
|
|
|
156: `/oe`,
|
|
|
|
|
157: `/scaron`,
|
|
|
|
|
158: `/zcaron`,
|
|
|
|
|
160: `/Euro`,
|
|
|
|
|
164: `/currency`,
|
|
|
|
|
166: `/brokenbar`,
|
|
|
|
|
168: `/dieresis`,
|
|
|
|
|
169: `/copyright`,
|
|
|
|
|
170: `/ordfeminine`,
|
|
|
|
|
172: `/logicalnot`,
|
|
|
|
|
173: `/.notdef`,
|
|
|
|
|
174: `/registered`,
|
|
|
|
|
175: `/macron`,
|
|
|
|
|
176: `/degree`,
|
|
|
|
|
177: `/plusminus`,
|
|
|
|
|
178: `/twosuperior`,
|
|
|
|
|
179: `/threesuperior`,
|
|
|
|
|
180: `/acute`,
|
|
|
|
|
181: `/mu`,
|
|
|
|
|
183: `/periodcentered`,
|
|
|
|
|
184: `/cedilla`,
|
|
|
|
|
185: `/onesuperior`,
|
|
|
|
|
186: `/ordmasculine`,
|
|
|
|
|
188: `/onequarter`,
|
|
|
|
|
189: `/onehalf`,
|
|
|
|
|
190: `/threequarters`,
|
|
|
|
|
192: `/Agrave`,
|
|
|
|
|
193: `/Aacute`,
|
|
|
|
|
194: `/Acircumflex`,
|
|
|
|
|
195: `/Atilde`,
|
|
|
|
|
196: `/Adieresis`,
|
|
|
|
|
197: `/Aring`,
|
|
|
|
|
198: `/AE`,
|
|
|
|
|
199: `/Ccedilla`,
|
|
|
|
|
200: `/Egrave`,
|
|
|
|
|
201: `/Eacute`,
|
|
|
|
|
202: `/Ecircumflex`,
|
|
|
|
|
203: `/Edieresis`,
|
|
|
|
|
204: `/Igrave`,
|
|
|
|
|
205: `/Iacute`,
|
|
|
|
|
206: `/Icircumflex`,
|
|
|
|
|
207: `/Idieresis`,
|
|
|
|
|
208: `/Eth`,
|
|
|
|
|
209: `/Ntilde`,
|
|
|
|
|
210: `/Ograve`,
|
|
|
|
|
211: `/Oacute`,
|
|
|
|
|
212: `/Ocircumflex`,
|
|
|
|
|
213: `/Otilde`,
|
|
|
|
|
214: `/Odieresis`,
|
|
|
|
|
215: `/multiply`,
|
|
|
|
|
216: `/Oslash`,
|
|
|
|
|
217: `/Ugrave`,
|
|
|
|
|
218: `/Uacute`,
|
|
|
|
|
219: `/Ucircumflex`,
|
|
|
|
|
220: `/Udieresis`,
|
|
|
|
|
221: `/Yacute`,
|
|
|
|
|
222: `/Thorn`,
|
|
|
|
|
223: `/germandbls`,
|
|
|
|
|
224: `/agrave`,
|
|
|
|
|
225: `/aacute`,
|
|
|
|
|
226: `/acircumflex`,
|
|
|
|
|
227: `/atilde`,
|
|
|
|
|
228: `/adieresis`,
|
|
|
|
|
229: `/aring`,
|
|
|
|
|
230: `/ae`,
|
|
|
|
|
231: `/ccedilla`,
|
|
|
|
|
232: `/egrave`,
|
|
|
|
|
233: `/eacute`,
|
|
|
|
|
234: `/ecircumflex`,
|
|
|
|
|
235: `/edieresis`,
|
|
|
|
|
236: `/igrave`,
|
|
|
|
|
237: `/iacute`,
|
|
|
|
|
238: `/icircumflex`,
|
|
|
|
|
239: `/idieresis`,
|
|
|
|
|
240: `/eth`,
|
|
|
|
|
241: `/ntilde`,
|
|
|
|
|
242: `/ograve`,
|
|
|
|
|
243: `/oacute`,
|
|
|
|
|
244: `/ocircumflex`,
|
|
|
|
|
245: `/otilde`,
|
|
|
|
|
246: `/odieresis`,
|
|
|
|
|
247: `/divide`,
|
|
|
|
|
248: `/oslash`,
|
|
|
|
|
249: `/ugrave`,
|
|
|
|
|
250: `/uacute`,
|
|
|
|
|
251: `/ucircumflex`,
|
|
|
|
|
252: `/udieresis`,
|
|
|
|
|
253: `/yacute`,
|
|
|
|
|
254: `/thorn`,
|
|
|
|
|
255: `/ydieresis`,
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-29 04:02:20 +02:00
|
|
|
|
for ccode := textencoding.CharCode(32); ccode < 255; ccode++ {
|
|
|
|
|
fontglyph, has := font.Encoder().CharcodeToGlyph(ccode)
|
2018-11-01 21:33:51 +11:00
|
|
|
|
if !has {
|
2018-12-07 18:30:37 +02:00
|
|
|
|
baseglyph, bad := baseEncoding.CharcodeToGlyph(ccode)
|
2018-11-01 21:33:51 +11:00
|
|
|
|
if bad {
|
|
|
|
|
t.Fatalf("font not having glyph for char code %d - whereas base encoding had '%s'", ccode, baseglyph)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if in differencesmap first.
|
|
|
|
|
glyph, has := differencesMap[ccode]
|
|
|
|
|
if has {
|
2018-11-29 23:24:40 +02:00
|
|
|
|
glyph = textencoding.GlyphName(strings.Trim(string(glyph), `/`))
|
2018-11-01 21:33:51 +11:00
|
|
|
|
if glyph != fontglyph {
|
|
|
|
|
t.Fatalf("Mismatch for char code %d, font has: %s and expected is: %s (differences)", ccode, fontglyph, glyph)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If not in differences, should be according to StandardEncoding (base).
|
2018-12-07 18:30:37 +02:00
|
|
|
|
glyph, has = baseEncoding.CharcodeToGlyph(ccode)
|
2018-11-01 21:33:51 +11:00
|
|
|
|
if has && glyph != fontglyph {
|
|
|
|
|
t.Fatalf("Mismatch for char code %d (%X), font has: %s and expected is: %s (StandardEncoding)", ccode, ccode, fontglyph, glyph)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-30 16:18:56 +02:00
|
|
|
|
// newStandandTextEncoder returns a simpleEncoder that implements StandardEncoding.
|
2018-11-01 21:33:51 +11:00
|
|
|
|
// The non-symbolic standard 14 fonts have StandardEncoding.
|
|
|
|
|
func newStandandTextEncoder(t *testing.T) textencoding.SimpleEncoder {
|
|
|
|
|
enc, err := textencoding.NewSimpleTextEncoder("StandardEncoding", nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Error: %v", err)
|
|
|
|
|
}
|
2018-12-30 16:18:56 +02:00
|
|
|
|
return enc
|
2018-11-01 21:33:51 +11:00
|
|
|
|
}
|