Merge pull request #259 from dennwc/font_codes_strict

Strict types for runes, char codes and GIDs
This commit is contained in:
Gunnsteinn Hall 2018-12-07 15:20:45 +00:00 committed by GitHub
commit 01a87efdf3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 8701 additions and 8660 deletions

View File

@ -12,6 +12,7 @@ import (
"github.com/unidoc/unidoc/common"
"github.com/unidoc/unidoc/pdf/contentstream"
"github.com/unidoc/unidoc/pdf/core"
"github.com/unidoc/unidoc/pdf/internal/textencoding"
"github.com/unidoc/unidoc/pdf/model"
)
@ -33,7 +34,7 @@ type AppearanceStyle struct {
// How much of Rect height to fill when autosizing text.
AutoFontSizeFraction float64
// Glyph used for check mark in checkboxes (for ZapfDingbats font).
CheckmarkGlyph string
CheckmarkGlyph textencoding.GlyphName
BorderSize float64
BorderColor model.PdfColor
@ -1111,7 +1112,9 @@ func (style *AppearanceStyle) applyAppearanceCharacteristics(mkDict *core.PdfObj
if CA, has := core.GetString(mkDict.Get("CA")); has && font != nil {
encoded := CA.Bytes()
if len(encoded) == 1 {
if checkglyph, has := font.Encoder().CharcodeToGlyph(uint16(encoded[0])); has {
// TODO: this may be a multi-byte encoding
charcode := textencoding.CharCode(encoded[0])
if checkglyph, has := font.Encoder().CharcodeToGlyph(charcode); has {
style.CheckmarkGlyph = checkglyph
}
}

View File

@ -286,13 +286,15 @@ func (p *Paragraph) wrapText() error {
return nil
}
line := []rune{}
var line []rune
lineWidth := 0.0
p.textLines = []string{}
p.textLines = nil
runes := []rune(p.text)
glyphs := []string{}
widths := []float64{}
var (
glyphs []textencoding.GlyphName
widths []float64
)
for _, val := range runes {
glyph, found := p.textFont.Encoder().RuneToGlyph(val)
@ -305,10 +307,10 @@ func (p *Paragraph) wrapText() error {
if glyph == "controlLF" {
// Moves to next line.
p.textLines = append(p.textLines, string(line))
line = []rune{}
line = nil
lineWidth = 0
widths = []float64{}
glyphs = []string{}
widths = nil
glyphs = nil
continue
}
@ -345,7 +347,7 @@ func (p *Paragraph) wrapText() error {
} else {
p.textLines = append(p.textLines, string(line))
line = []rune{val}
glyphs = []string{glyph}
glyphs = []textencoding.GlyphName{glyph}
widths = []float64{w}
lineWidth = w
}

View File

@ -11,6 +11,8 @@ import (
"strings"
"unicode"
"github.com/unidoc/unidoc/pdf/internal/textencoding"
"github.com/unidoc/unidoc/common"
"github.com/unidoc/unidoc/pdf/contentstream"
"github.com/unidoc/unidoc/pdf/core"
@ -352,7 +354,7 @@ func (p *StyledParagraph) wrapText() error {
annotation := chunk.annotation
var part []rune
var glyphs []string
var glyphs []textencoding.GlyphName
var widths []float64
for _, r := range chunk.Text {
@ -373,12 +375,12 @@ func (p *StyledParagraph) wrapText() error {
annotation: copyAnnotation(annotation),
})
p.lines = append(p.lines, line)
line = []*TextChunk{}
line = nil
lineWidth = 0
part = []rune{}
widths = []float64{}
glyphs = []string{}
part = nil
widths = nil
glyphs = nil
continue
}
@ -422,7 +424,7 @@ func (p *StyledParagraph) wrapText() error {
} else {
lineWidth = w
part = []rune{r}
glyphs = []string{glyph}
glyphs = []textencoding.GlyphName{glyph}
widths = []float64{w}
}

View File

@ -54,11 +54,11 @@ type CMap struct {
codespaces []Codespace
// For ToUnicode (ctype 2) cmaps.
codeToUnicode map[CharCode]string
codeToUnicode map[CharCode]rune
}
// NewToUnicodeCMap returns an identity CMap with codeToUnicode matching the `codeToUnicode` arg.
func NewToUnicodeCMap(codeToUnicode map[CharCode]string) *CMap {
func NewToUnicodeCMap(codeToUnicode map[CharCode]rune) *CMap {
return &CMap{
name: "Adobe-Identity-UCS",
ctype: 2,
@ -102,11 +102,10 @@ func newCMap(isSimple bool) *CMap {
if isSimple {
nbits = 8
}
cmap := &CMap{
return &CMap{
nbits: nbits,
codeToUnicode: map[CharCode]string{},
codeToUnicode: make(map[CharCode]rune),
}
return cmap
}
// String returns a human readable description of `info`.
@ -153,9 +152,6 @@ func (cmap *CMap) Type() int {
// MissingCodeRune replaces runes that can't be decoded. '\ufffd' = <20>. Was '?'.
const MissingCodeRune = textencoding.MissingCodeRune
// MissingCodeString replaces strings that can't be decoded.
var MissingCodeString = string(MissingCodeRune)
// CharcodeBytesToUnicode converts a byte array of charcodes to a unicode string representation.
// It also returns a bool flag to tell if the conversion was successful.
// NOTE: This only works for ToUnicode cmaps.
@ -167,17 +163,19 @@ func (cmap *CMap) CharcodeBytesToUnicode(data []byte) (string, int) {
return "", 0
}
parts := []string{}
missing := []CharCode{}
var (
parts []rune
missing []CharCode
)
for _, code := range charcodes {
s, ok := cmap.codeToUnicode[code]
if !ok {
missing = append(missing, code)
s = MissingCodeString
s = MissingCodeRune
}
parts = append(parts, s)
}
unicode := strings.Join(parts, "")
unicode := string(parts)
if len(missing) > 0 {
common.Log.Debug("ERROR: CharcodeBytesToUnicode. Not in map.\n"+
"\tdata=[% 02x]=%#q\n"+
@ -191,13 +189,13 @@ func (cmap *CMap) CharcodeBytesToUnicode(data []byte) (string, int) {
}
// CharcodeToUnicode converts a single character code `code` to a unicode string.
// If `code` is not in the unicode map, "<22>" is returned.
// If `code` is not in the unicode map, '<27>' is returned.
// NOTE: CharcodeBytesToUnicode is typically more efficient.
func (cmap *CMap) CharcodeToUnicode(code CharCode) (string, bool) {
func (cmap *CMap) CharcodeToUnicode(code CharCode) (rune, bool) {
if s, ok := cmap.codeToUnicode[code]; ok {
return s, true
}
return MissingCodeString, false
return MissingCodeRune, false
}
// bytesToCharcodes attempts to convert the entire byte array `data` to a list of character codes
@ -207,7 +205,7 @@ func (cmap *CMap) CharcodeToUnicode(code CharCode) (string, bool) {
// matched?
// NOTE: A partial list of character codes will be returned if a complete match is not possible.
func (cmap *CMap) bytesToCharcodes(data []byte) ([]CharCode, bool) {
charcodes := []CharCode{}
var charcodes []CharCode
if cmap.nbits == 8 {
for _, b := range data {
charcodes = append(charcodes, CharCode(b))
@ -350,7 +348,7 @@ func (cmap *CMap) toBfData() string {
fbRanges = append(fbRanges, fbRange{
code0: cr.code0,
code1: cr.code1,
r0: []rune(cmap.codeToUnicode[cr.code0])[0],
r0: cmap.codeToUnicode[cr.code0],
})
}
}
@ -365,8 +363,7 @@ func (cmap *CMap) toBfData() string {
lines = append(lines, fmt.Sprintf("%d beginbfchar", n))
for j := 0; j < n; j++ {
code := fbChars[i*maxBfEntries+j]
s := cmap.codeToUnicode[code]
r := []rune(s)[0]
r := cmap.codeToUnicode[code]
lines = append(lines, fmt.Sprintf("<%04x> <%04x>", code, r))
}
lines = append(lines, "endbfchar")

View File

@ -391,8 +391,7 @@ func (cmap *CMap) parseBfchar() error {
}
return err
}
target := ""
var target rune
switch v := o.(type) {
case cmapOperand:
if v.Operand == endbfchar {
@ -401,10 +400,10 @@ func (cmap *CMap) parseBfchar() error {
common.Log.Debug("ERROR: Unexpected operand. %#v", v)
return ErrBadCMap
case cmapHexString:
target = hexToString(v)
target = hexToRune(v)
case cmapName:
common.Log.Debug("ERROR: Unexpected name. %#v", v)
target = MissingCodeString
target = MissingCodeRune
default:
common.Log.Debug("ERROR: Unexpected type. %#v", o)
return ErrBadCMap
@ -484,17 +483,16 @@ func (cmap *CMap) parseBfrange() error {
if !ok {
return errors.New("Non-hex string in array")
}
s := hexToString(hexs)
cmap.codeToUnicode[code] = s
r := hexToRune(hexs)
cmap.codeToUnicode[code] = r
}
case cmapHexString:
// <codeFrom> <codeTo> <dst>, maps [from,to] to [dst,dst+to-from].
target := hexToString(v)
runes := []rune(target)
r := hexToRune(v)
for code := srcCodeFrom; code <= srcCodeTo; code++ {
cmap.codeToUnicode[code] = string(runes)
runes[len(runes)-1]++
cmap.codeToUnicode[code] = r
r++
}
default:
common.Log.Debug("ERROR: Unexpected type %T", o)

View File

@ -104,14 +104,14 @@ func TestCMapParser1(t *testing.T) {
}
for k, expected := range expectedMappings {
if v, ok := cmap.CharcodeToUnicode(k); !ok || v != string(expected) {
if v, ok := cmap.CharcodeToUnicode(k); !ok || v != expected {
t.Errorf("incorrect mapping, expecting 0x%X ➞ 0x%X (%#v)", k, expected, v)
return
}
}
v, _ := cmap.CharcodeToUnicode(0x99)
if v != MissingCodeString { //!= "notdef" {
if v != MissingCodeRune { //!= "notdef" {
t.Errorf("Unmapped code, expected to map to undefined")
return
}
@ -188,7 +188,7 @@ func TestCMapParser2(t *testing.T) {
}
for k, expected := range expectedMappings {
if v, ok := cmap.CharcodeToUnicode(k); !ok || v != string(expected) {
if v, ok := cmap.CharcodeToUnicode(k); !ok || v != expected {
t.Errorf("incorrect mapping, expecting 0x%X ➞ 0x%X (got 0x%X)", k, expected, v)
return
}
@ -297,7 +297,7 @@ func TestCMapParser3(t *testing.T) {
0xd140: 0xa000,
}
for k, expected := range expectedMappings {
if v, ok := cmap.CharcodeToUnicode(k); !ok || v != string(expected) {
if v, ok := cmap.CharcodeToUnicode(k); !ok || v != expected {
t.Errorf("incorrect mapping: expecting 0x%02X ➞ 0x%02X (got 0x%02X)", k, expected, v)
return
}
@ -399,11 +399,11 @@ func TestCMapParser4(t *testing.T) {
return
}
expectedMappings := map[CharCode]string{
0x0889: "\U0001d484", // `𝒄`
0x0893: "\U0001d48e", // `𝒎`
0x08DD: "\U0001d49e", // `𝒞`
0x08E5: "\U0001d4a6", // `𝒦
expectedMappings := map[CharCode]rune{
0x0889: '\U0001d484', // `𝒄`
0x0893: '\U0001d48e', // `𝒎`
0x08DD: '\U0001d49e', // `𝒞`
0x08E5: '\U0001d4a6', // `𝒦
}
for k, expected := range expectedMappings {
@ -435,185 +435,185 @@ func TestCMapParser4(t *testing.T) {
}
var (
codeToUnicode1 = map[CharCode]string{ // 40 entries
0x02ca: "ˊ",
0x02cb: "ˋ",
0x02cd: "ˍ",
0x039c: "Μ",
0x039d: "Ν",
0x039e: "Ξ",
0x039f: "Ο",
0x03a0: "Π",
0x03a1: "Ρ",
0x03a6: "Φ",
0x03b1: "α",
0x03b2: "β",
0x03b3: "γ",
0x03b4: "δ",
0x03b5: "ε",
0x03b6: "ζ",
0x03b7: "η",
0x03c6: "φ",
0x03c7: "χ",
0x03c9: "ω",
0x2013: "",
0x2014: "—",
0x2018: "",
0x2019: "",
0x203e: "‾",
0x20ac: "€",
0x2163: "Ⅳ",
0x2164: "",
0x2165: "Ⅵ",
0x2166: "Ⅶ",
0x2167: "Ⅷ",
0x2168: "Ⅸ",
0x2169: "",
0x2190: "←",
0x2191: "↑",
0x2192: "→",
0x2193: "↓",
0x2220: "∠",
0x2223: "",
0x222a: "",
codeToUnicode1 = map[CharCode]rune{ // 40 entries
0x02ca: 'ˊ',
0x02cb: 'ˋ',
0x02cd: 'ˍ',
0x039c: 'Μ',
0x039d: 'Ν',
0x039e: 'Ξ',
0x039f: 'Ο',
0x03a0: 'Π',
0x03a1: 'Ρ',
0x03a6: 'Φ',
0x03b1: 'α',
0x03b2: 'β',
0x03b3: 'γ',
0x03b4: 'δ',
0x03b5: 'ε',
0x03b6: 'ζ',
0x03b7: 'η',
0x03c6: 'φ',
0x03c7: 'χ',
0x03c9: 'ω',
0x2013: '',
0x2014: '—',
0x2018: '',
0x2019: '',
0x203e: '‾',
0x20ac: '€',
0x2163: 'Ⅳ',
0x2164: '',
0x2165: 'Ⅵ',
0x2166: 'Ⅶ',
0x2167: 'Ⅷ',
0x2168: 'Ⅸ',
0x2169: '',
0x2190: '←',
0x2191: '↑',
0x2192: '→',
0x2193: '↓',
0x2220: '∠',
0x2223: '',
0x222a: '',
}
codeToUnicode2 = map[CharCode]string{ // 40 entries
0x0100: "Ā",
0x0101: "ā",
0x0102: "Ă",
0x0111: "đ",
0x0112: "Ē",
0x0113: "ē",
0x0114: "Ĕ",
0x0115: "ĕ",
0x0116: "Ė",
0x011b: "ě",
0x0126: "Ħ",
0x0127: "ħ",
0x0128: "Ĩ",
0x0129: "ĩ",
0x012a: "Ī",
0x012b: "ī",
0x012c: "Ĭ",
0x013b: "Ļ",
0x013c: "ļ",
0x013e: "ľ",
0x013f: "Ŀ",
0x0140: "ŀ",
0x0141: "Ł",
0x0150: "Ő",
0x0151: "ő",
0x0152: "Œ",
0x0153: "œ",
0x0154: "Ŕ",
0x0155: "ŕ",
0x015a: "Ś",
0x0165: "ť",
0x0166: "Ŧ",
0x0167: "ŧ",
0x0168: "Ũ",
0x0169: "ũ",
0x016a: "Ū",
0x016b: "ū",
0x017a: "ź",
0x017b: "Ż",
0x017d: "Ž",
codeToUnicode2 = map[CharCode]rune{ // 40 entries
0x0100: 'Ā',
0x0101: 'ā',
0x0102: 'Ă',
0x0111: 'đ',
0x0112: 'Ē',
0x0113: 'ē',
0x0114: 'Ĕ',
0x0115: 'ĕ',
0x0116: 'Ė',
0x011b: 'ě',
0x0126: 'Ħ',
0x0127: 'ħ',
0x0128: 'Ĩ',
0x0129: 'ĩ',
0x012a: 'Ī',
0x012b: 'ī',
0x012c: 'Ĭ',
0x013b: 'Ļ',
0x013c: 'ļ',
0x013e: 'ľ',
0x013f: 'Ŀ',
0x0140: 'ŀ',
0x0141: 'Ł',
0x0150: 'Ő',
0x0151: 'ő',
0x0152: 'Œ',
0x0153: 'œ',
0x0154: 'Ŕ',
0x0155: 'ŕ',
0x015a: 'Ś',
0x0165: 'ť',
0x0166: 'Ŧ',
0x0167: 'ŧ',
0x0168: 'Ũ',
0x0169: 'ũ',
0x016a: 'Ū',
0x016b: 'ū',
0x017a: 'ź',
0x017b: 'Ż',
0x017d: 'Ž',
}
codeToUnicode3 = map[CharCode]string{ // 93 entries
0x0124: "Ĥ",
0x0125: "ĥ",
0x0126: "Ħ",
0x0127: "ħ",
0x0134: "Ĵ",
0x0135: "ĵ",
0x0136: "Ķ",
0x0137: "ķ",
0x0138: "ĸ",
0x0144: "ń",
0x0145: "Ņ",
0x0146: "ņ",
0x0147: "Ň",
0x0154: "Ŕ",
0x0155: "ŕ",
0x0156: "Ŗ",
0x0157: "ŗ",
0x0164: "Ť",
0x0169: "ũ",
0x0174: "Ŵ",
0x0175: "ŵ",
0x0176: "Ŷ",
0x0177: "ŷ",
0x0184: "Ƅ",
0x0185: "ƅ",
0x0186: "Ɔ",
0x0187: "Ƈ",
0x0194: "Ɣ",
0x019a: "ƚ",
0x01a4: "Ƥ",
0x01a5: "ƥ",
0x01a6: "Ʀ",
0x01a7: "Ƨ",
0x01b4: "ƴ",
0x01b5: "Ƶ",
0x01b6: "ƶ",
0x01b7: "Ʒ",
0x01c4: "DŽ",
0x01cb: "Nj",
0x01d4: "ǔ",
0x01d5: "Ǖ",
0x01d6: "ǖ",
0x01d7: "Ǘ",
0x01e4: "Ǥ",
0x01e5: "ǥ",
0x01e6: "Ǧ",
0x01e7: "ǧ",
0x01f4: "Ǵ",
0x01f5: "ǵ",
0x0204: "Ȅ",
0x0205: "ȅ",
0x0206: "Ȇ",
0x0207: "ȇ",
0x0214: "Ȕ",
0x0215: "ȕ",
0x0216: "Ȗ",
0x0217: "ȗ",
0x0224: "Ȥ",
0x0226: "Ȧ",
0x0227: "ȧ",
0x0254: "ɔ",
0x0255: "ɕ",
0x0256: "ɖ",
0x0257: "ɗ",
0x0264: "ɤ",
0x0265: "ɥ",
0x0266: "ɦ",
0x0267: "ɧ",
0x0273: "ɳ",
0x0274: "ɴ",
0x0275: "ɵ",
0x0276: "ɶ",
0x0277: "ɷ",
0x0284: "ʄ",
0x0285: "ʅ",
0x0286: "ʆ",
0x0287: "ʇ",
0x0294: "ʔ",
0x0296: "ʖ",
0x0297: "ʗ",
0x02a4: "ʤ",
0x02a5: "ʥ",
0x02c6: "ˆ",
0x02c7: "ˇ",
0x0304: "̄",
0x0305: "̅",
0x0306: "̆",
0x0307: "̇",
0x030d: "̍",
0x0314: "̔",
0x0315: "̕",
0x0316: "̖",
0x0317: "̗",
codeToUnicode3 = map[CharCode]rune{ // 93 entries
0x0124: 'Ĥ',
0x0125: 'ĥ',
0x0126: 'Ħ',
0x0127: 'ħ',
0x0134: 'Ĵ',
0x0135: 'ĵ',
0x0136: 'Ķ',
0x0137: 'ķ',
0x0138: 'ĸ',
0x0144: 'ń',
0x0145: 'Ņ',
0x0146: 'ņ',
0x0147: 'Ň',
0x0154: 'Ŕ',
0x0155: 'ŕ',
0x0156: 'Ŗ',
0x0157: 'ŗ',
0x0164: 'Ť',
0x0169: 'ũ',
0x0174: 'Ŵ',
0x0175: 'ŵ',
0x0176: 'Ŷ',
0x0177: 'ŷ',
0x0184: 'Ƅ',
0x0185: 'ƅ',
0x0186: 'Ɔ',
0x0187: 'Ƈ',
0x0194: 'Ɣ',
0x019a: 'ƚ',
0x01a4: 'Ƥ',
0x01a5: 'ƥ',
0x01a6: 'Ʀ',
0x01a7: 'Ƨ',
0x01b4: 'ƴ',
0x01b5: 'Ƶ',
0x01b6: 'ƶ',
0x01b7: 'Ʒ',
0x01c4: 'DŽ',
0x01cb: 'Nj',
0x01d4: 'ǔ',
0x01d5: 'Ǖ',
0x01d6: 'ǖ',
0x01d7: 'Ǘ',
0x01e4: 'Ǥ',
0x01e5: 'ǥ',
0x01e6: 'Ǧ',
0x01e7: 'ǧ',
0x01f4: 'Ǵ',
0x01f5: 'ǵ',
0x0204: 'Ȅ',
0x0205: 'ȅ',
0x0206: 'Ȇ',
0x0207: 'ȇ',
0x0214: 'Ȕ',
0x0215: 'ȕ',
0x0216: 'Ȗ',
0x0217: 'ȗ',
0x0224: 'Ȥ',
0x0226: 'Ȧ',
0x0227: 'ȧ',
0x0254: 'ɔ',
0x0255: 'ɕ',
0x0256: 'ɖ',
0x0257: 'ɗ',
0x0264: 'ɤ',
0x0265: 'ɥ',
0x0266: 'ɦ',
0x0267: 'ɧ',
0x0273: 'ɳ',
0x0274: 'ɴ',
0x0275: 'ɵ',
0x0276: 'ɶ',
0x0277: 'ɷ',
0x0284: 'ʄ',
0x0285: 'ʅ',
0x0286: 'ʆ',
0x0287: 'ʇ',
0x0294: 'ʔ',
0x0296: 'ʖ',
0x0297: 'ʗ',
0x02a4: 'ʤ',
0x02a5: 'ʥ',
0x02c6: 'ˆ',
0x02c7: 'ˇ',
0x0304: '̄',
0x0305: '̅',
0x0306: '̆',
0x0307: '̇',
0x030d: '̍',
0x0314: '̔',
0x0315: '̕',
0x0316: '̖',
0x0317: '̗',
}
)
@ -662,7 +662,7 @@ func TestCMapCreation(t *testing.T) {
// checkCmapWriteRead creates CMap data from `codeToUnicode` then parses it and checks that the
// same codeToUnicode is returned.
func checkCmapWriteRead(t *testing.T, codeToUnicode map[CharCode]string) {
func checkCmapWriteRead(t *testing.T, codeToUnicode map[CharCode]rune) {
cmap0 := NewToUnicodeCMap(codeToUnicode)
data := cmap0.Bytes()

View File

@ -21,16 +21,11 @@ func hexToCharCode(shex cmapHexString) CharCode {
return code
}
// hexToString returns the unicode string that is UTF-16BE encoded in `shex`.
// hexToString decodes the UTF-16BE encoded string `shex` to unicode runes.
// 9.10.3 ToUnicode CMaps (page 293)
// • It shall use the beginbfchar, endbfchar, beginbfrange, and endbfrange operators to define the
// mapping from character codes to Unicode character sequences expressed in UTF-16BE encoding.
func hexToString(shex cmapHexString) string {
return string(utf16ToRunes(shex))
}
// hexToString decodes the UTF-16BE encoded string `shex` to unicode runes.
func utf16ToRunes(shex cmapHexString) []rune {
func hexToRunes(shex cmapHexString) []rune {
if len(shex.b) == 1 {
return []rune{rune(shex.b[0])}
}
@ -47,3 +42,16 @@ func utf16ToRunes(shex cmapHexString) []rune {
runes := utf16.Decode(chars)
return runes
}
// hexToRune is the same as hexToRunes but expects only a single rune to be decoded.
func hexToRune(shex cmapHexString) rune {
runes := hexToRunes(shex)
if n := len(runes); n == 0 {
common.Log.Debug("ERROR: hexToRune. Expected at least one rune shex=%#v", shex)
return MissingCodeRune
}
if len(runes) > 1 {
common.Log.Debug("ERROR: hexToRune. Expected exactly one rune shex=%#v -> %#v", shex, runes)
}
return runes[0]
}

View File

@ -12,6 +12,12 @@ import (
"github.com/unidoc/unidoc/pdf/core"
)
// CharCode is a character code used in the specific encoding.
type CharCode uint16
// GlyphName is a name of a glyph.
type GlyphName string
// TextEncoder defines the common methods that a text encoder implementation must have in UniDoc.
type TextEncoder interface {
// String returns a string that describes the TextEncoder instance.
@ -22,29 +28,29 @@ type TextEncoder interface {
// CharcodeToGlyph returns the glyph name for character code `code`.
// The bool return flag is true if there was a match, and false otherwise.
CharcodeToGlyph(code uint16) (string, bool)
CharcodeToGlyph(code CharCode) (GlyphName, bool)
// GlyphToCharcode returns the PDF character code corresponding to glyph name `glyph`.
// The bool return flag is true if there was a match, and false otherwise.
GlyphToCharcode(glyph string) (uint16, bool)
GlyphToCharcode(glyph GlyphName) (CharCode, bool)
// RuneToCharcode returns the PDF character code corresponding to rune `r`.
// The bool return flag is true if there was a match, and false otherwise.
// This is usually implemented as RuneToGlyph->GlyphToCharcode
RuneToCharcode(r rune) (uint16, bool)
RuneToCharcode(r rune) (CharCode, bool)
// CharcodeToRune returns the rune corresponding to character code `code`.
// The bool return flag is true if there was a match, and false otherwise.
// This is usually implemented as CharcodeToGlyph->GlyphToRune
CharcodeToRune(code uint16) (rune, bool)
CharcodeToRune(code CharCode) (rune, bool)
// RuneToGlyph returns the glyph name for rune `r`.
// The bool return flag is true if there was a match, and false otherwise.
RuneToGlyph(r rune) (string, bool)
RuneToGlyph(r rune) (GlyphName, bool)
// GlyphToRune returns the rune corresponding to glyph name `glyph`.
// The bool return flag is true if there was a match, and false otherwise.
GlyphToRune(glyph string) (rune, bool)
GlyphToRune(glyph GlyphName) (rune, bool)
// ToPdfObject returns a PDF Object that represents the encoding.
ToPdfObject() core.PdfObject
@ -82,7 +88,7 @@ func encodeString16bit(enc TextEncoder, raw string) []byte {
// Each entry represented by 2 bytes.
var v [2]byte
binary.BigEndian.PutUint16(v[:], code)
binary.BigEndian.PutUint16(v[:], uint16(code))
encoded = append(encoded, v[:]...)
}
return encoded
@ -90,7 +96,7 @@ func encodeString16bit(enc TextEncoder, raw string) []byte {
// doRuneToCharcode converts rune `r` to a PDF character code.
// The bool return flag is true if there was a match, and false otherwise.
func doRuneToCharcode(enc TextEncoder, r rune) (uint16, bool) {
func doRuneToCharcode(enc TextEncoder, r rune) (CharCode, bool) {
g, ok := enc.RuneToGlyph(r)
if !ok {
return 0, false
@ -100,7 +106,7 @@ func doRuneToCharcode(enc TextEncoder, r rune) (uint16, bool) {
// doCharcodeToRune converts PDF character code `code` to a rune.
// The bool return flag is true if there was a match, and false otherwise.
func doCharcodeToRune(enc TextEncoder, code uint16) (rune, bool) {
func doCharcodeToRune(enc TextEncoder, code CharCode) (rune, bool) {
g, ok := enc.CharcodeToGlyph(code)
if !ok {
return 0, false

File diff suppressed because it is too large Load Diff

View File

@ -36,20 +36,20 @@ func (enc IdentityEncoder) Encode(raw string) []byte {
// CharcodeToGlyph returns the glyph name matching character code `code`.
// The bool return flag is true if there was a match, and false otherwise.
func (enc IdentityEncoder) CharcodeToGlyph(code uint16) (string, bool) {
func (enc IdentityEncoder) CharcodeToGlyph(code CharCode) (GlyphName, bool) {
r, found := enc.CharcodeToRune(code)
if found && r == 0x20 {
return "space", true
}
// Returns "uniXXXX" format where XXXX is the code in hex format.
glyph := fmt.Sprintf("uni%.4X", code)
glyph := GlyphName(fmt.Sprintf("uni%.4X", code))
return glyph, true
}
// GlyphToCharcode returns the character code matching glyph `glyph`.
// The bool return flag is true if there was a match, and false otherwise.
func (enc IdentityEncoder) GlyphToCharcode(glyph string) (uint16, bool) {
func (enc IdentityEncoder) GlyphToCharcode(glyph GlyphName) (CharCode, bool) {
r, ok := enc.GlyphToRune(glyph)
if !ok {
return 0, false
@ -59,36 +59,36 @@ func (enc IdentityEncoder) GlyphToCharcode(glyph string) (uint16, bool) {
// RuneToCharcode converts rune `r` to a PDF character code.
// The bool return flag is true if there was a match, and false otherwise.
func (enc IdentityEncoder) RuneToCharcode(r rune) (uint16, bool) {
return uint16(r), true
func (enc IdentityEncoder) RuneToCharcode(r rune) (CharCode, bool) {
return CharCode(r), true
}
// CharcodeToRune converts PDF character code `code` to a rune.
// The bool return flag is true if there was a match, and false otherwise.
func (enc IdentityEncoder) CharcodeToRune(code uint16) (rune, bool) {
func (enc IdentityEncoder) CharcodeToRune(code CharCode) (rune, bool) {
return rune(code), true
}
// RuneToGlyph returns the glyph name for rune `r`.
// The bool return flag is true if there was a match, and false otherwise.
func (enc IdentityEncoder) RuneToGlyph(r rune) (string, bool) {
func (enc IdentityEncoder) RuneToGlyph(r rune) (GlyphName, bool) {
if r == ' ' {
return "space", true
}
glyph := fmt.Sprintf("uni%.4X", r)
glyph := GlyphName(fmt.Sprintf("uni%.4X", r))
return glyph, true
}
// GlyphToRune returns the rune corresponding to glyph name `glyph`.
// The bool return flag is true if there was a match, and false otherwise.
func (enc IdentityEncoder) GlyphToRune(glyph string) (rune, bool) {
func (enc IdentityEncoder) GlyphToRune(glyph GlyphName) (rune, bool) {
// String with "uniXXXX" format where XXXX is the hexcode.
if glyph == "space" {
return ' ', true
} else if !strings.HasPrefix(glyph, "uni") || len(glyph) != 7 {
} else if !strings.HasPrefix(string(glyph), "uni") || len(glyph) != 7 {
return 0, false
}
r, err := strconv.ParseUint(glyph[3:], 16, 16)
r, err := strconv.ParseUint(string(glyph[3:]), 16, 16)
if err != nil {
return 0, false
}

View File

@ -25,20 +25,22 @@ import (
// SimpleEncoder represents a 1 byte encoding
type SimpleEncoder struct {
baseName string
baseEncoding map[uint16]rune
differences map[byte]string
CodeToGlyph map[uint16]string
glyphToCode map[string]uint16
codeToRune map[uint16]rune
baseName string
baseEncoding map[CharCode]rune
differences map[CharCode]GlyphName
codeToGlyph map[CharCode]GlyphName
glyphToCode map[GlyphName]CharCode
codeToRune map[CharCode]rune
}
// NewCustomSimpleTextEncoder returns a SimpleEncoder based on map `encoding` and difference map
// `differences`.
func NewCustomSimpleTextEncoder(encoding map[uint16]string, differences map[byte]string) (
func NewCustomSimpleTextEncoder(encoding, differences map[CharCode]GlyphName) (
*SimpleEncoder, error) {
baseName := "custom"
baseEncoding := map[uint16]rune{}
baseEncoding := make(map[CharCode]rune)
if len(encoding) == 0 {
return &SimpleEncoder{}, errors.New("Empty custom encoding")
}
@ -54,14 +56,14 @@ func NewCustomSimpleTextEncoder(encoding map[uint16]string, differences map[byte
}
// ApplyDifferences applies the encoding delta `differences` to `se`.
func (se *SimpleEncoder) ApplyDifferences(differences map[byte]string) {
func (se *SimpleEncoder) ApplyDifferences(differences map[CharCode]GlyphName) {
se.differences = differences
se.computeTables()
}
// NewSimpleTextEncoder returns a SimpleEncoder based on predefined encoding `baseName` and
// difference map `differences`.
func NewSimpleTextEncoder(baseName string, differences map[byte]string) (*SimpleEncoder, error) {
func NewSimpleTextEncoder(baseName string, differences map[CharCode]GlyphName) (*SimpleEncoder, error) {
baseEncoding, ok := simpleEncodings[baseName]
if !ok {
common.Log.Debug("ERROR: NewSimpleTextEncoder. Unknown encoding %q", baseName)
@ -72,8 +74,8 @@ func NewSimpleTextEncoder(baseName string, differences map[byte]string) (*Simple
// newSimpleTextEncoder returns a SimpleEncoder based on map `encoding` and difference map
// `differences`.
func newSimpleTextEncoder(baseEncoding map[uint16]rune, baseName string,
differences map[byte]string) (*SimpleEncoder, error) {
func newSimpleTextEncoder(baseEncoding map[CharCode]rune, baseName string,
differences map[CharCode]GlyphName) (*SimpleEncoder, error) {
se := SimpleEncoder{
baseName: baseName,
@ -94,15 +96,17 @@ func (se SimpleEncoder) String() string {
name = fmt.Sprintf("%s(diff)", se.baseName)
}
parts := []string{
fmt.Sprintf("%#q %d entries %d differences", name, len(se.CodeToGlyph), len(se.differences)),
fmt.Sprintf("%#q %d entries %d differences", name, len(se.codeToGlyph), len(se.differences)),
fmt.Sprintf("differences=%+v", se.differences),
}
codes := []int{}
for c := range se.CodeToGlyph {
codes = append(codes, int(c))
codes := make([]CharCode, 0, len(se.codeToGlyph))
for c := range se.codeToGlyph {
codes = append(codes, c)
}
sort.Ints(codes)
sort.Slice(codes, func(i, j int) bool {
return codes[i] < codes[j]
})
numCodes := len(codes)
if numCodes > simpleEncoderNumEntries {
numCodes = simpleEncoderNumEntries
@ -110,7 +114,7 @@ func (se SimpleEncoder) String() string {
for i := 0; i < numCodes; i++ {
c := codes[i]
parts = append(parts, fmt.Sprintf("%d=0x%02x: %q", c, c, se.CodeToGlyph[uint16(c)]))
parts = append(parts, fmt.Sprintf("%d=0x%02x: %q", c, c, se.codeToGlyph[c]))
}
return fmt.Sprintf("SIMPLE_ENCODER{%s}", strings.Join(parts, ", "))
}
@ -122,8 +126,8 @@ func (se SimpleEncoder) Encode(raw string) []byte {
// CharcodeToGlyph returns the glyph name for character code `code`.
// The bool return flag is true if there was a match, and false otherwise.
func (se SimpleEncoder) CharcodeToGlyph(code uint16) (string, bool) {
glyph, ok := se.CodeToGlyph[code]
func (se SimpleEncoder) CharcodeToGlyph(code CharCode) (GlyphName, bool) {
glyph, ok := se.codeToGlyph[code]
if !ok {
common.Log.Debug("Charcode -> Glyph error: charcode not found: 0x%04x", code)
}
@ -132,7 +136,7 @@ func (se SimpleEncoder) CharcodeToGlyph(code uint16) (string, bool) {
// GlyphToCharcode returns character code for glyph `glyph`.
// The bool return flag is true if there was a match, and false otherwise.
func (se SimpleEncoder) GlyphToCharcode(glyph string) (uint16, bool) {
func (se SimpleEncoder) GlyphToCharcode(glyph GlyphName) (CharCode, bool) {
code, ok := se.glyphToCode[glyph]
if !ok {
common.Log.Debug("Glyph -> Charcode error: glyph not found: %q %s", glyph, se)
@ -142,13 +146,13 @@ func (se SimpleEncoder) GlyphToCharcode(glyph string) (uint16, bool) {
// RuneToCharcode returns the PDF character code corresponding to rune `r`.
// The bool return flag is true if there was a match, and false otherwise.
func (se SimpleEncoder) RuneToCharcode(val rune) (uint16, bool) {
func (se SimpleEncoder) RuneToCharcode(val rune) (CharCode, bool) {
return doRuneToCharcode(se, val)
}
// CharcodeToRune returns the rune corresponding to character code `code`.
// The bool return flag is true if there was a match, and false otherwise.
func (se SimpleEncoder) CharcodeToRune(code uint16) (rune, bool) {
func (se SimpleEncoder) CharcodeToRune(code CharCode) (rune, bool) {
r, ok := se.codeToRune[code]
if !ok {
common.Log.Debug("Charcode -> Rune error: charcode not found: 0x%04x", code)
@ -158,13 +162,13 @@ func (se SimpleEncoder) CharcodeToRune(code uint16) (rune, bool) {
// RuneToGlyph returns the glyph corresponding to rune `r`.
// The bool return flag is true if there was a match, and false otherwise.
func (se SimpleEncoder) RuneToGlyph(r rune) (string, bool) {
func (se SimpleEncoder) RuneToGlyph(r rune) (GlyphName, bool) {
return runeToGlyph(r, glyphlistRuneToGlyphMap)
}
// GlyphToRune returns the rune corresponding to glyph `glyph`.
// The bool return flag is true if there was a match, and false otherwise.
func (se SimpleEncoder) GlyphToRune(glyph string) (rune, bool) {
func (se SimpleEncoder) GlyphToRune(glyph GlyphName) (rune, bool) {
return glyphToRune(glyph, glyphlistGlyphToRuneMap)
}
@ -187,46 +191,44 @@ func (se SimpleEncoder) ToPdfObject() core.PdfObject {
// computeTables computes the tables needed for a working SimpleEncoder from the member
// fields `baseEncoding` and `differences`.
func (se *SimpleEncoder) computeTables() {
codeToRune := map[uint16]rune{}
codeToRune := make(map[CharCode]rune)
for code, r := range se.baseEncoding {
codeToRune[code] = r
}
if se.differences != nil {
for code, glyph := range se.differences {
r, ok := GlyphToRune(glyph)
if !ok {
common.Log.Debug("ERROR: No match for glyph=%q differences=%+v", glyph,
se.differences)
}
codeToRune[uint16(code)] = r
for code, glyph := range se.differences {
r, ok := GlyphToRune(glyph)
if !ok {
common.Log.Debug("ERROR: No match for glyph=%q differences=%+v", glyph,
se.differences)
}
codeToRune[code] = r
}
codeToGlyph := map[uint16]string{}
glyphToCode := map[string]uint16{}
codeToGlyph := make(map[CharCode]GlyphName)
glyphToCode := make(map[GlyphName]CharCode)
for code, r := range codeToRune {
if glyph, ok := RuneToGlyph(r); ok {
codeToGlyph[code] = glyph
glyphToCode[glyph] = code
}
}
se.CodeToGlyph = codeToGlyph
se.codeToGlyph = codeToGlyph
se.glyphToCode = glyphToCode
se.codeToRune = codeToRune
}
// FromFontDifferences converts `diffList` (a /Differences array from an /Encoding object) to a map
// representing character code to glyph mappings.
func FromFontDifferences(diffList *core.PdfObjectArray) (map[byte]string, error) {
differences := map[byte]string{}
var n byte
func FromFontDifferences(diffList *core.PdfObjectArray) (map[CharCode]GlyphName, error) {
differences := make(map[CharCode]GlyphName)
var n CharCode
for _, obj := range diffList.Elements() {
switch v := obj.(type) {
case *core.PdfObjectInteger:
n = byte(*v)
n = CharCode(*v)
case *core.PdfObjectName:
s := string(*v)
differences[n] = s
differences[n] = GlyphName(s)
n++
default:
common.Log.Debug("ERROR: Bad type. obj=%s", obj)
@ -238,12 +240,12 @@ func FromFontDifferences(diffList *core.PdfObjectArray) (map[byte]string, error)
// ToFontDifferences converts `differences` (a map representing character code to glyph mappings)
// to a /Differences array for an /Encoding object.
func ToFontDifferences(differences map[byte]string) *core.PdfObjectArray {
func ToFontDifferences(differences map[CharCode]GlyphName) *core.PdfObjectArray {
if len(differences) == 0 {
return nil
}
codes := []byte{}
codes := make([]CharCode, 0, len(differences))
for c := range differences {
codes = append(codes, c)
}
@ -252,10 +254,10 @@ func ToFontDifferences(differences map[byte]string) *core.PdfObjectArray {
})
n := codes[0]
diffList := []core.PdfObject{core.MakeInteger(int64(n)), core.MakeName(differences[n])}
diffList := []core.PdfObject{core.MakeInteger(int64(n)), core.MakeName(string(differences[n]))}
for _, c := range codes[1:] {
if c == n+1 {
diffList = append(diffList, core.MakeName(differences[c]))
diffList = append(diffList, core.MakeName(string(differences[c])))
} else {
diffList = append(diffList, core.MakeInteger(int64(c)))
}
@ -265,7 +267,7 @@ func ToFontDifferences(differences map[byte]string) *core.PdfObjectArray {
}
// simpleEncodings is a map of the standard 8 bit character encodings.
var simpleEncodings = map[string]map[uint16]rune{
var simpleEncodings = map[string]map[CharCode]rune{
"MacExpertEncoding": { // 165 entries
0x20: 0x0020, // "space"
0x21: 0xf721, // "exclamsmall"

View File

@ -26,19 +26,19 @@ func TestBasicEncodings(t *testing.T) {
}
var testCases = []encodingTest{
encodingTest{"MacExpertEncoding", "₂₃₄₅", []string{"twoinferior", "threeinferior", "fourinferior", "fiveinferior"}},
encodingTest{"MacRomanEncoding", "◊fl˝ˇ", []string{"lozenge", "fl", "hungarumlaut", "caron"}},
encodingTest{"PdfDocEncoding", "¾Ðí©", []string{"threequarters", "Eth", "iacute", "copyright"}},
encodingTest{"StandardEncoding", "ºªı„", []string{"ordmasculine", "ordfeminine", "dotlessi", "quotedblbase"}},
encodingTest{"SymbolEncoding", "δ∂ℵ⌡", []string{"delta", "partialdiff", "aleph", "integralbt"}},
encodingTest{"WinAnsiEncoding", "×÷®Ï", []string{"multiply", "divide", "registered", "Idieresis"}},
encodingTest{"ZapfDingbatsEncoding", "☎①➔➨", []string{"a4", "a120", "a160", "a178"}},
{"MacExpertEncoding", "₂₃₄₅", []GlyphName{"twoinferior", "threeinferior", "fourinferior", "fiveinferior"}},
{"MacRomanEncoding", "◊fl˝ˇ", []GlyphName{"lozenge", "fl", "hungarumlaut", "caron"}},
{"PdfDocEncoding", "¾Ðí©", []GlyphName{"threequarters", "Eth", "iacute", "copyright"}},
{"StandardEncoding", "ºªı„", []GlyphName{"ordmasculine", "ordfeminine", "dotlessi", "quotedblbase"}},
{"SymbolEncoding", "δ∂ℵ⌡", []GlyphName{"delta", "partialdiff", "aleph", "integralbt"}},
{"WinAnsiEncoding", "×÷®Ï", []GlyphName{"multiply", "divide", "registered", "Idieresis"}},
{"ZapfDingbatsEncoding", "☎①➔➨", []GlyphName{"a4", "a120", "a160", "a178"}},
}
type encodingTest struct {
encoding string
runes string
glyphs []string
glyphs []GlyphName
}
func (f *encodingTest) String() string {

View File

@ -14,23 +14,26 @@ import (
"github.com/unidoc/unidoc/pdf/core"
)
// GID is a glyph index.
type GID uint16
// TrueTypeFontEncoder handles text encoding for composite TrueType fonts.
// It performs mapping between character ids and glyph ids.
// It has a preloaded rune (unicode code point) to glyph index map that has been loaded from a font.
// Corresponds to Identity-H.
type TrueTypeFontEncoder struct {
runeToGlyphIndexMap map[uint16]uint16
cmap CMap
runeToGIDMap map[rune]GID
cmap CMap
}
// NewTrueTypeFontEncoder creates a new text encoder for TTF fonts with a pre-loaded
// runeToGlyphIndexMap, that has been pre-loaded from the font file.
// runeToGIDMap, that has been pre-loaded from the font file.
// The new instance is preloaded with a CMapIdentityH (Identity-H) CMap which maps 2-byte charcodes
// to CIDs (glyph index).
func NewTrueTypeFontEncoder(runeToGlyphIndexMap map[uint16]uint16) TrueTypeFontEncoder {
func NewTrueTypeFontEncoder(runeToGIDMap map[rune]GID) TrueTypeFontEncoder {
return TrueTypeFontEncoder{
runeToGlyphIndexMap: runeToGlyphIndexMap,
cmap: CMapIdentityH{},
runeToGIDMap: runeToGIDMap,
cmap: CMapIdentityH{},
}
}
@ -40,23 +43,25 @@ const ttEncoderMaxNumEntries = 10
// String returns a string that describes `enc`.
func (enc TrueTypeFontEncoder) String() string {
parts := []string{
fmt.Sprintf("%d entries", len(enc.runeToGlyphIndexMap)),
fmt.Sprintf("%d entries", len(enc.runeToGIDMap)),
}
codes := []int{}
for c := range enc.runeToGlyphIndexMap {
codes = append(codes, int(c))
runes := make([]rune, 0, len(enc.runeToGIDMap))
for r := range enc.runeToGIDMap {
runes = append(runes, r)
}
sort.Ints(codes)
numCodes := len(codes)
if numCodes > ttEncoderMaxNumEntries {
numCodes = ttEncoderMaxNumEntries
sort.Slice(runes, func(i, j int) bool {
return runes[i] < runes[j]
})
n := len(runes)
if n > ttEncoderMaxNumEntries {
n = ttEncoderMaxNumEntries
}
for i := 0; i < numCodes; i++ {
c := codes[i]
for i := 0; i < n; i++ {
r := runes[i]
parts = append(parts, fmt.Sprintf("%d=0x%02x: %q",
c, c, enc.runeToGlyphIndexMap[uint16(c)]))
r, r, enc.runeToGIDMap[r]))
}
return fmt.Sprintf("TRUETYPE_ENCODER{%s}", strings.Join(parts, ", "))
}
@ -68,24 +73,24 @@ func (enc TrueTypeFontEncoder) Encode(raw string) []byte {
// CharcodeToGlyph returns the glyph name matching character code `code`.
// The bool return flag is true if there was a match, and false otherwise.
func (enc TrueTypeFontEncoder) CharcodeToGlyph(code uint16) (string, bool) {
func (enc TrueTypeFontEncoder) CharcodeToGlyph(code CharCode) (GlyphName, bool) {
r, found := enc.CharcodeToRune(code)
if found && r == 0x20 {
return "space", true
}
// Returns "uniXXXX" format where XXXX is the code in hex format.
glyph := fmt.Sprintf("uni%.4X", code)
glyph := GlyphName(fmt.Sprintf("uni%.4X", code))
return glyph, true
}
// GlyphToCharcode returns character code matching the glyph name `glyph`.
// The bool return flag is true if there was a match, and false otherwise.
func (enc TrueTypeFontEncoder) GlyphToCharcode(glyph string) (uint16, bool) {
func (enc TrueTypeFontEncoder) GlyphToCharcode(glyph GlyphName) (CharCode, bool) {
// String with "uniXXXX" format where XXXX is the hexcode.
if len(glyph) == 7 && glyph[0:3] == "uni" {
var unicode uint16
n, err := fmt.Sscanf(glyph, "uni%X", &unicode)
n, err := fmt.Sscanf(string(glyph), "uni%X", &unicode)
if n == 1 && err == nil {
return enc.RuneToCharcode(rune(unicode))
}
@ -102,25 +107,29 @@ func (enc TrueTypeFontEncoder) GlyphToCharcode(glyph string) (uint16, bool) {
// RuneToCharcode converts rune `r` to a PDF character code.
// The bool return flag is true if there was a match, and false otherwise.
func (enc TrueTypeFontEncoder) RuneToCharcode(r rune) (uint16, bool) {
glyphIndex, ok := enc.runeToGlyphIndexMap[uint16(r)]
func (enc TrueTypeFontEncoder) RuneToCharcode(r rune) (CharCode, bool) {
glyphIndex, ok := enc.runeToGIDMap[r]
if !ok {
common.Log.Debug("Missing rune %d (%+q) from encoding", r, r)
return 0, false
}
// Identity : charcode <-> glyphIndex
charcode := glyphIndex
// TODO(dennwc): Here charcode is probably the same as CID.
// TODO(dennwc): Find out what are the alternative mappings (enc.cmap?).
charcode := CharCode(glyphIndex)
return uint16(charcode), true
return charcode, true
}
// CharcodeToRune converts PDF character code `code` to a rune.
// The bool return flag is true if there was a match, and false otherwise.
func (enc TrueTypeFontEncoder) CharcodeToRune(code uint16) (rune, bool) {
func (enc TrueTypeFontEncoder) CharcodeToRune(code CharCode) (rune, bool) {
// TODO: Make a reverse map stored.
for code, glyphIndex := range enc.runeToGlyphIndexMap {
if glyphIndex == code {
return rune(code), true
for r, gid := range enc.runeToGIDMap {
// Identity : glyphIndex <-> charcode
charcode := CharCode(gid)
if charcode == code {
return r, true
}
}
common.Log.Debug("CharcodeToRune: No match. code=0x%04x enc=%s", code, enc)
@ -129,21 +138,21 @@ func (enc TrueTypeFontEncoder) CharcodeToRune(code uint16) (rune, bool) {
// RuneToGlyph returns the glyph name for rune `r`.
// The bool return flag is true if there was a match, and false otherwise.
func (enc TrueTypeFontEncoder) RuneToGlyph(r rune) (string, bool) {
func (enc TrueTypeFontEncoder) RuneToGlyph(r rune) (GlyphName, bool) {
if r == 0x20 {
return "space", true
}
glyph := fmt.Sprintf("uni%.4X", r)
glyph := GlyphName(fmt.Sprintf("uni%.4X", r))
return glyph, true
}
// GlyphToRune returns the rune corresponding to glyph name `glyph`.
// The bool return flag is true if there was a match, and false otherwise.
func (enc TrueTypeFontEncoder) GlyphToRune(glyph string) (rune, bool) {
func (enc TrueTypeFontEncoder) GlyphToRune(glyph GlyphName) (rune, bool) {
// String with "uniXXXX" format where XXXX is the hexcode.
if len(glyph) == 7 && glyph[0:3] == "uni" {
unicode := uint16(0)
n, err := fmt.Sscanf(glyph, "uni%X", &unicode)
n, err := fmt.Sscanf(string(glyph), "uni%X", &unicode)
if n == 1 && err == nil {
return rune(unicode), true
}

View File

@ -12,7 +12,7 @@ import (
"github.com/unidoc/unidoc/common"
)
func glyphToRune(glyph string, glyphToRuneMap map[string]rune) (rune, bool) {
func glyphToRune(glyph GlyphName, glyphToRuneMap map[GlyphName]rune) (rune, bool) {
r, ok := glyphToRuneMap[glyph]
if ok {
return r, true
@ -22,7 +22,7 @@ func glyphToRune(glyph string, glyphToRuneMap map[string]rune) (rune, bool) {
return 0, false
}
func runeToGlyph(r rune, runeToGlyphMap map[rune]string) (string, bool) {
func runeToGlyph(r rune, runeToGlyphMap map[rune]GlyphName) (GlyphName, bool) {
glyph, ok := runeToGlyphMap[r]
if ok {
return glyph, true

View File

@ -126,28 +126,27 @@ func NewStandard14FontWithEncoding(basefont Standard14Font, alphabet map[rune]in
}
// glyphCode are the encoding glyphs. We need to match them to the font glyphs.
glyphCode := map[string]byte{}
glyphCode := make(map[textencoding.GlyphName]textencoding.CharCode)
// slots are the indexes in the encoding where the new character codes are added.
// slots are unused indexes, which are filled first. slots1 are the used indexes.
slots := []byte{}
slots1 := []byte{}
for code := uint16(1); code <= 0xff; code++ {
if glyph, ok := encoder.CodeToGlyph[code]; ok {
glyphCode[glyph] = byte(code)
var slots, slots1 []textencoding.CharCode
for code := textencoding.CharCode(1); code <= 0xff; code++ {
if glyph, ok := encoder.CharcodeToGlyph(code); ok {
glyphCode[glyph] = code
// Don't overwrite space
if glyph != "space" {
slots1 = append(slots1, byte(code))
slots1 = append(slots1, code)
}
} else {
slots = append(slots, byte(code))
slots = append(slots, code)
}
}
slots = append(slots, slots1...)
// `glyphs` are the font glyphs that we need to encode.
glyphs := []string{}
var glyphs []textencoding.GlyphName
for _, r := range sortedAlphabet(alphabet) {
glyph, ok := textencoding.RuneToGlyph(r)
if !ok {
@ -168,7 +167,7 @@ func NewStandard14FontWithEncoding(basefont Standard14Font, alphabet map[rune]in
// Fill the slots, starting with the empty ones.
slotIdx := 0
differences := map[byte]string{}
differences := make(map[textencoding.CharCode]textencoding.GlyphName)
for _, glyph := range glyphs {
if _, ok := glyphCode[glyph]; !ok {
differences[slots[slotIdx]] = glyph
@ -304,7 +303,7 @@ func newPdfFontFromPdfObject(fontObj core.PdfObject, allowType0 bool) (*PdfFont,
func (font PdfFont) CharcodeBytesToUnicode(data []byte) (string, int, int) {
common.Log.Trace("showText: data=[% 02x]=%#q", data, data)
charcodes := make([]uint16, 0, len(data)+len(data)%2)
charcodes := make([]textencoding.CharCode, 0, len(data)+len(data)%2)
if font.baseFields().isCIDFont() {
if len(data) == 1 {
data = []byte{0, data[0]}
@ -315,11 +314,11 @@ func (font PdfFont) CharcodeBytesToUnicode(data []byte) (string, int, int) {
}
for i := 0; i < len(data); i += 2 {
b := uint16(data[i])<<8 | uint16(data[i+1])
charcodes = append(charcodes, b)
charcodes = append(charcodes, textencoding.CharCode(b))
}
} else {
for _, b := range data {
charcodes = append(charcodes, uint16(b))
charcodes = append(charcodes, textencoding.CharCode(b))
}
}
@ -329,7 +328,7 @@ func (font PdfFont) CharcodeBytesToUnicode(data []byte) (string, int, int) {
if font.baseFields().toUnicodeCmap != nil {
r, ok := font.baseFields().toUnicodeCmap.CharcodeToUnicode(cmap.CharCode(code))
if ok {
charstrings = append(charstrings, r)
charstrings = append(charstrings, string(r))
continue
}
}
@ -345,7 +344,7 @@ func (font PdfFont) CharcodeBytesToUnicode(data []byte) (string, int, int) {
"\tfont=%s\n\tencoding=%s",
code, data, data, charcodes, font.baseFields().isCIDFont(), font, encoder)
numMisses++
charstrings = append(charstrings, cmap.MissingCodeString)
charstrings = append(charstrings, string(cmap.MissingCodeRune))
}
}
@ -392,7 +391,7 @@ func (font PdfFont) SetEncoder(encoder textencoding.TextEncoder) {
}
// GetGlyphCharMetrics returns the specified char metrics for a specified glyph name.
func (font PdfFont) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics, bool) {
func (font PdfFont) GetGlyphCharMetrics(glyph textencoding.GlyphName) (fonts.CharMetrics, bool) {
t := font.actualFont()
if t == nil {
common.Log.Debug("ERROR: GetGlyphCharMetrics Not implemented for font type=%#T", font.context)

View File

@ -114,7 +114,7 @@ func (font *pdfFontType0) baseFields() *fontCommon {
// GetGlyphCharMetrics returns the character metrics for the specified glyph. A bool flag is
// returned to indicate whether or not the entry was found in the glyph to charcode mapping.
func (font pdfFontType0) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics, bool) {
func (font pdfFontType0) GetGlyphCharMetrics(glyph textencoding.GlyphName) (fonts.CharMetrics, bool) {
if font.DescendantFont == nil {
common.Log.Debug("ERROR: No descendant. font=%s", font)
return fonts.CharMetrics{}, false
@ -226,7 +226,7 @@ func (font pdfCIDFontType0) SetEncoder(encoder textencoding.TextEncoder) {
// GetGlyphCharMetrics returns the character metrics for the specified glyph. A bool flag is
// returned to indicate whether or not the entry was found in the glyph to charcode mapping.
func (font pdfCIDFontType0) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics, bool) {
func (font pdfCIDFontType0) GetGlyphCharMetrics(glyph textencoding.GlyphName) (fonts.CharMetrics, bool) {
return fonts.CharMetrics{}, true
}
@ -273,10 +273,10 @@ type pdfCIDFontType2 struct {
CIDToGIDMap core.PdfObject
// Mapping between unicode runes to widths.
runeToWidthMap map[uint16]int
runeToWidthMap map[rune]int
// Also mapping between GIDs (glyph index) and width.
gidToWidthMap map[uint16]int
gidToWidthMap map[fonts.GID]int
}
// pdfCIDFontType2FromSkeleton returns a pdfCIDFontType2 with its common fields initalized.
@ -303,7 +303,7 @@ func (font pdfCIDFontType2) SetEncoder(encoder textencoding.TextEncoder) {
// GetGlyphCharMetrics returns the character metrics for the specified glyph. A bool flag is
// returned to indicate whether or not the entry was found in the glyph to charcode mapping.
func (font pdfCIDFontType2) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics, bool) {
func (font pdfCIDFontType2) GetGlyphCharMetrics(glyph textencoding.GlyphName) (fonts.CharMetrics, bool) {
metrics := fonts.CharMetrics{}
enc := textencoding.NewTrueTypeFontEncoder(font.ttfParser.Chars)
@ -315,7 +315,7 @@ func (font pdfCIDFontType2) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics
return metrics, false
}
w, found := font.runeToWidthMap[uint16(r)]
w, found := font.runeToWidthMap[r]
if !found {
dw, ok := core.GetInt(font.DW)
if !ok {
@ -409,9 +409,9 @@ func NewCompositePdfFontFromTTFFile(filePath string) (*PdfFont, error) {
cidfont.ttfParser = &ttf
// 2-byte character codes ➞ runes
runes := make([]uint16, 0, len(ttf.Chars))
runes := make([]rune, 0, len(ttf.Chars))
for r := range ttf.Chars {
runes = append(runes, r)
runes = append(runes, rune(r))
}
// make sure runes are sorted so PDF output is stable
sort.Slice(runes, func(i, j int) bool {
@ -427,14 +427,14 @@ func NewCompositePdfFontFromTTFFile(filePath string) (*PdfFont, error) {
missingWidth := k * float64(ttf.Widths[0])
// Construct a rune ➞ width map.
runeToWidthMap := map[uint16]int{}
gidToWidthMap := map[uint16]int{}
runeToWidthMap := make(map[rune]int)
gidToWidthMap := map[fonts.GID]int{}
for _, r := range runes {
glyphIndex := ttf.Chars[r]
gid := ttf.Chars[r]
w := k * float64(ttf.Widths[glyphIndex])
w := k * float64(ttf.Widths[gid])
runeToWidthMap[r] = int(w)
gidToWidthMap[glyphIndex] = int(w)
gidToWidthMap[gid] = int(w)
}
cidfont.runeToWidthMap = runeToWidthMap
cidfont.gidToWidthMap = gidToWidthMap

View File

@ -36,8 +36,8 @@ type pdfFontSimple struct {
container *core.PdfIndirectObject
// These fields are specific to simple PDF fonts.
firstChar int
lastChar int
firstChar textencoding.CharCode
lastChar textencoding.CharCode
charWidths []float64
encoder textencoding.TextEncoder
@ -49,7 +49,7 @@ type pdfFontSimple struct {
Encoding core.PdfObject
// Standard 14 fonts metrics
fontMetrics map[string]fonts.CharMetrics
fontMetrics map[textencoding.GlyphName]fonts.CharMetrics
}
// pdfCIDFontType0FromSkeleton returns a pdfFontSimple with its common fields initalized.
@ -76,7 +76,7 @@ func (font *pdfFontSimple) SetEncoder(encoder textencoding.TextEncoder) {
// GetGlyphCharMetrics returns the character metrics for the specified glyph. A bool flag is
// returned to indicate whether or not the entry was found in the glyph to charcode mapping.
func (font pdfFontSimple) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics, bool) {
func (font pdfFontSimple) GetGlyphCharMetrics(glyph textencoding.GlyphName) (fonts.CharMetrics, bool) {
if font.fontMetrics != nil {
metrics, ok := font.fontMetrics[glyph]
return metrics, ok
@ -90,17 +90,17 @@ func (font pdfFontSimple) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics,
}
metrics.GlyphName = glyph
if int(code) < font.firstChar {
if code < font.firstChar {
common.Log.Debug("Code lower than firstchar (%d < %d)", code, font.firstChar)
return metrics, false
}
if int(code) > font.lastChar {
if code > font.lastChar {
common.Log.Debug("Code higher than lastchar (%d < %d)", code, font.lastChar)
return metrics, false
}
index := int(code) - font.firstChar
index := int(code - font.firstChar)
if index >= len(font.charWidths) {
common.Log.Debug("Code outside of widths range")
return metrics, false
@ -135,7 +135,7 @@ func newSimpleFontFromPdfObject(d *core.PdfObjectDictionary, base *fontCommon, s
common.Log.Debug("ERROR: Invalid FirstChar type (%T)", obj)
return nil, core.ErrTypeError
}
font.firstChar = int(intVal)
font.firstChar = textencoding.CharCode(intVal)
obj = d.Get("LastChar")
if obj == nil {
@ -147,7 +147,7 @@ func newSimpleFontFromPdfObject(d *core.PdfObjectDictionary, base *fontCommon, s
common.Log.Debug("ERROR: Invalid LastChar type (%T)", obj)
return nil, core.ErrTypeError
}
font.lastChar = int(intVal)
font.lastChar = textencoding.CharCode(intVal)
font.charWidths = []float64{}
obj = d.Get("Widths")
@ -166,7 +166,7 @@ func newSimpleFontFromPdfObject(d *core.PdfObjectDictionary, base *fontCommon, s
return nil, err
}
if len(widths) != (font.lastChar - font.firstChar + 1) {
if len(widths) != int(font.lastChar-font.firstChar+1) {
common.Log.Debug("ERROR: Invalid widths length != %d (%d)",
font.lastChar-font.firstChar+1, len(widths))
return nil, core.ErrRangeError
@ -182,10 +182,12 @@ func newSimpleFontFromPdfObject(d *core.PdfObjectDictionary, base *fontCommon, s
// addEncoding adds the encoding to the font.
// The order of precedence is important.
func (font *pdfFontSimple) addEncoding() error {
var baseEncoder string
var differences map[byte]string
var err error
var encoder *textencoding.SimpleEncoder
var (
baseEncoder string
differences map[textencoding.CharCode]textencoding.GlyphName
err error
encoder *textencoding.SimpleEncoder
)
if font.Encoding != nil {
baseEncoder, differences, err = getFontEncoding(font.Encoding)
@ -247,7 +249,7 @@ func (font *pdfFontSimple) addEncoding() error {
// Except for Type 3 fonts, every font program shall have a built-in encoding. Under certain
// circumstances, a PDF font dictionary may change the encoding used with the font program to match
// the requirements of the conforming writer generating the text being shown.
func getFontEncoding(obj core.PdfObject) (baseName string, differences map[byte]string, err error) {
func getFontEncoding(obj core.PdfObject) (baseName string, differences map[textencoding.CharCode]textencoding.GlyphName, err error) {
baseName = "StandardEncoding"
if obj == nil {
@ -313,8 +315,8 @@ func (font *pdfFontSimple) ToPdfObject() core.PdfObject {
// styling functions.
// Uses a WinAnsiTextEncoder and loads only character codes 32-255.
func NewPdfFontFromTTFFile(filePath string) (*PdfFont, error) {
const minCode = 32
const maxCode = 255
const minCode = textencoding.CharCode(32)
const maxCode = textencoding.CharCode(255)
ttf, err := fonts.TtfParse(filePath)
if err != nil {
@ -336,8 +338,8 @@ func NewPdfFontFromTTFFile(filePath string) (*PdfFont, error) {
truefont.lastChar = maxCode
truefont.basefont = ttf.PostScriptName
truefont.FirstChar = core.MakeInteger(minCode)
truefont.LastChar = core.MakeInteger(maxCode)
truefont.FirstChar = core.MakeInteger(int64(minCode))
truefont.LastChar = core.MakeInteger(int64(maxCode))
k := 1000.0 / float64(ttf.UnitsPerEm)
if len(ttf.Widths) <= 0 {
@ -348,14 +350,14 @@ func NewPdfFontFromTTFFile(filePath string) (*PdfFont, error) {
vals := make([]float64, 0, maxCode-minCode+1)
for code := minCode; code <= maxCode; code++ {
r, found := truefont.Encoder().CharcodeToRune(uint16(code))
r, found := truefont.Encoder().CharcodeToRune(code)
if !found {
common.Log.Debug("Rune not found (code: %d)", code)
vals = append(vals, missingWidth)
continue
}
pos, ok := ttf.Chars[uint16(r)]
pos, ok := ttf.Chars[r]
if !ok {
common.Log.Debug("Rune not in TTF Chars")
vals = append(vals, missingWidth)
@ -450,7 +452,7 @@ const (
)
var standard14Fonts = map[Standard14Font]pdfFontSimple{
Courier: pdfFontSimple{
Courier: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "Courier",
@ -458,7 +460,7 @@ var standard14Fonts = map[Standard14Font]pdfFontSimple{
encoder: textencoding.NewWinAnsiTextEncoder(),
fontMetrics: fonts.CourierCharMetrics,
},
CourierBold: pdfFontSimple{
CourierBold: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "Courier-Bold",
@ -466,7 +468,7 @@ var standard14Fonts = map[Standard14Font]pdfFontSimple{
encoder: textencoding.NewWinAnsiTextEncoder(),
fontMetrics: fonts.CourierBoldCharMetrics,
},
CourierBoldOblique: pdfFontSimple{
CourierBoldOblique: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "Courier-BoldOblique",
@ -474,7 +476,7 @@ var standard14Fonts = map[Standard14Font]pdfFontSimple{
encoder: textencoding.NewWinAnsiTextEncoder(),
fontMetrics: fonts.CourierBoldObliqueCharMetrics,
},
CourierOblique: pdfFontSimple{
CourierOblique: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "Courier-Oblique",
@ -482,7 +484,7 @@ var standard14Fonts = map[Standard14Font]pdfFontSimple{
encoder: textencoding.NewWinAnsiTextEncoder(),
fontMetrics: fonts.CourierObliqueCharMetrics,
},
Helvetica: pdfFontSimple{
Helvetica: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "Helvetica",
@ -490,7 +492,7 @@ var standard14Fonts = map[Standard14Font]pdfFontSimple{
encoder: textencoding.NewWinAnsiTextEncoder(),
fontMetrics: fonts.HelveticaCharMetrics,
},
HelveticaBold: pdfFontSimple{
HelveticaBold: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "Helvetica-Bold",
@ -498,7 +500,7 @@ var standard14Fonts = map[Standard14Font]pdfFontSimple{
encoder: textencoding.NewWinAnsiTextEncoder(),
fontMetrics: fonts.HelveticaBoldCharMetrics,
},
HelveticaBoldOblique: pdfFontSimple{
HelveticaBoldOblique: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "Helvetica-BoldOblique",
@ -506,7 +508,7 @@ var standard14Fonts = map[Standard14Font]pdfFontSimple{
encoder: textencoding.NewWinAnsiTextEncoder(),
fontMetrics: fonts.HelveticaBoldObliqueCharMetrics,
},
HelveticaOblique: pdfFontSimple{
HelveticaOblique: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "Helvetica-Oblique",
@ -514,7 +516,7 @@ var standard14Fonts = map[Standard14Font]pdfFontSimple{
encoder: textencoding.NewWinAnsiTextEncoder(),
fontMetrics: fonts.HelveticaObliqueCharMetrics,
},
TimesRoman: pdfFontSimple{
TimesRoman: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "Times-Roman",
@ -522,7 +524,7 @@ var standard14Fonts = map[Standard14Font]pdfFontSimple{
encoder: textencoding.NewWinAnsiTextEncoder(),
fontMetrics: fonts.TimesRomanCharMetrics,
},
TimesBold: pdfFontSimple{
TimesBold: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "Times-Bold",
@ -530,7 +532,7 @@ var standard14Fonts = map[Standard14Font]pdfFontSimple{
encoder: textencoding.NewWinAnsiTextEncoder(),
fontMetrics: fonts.TimesBoldCharMetrics,
},
TimesBoldItalic: pdfFontSimple{
TimesBoldItalic: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "Times-BoldItalic",
@ -538,7 +540,7 @@ var standard14Fonts = map[Standard14Font]pdfFontSimple{
encoder: textencoding.NewWinAnsiTextEncoder(),
fontMetrics: fonts.TimesBoldItalicCharMetrics,
},
TimesItalic: pdfFontSimple{
TimesItalic: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "Times-Italic",
@ -546,7 +548,7 @@ var standard14Fonts = map[Standard14Font]pdfFontSimple{
encoder: textencoding.NewWinAnsiTextEncoder(),
fontMetrics: fonts.TimesItalicCharMetrics,
},
Symbol: pdfFontSimple{
Symbol: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "Symbol",
@ -554,7 +556,7 @@ var standard14Fonts = map[Standard14Font]pdfFontSimple{
encoder: textencoding.NewSymbolEncoder(),
fontMetrics: fonts.SymbolCharMetrics,
},
ZapfDingbats: pdfFontSimple{
ZapfDingbats: {
fontCommon: fontCommon{
subtype: "Type1",
basefont: "ZapfDingbats",

View File

@ -623,7 +623,7 @@ endobj
// Expected is WinAnsiEncoding with the applied differences.
winansi := textencoding.NewWinAnsiTextEncoder()
differencesMap := map[int]string{
differencesMap := map[textencoding.CharCode]textencoding.GlyphName{
24: `/breve`,
25: `/caron`,
26: `/circumflex`,
@ -754,10 +754,10 @@ endobj
255: `/ydieresis`,
}
for ccode := 32; ccode < 255; ccode++ {
fontglyph, has := font.Encoder().CharcodeToGlyph(uint16(ccode))
for ccode := textencoding.CharCode(32); ccode < 255; ccode++ {
fontglyph, has := font.Encoder().CharcodeToGlyph(ccode)
if !has {
baseglyph, bad := winansi.CharcodeToGlyph(uint16(ccode))
baseglyph, bad := winansi.CharcodeToGlyph(ccode)
if bad {
t.Fatalf("font not having glyph for char code %d - whereas base encoding had '%s'", ccode, baseglyph)
}
@ -766,7 +766,7 @@ endobj
// Check if in differencesmap first.
glyph, has := differencesMap[ccode]
if has {
glyph = strings.Trim(glyph, `/`)
glyph = textencoding.GlyphName(strings.Trim(string(glyph), `/`))
if glyph != fontglyph {
t.Fatalf("Mismatch for char code %d, font has: %s and expected is: %s (differences)", ccode, fontglyph, glyph)
}
@ -774,7 +774,7 @@ endobj
}
// If not in differences, should be according to WinAnsiEncoding (base).
glyph, has = winansi.CharcodeToGlyph(uint16(ccode))
glyph, has = winansi.CharcodeToGlyph(ccode)
if !has {
t.Fatalf("WinAnsi not having glyph for char code %d", ccode)
}

View File

@ -220,9 +220,9 @@ func getKeyValues(data string) map[string]string {
}
// getEncodings returns the encodings encoded in `data`.
func getEncodings(data string) (map[uint16]string, error) {
func getEncodings(data string) (map[textencoding.CharCode]textencoding.GlyphName, error) {
lines := strings.Split(data, "\n")
keyValues := map[uint16]string{}
keyValues := make(map[textencoding.CharCode]textencoding.GlyphName)
for _, line := range lines {
matches := reEncoding.FindStringSubmatch(line)
if matches == nil {
@ -234,7 +234,7 @@ func getEncodings(data string) (map[uint16]string, error) {
common.Log.Debug("ERROR: Bad encoding line. %q", line)
return nil, core.ErrTypeError
}
keyValues[uint16(code)] = glyph
keyValues[textencoding.CharCode(code)] = textencoding.GlyphName(glyph)
}
common.Log.Trace("getEncodings: keyValues=%#v", keyValues)
return keyValues, nil

View File

@ -38,7 +38,7 @@ func (font FontCourier) SetEncoder(encoder textencoding.TextEncoder) {
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontCourier) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontCourier) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := CourierCharMetrics[glyph]
if !has {
return metrics, false
@ -60,7 +60,7 @@ func (font FontCourier) ToPdfObject() core.PdfObject {
// CourierCharMetrics are the font metrics loaded from afms/Courier.afm. See afms/MustRead.html for
// license information.
var CourierCharMetrics = map[string]CharMetrics{
var CourierCharMetrics = map[GlyphName]CharMetrics{
"A": {GlyphName: "A", Wx: 600.000000, Wy: 0.000000},
"AE": {GlyphName: "AE", Wx: 600.000000, Wy: 0.000000},
"Aacute": {GlyphName: "Aacute", Wx: 600.000000, Wy: 0.000000},

View File

@ -38,7 +38,7 @@ func (font FontCourierBold) SetEncoder(encoder textencoding.TextEncoder) {
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontCourierBold) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontCourierBold) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := CourierBoldCharMetrics[glyph]
if !has {
return metrics, false
@ -59,7 +59,7 @@ func (font FontCourierBold) ToPdfObject() core.PdfObject {
}
// Courier-Bold font metrics loaded from afms/Courier-Bold.afm. See afms/MustRead.html for license information.
var CourierBoldCharMetrics = map[string]CharMetrics{
var CourierBoldCharMetrics = map[GlyphName]CharMetrics{
"A": {GlyphName: "A", Wx: 600.000000, Wy: 0.000000},
"AE": {GlyphName: "AE", Wx: 600.000000, Wy: 0.000000},
"Aacute": {GlyphName: "Aacute", Wx: 600.000000, Wy: 0.000000},

View File

@ -39,7 +39,7 @@ func (font FontCourierBoldOblique) SetEncoder(encoder textencoding.TextEncoder)
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontCourierBoldOblique) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontCourierBoldOblique) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := CourierBoldObliqueCharMetrics[glyph]
if !has {
return metrics, false
@ -61,7 +61,7 @@ func (font FontCourierBoldOblique) ToPdfObject() core.PdfObject {
// CourierBoldObliqueCharMetrics are the font metrics loaded from afms/Courier-BoldOblique.afm.
// See afms/MustRead.html for license information.
var CourierBoldObliqueCharMetrics = map[string]CharMetrics{
var CourierBoldObliqueCharMetrics = map[GlyphName]CharMetrics{
"A": {GlyphName: "A", Wx: 600.000000, Wy: 0.000000},
"AE": {GlyphName: "AE", Wx: 600.000000, Wy: 0.000000},
"Aacute": {GlyphName: "Aacute", Wx: 600.000000, Wy: 0.000000},

View File

@ -38,7 +38,7 @@ func (font FontCourierOblique) SetEncoder(encoder textencoding.TextEncoder) {
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontCourierOblique) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontCourierOblique) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := CourierObliqueCharMetrics[glyph]
if !has {
return metrics, false
@ -60,7 +60,7 @@ func (font FontCourierOblique) ToPdfObject() core.PdfObject {
// CourierObliqueCharMetrics are the font metrics loaded from afms/Courier-Oblique.afm.
// See afms/MustRead.html for license information.
var CourierObliqueCharMetrics = map[string]CharMetrics{
var CourierObliqueCharMetrics = map[GlyphName]CharMetrics{
"A": {GlyphName: "A", Wx: 600.000000, Wy: 0.000000},
"AE": {GlyphName: "AE", Wx: 600.000000, Wy: 0.000000},
"Aacute": {GlyphName: "Aacute", Wx: 600.000000, Wy: 0.000000},

View File

@ -15,13 +15,13 @@ import (
type Font interface {
Encoder() textencoding.TextEncoder
SetEncoder(encoder textencoding.TextEncoder)
GetGlyphCharMetrics(glyph string) (CharMetrics, bool)
GetGlyphCharMetrics(glyph textencoding.GlyphName) (CharMetrics, bool)
ToPdfObject() core.PdfObject
}
// CharMetrics represents width and height metrics of a glyph.
type CharMetrics struct {
GlyphName string
GlyphName textencoding.GlyphName
Wx float64
Wy float64
}

View File

@ -38,7 +38,7 @@ func (font FontHelvetica) SetEncoder(encoder textencoding.TextEncoder) {
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontHelvetica) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontHelvetica) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := HelveticaCharMetrics[glyph]
if !has {
return metrics, false
@ -60,7 +60,7 @@ func (font FontHelvetica) ToPdfObject() core.PdfObject {
// HelveticaCharMetrics are the font metrics loaded from afms/Helvetica.afm.
// See afms/MustRead.html for license information.
var HelveticaCharMetrics = map[string]CharMetrics{
var HelveticaCharMetrics = map[GlyphName]CharMetrics{
"A": {GlyphName: "A", Wx: 667.000000, Wy: 0.000000},
"AE": {GlyphName: "AE", Wx: 1000.000000, Wy: 0.000000},
"Aacute": {GlyphName: "Aacute", Wx: 667.000000, Wy: 0.000000},

View File

@ -39,7 +39,7 @@ func (font FontHelveticaBold) SetEncoder(encoder textencoding.TextEncoder) {
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontHelveticaBold) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontHelveticaBold) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := HelveticaBoldCharMetrics[glyph]
if !has {
return metrics, false
@ -61,7 +61,7 @@ func (font FontHelveticaBold) ToPdfObject() core.PdfObject {
// HelveticaBoldCharMetrics are the font metrics loaded from afms/Helvetica-Bold.afm.
// See afms/MustRead.html for license information.
var HelveticaBoldCharMetrics = map[string]CharMetrics{
var HelveticaBoldCharMetrics = map[GlyphName]CharMetrics{
"A": {GlyphName: "A", Wx: 722.000000, Wy: 0.000000},
"AE": {GlyphName: "AE", Wx: 1000.000000, Wy: 0.000000},
"Aacute": {GlyphName: "Aacute", Wx: 722.000000, Wy: 0.000000},

View File

@ -38,7 +38,7 @@ func (font FontHelveticaBoldOblique) SetEncoder(encoder textencoding.TextEncoder
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontHelveticaBoldOblique) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontHelveticaBoldOblique) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := HelveticaBoldObliqueCharMetrics[glyph]
if !has {
return metrics, false
@ -60,7 +60,7 @@ func (font FontHelveticaBoldOblique) ToPdfObject() core.PdfObject {
// HelveticaBoldObliqueCharMetrics are the font metrics loaded from afms/Helvetica-BoldOblique.afm.
// See afms/MustRead.html for license information.
var HelveticaBoldObliqueCharMetrics = map[string]CharMetrics{
var HelveticaBoldObliqueCharMetrics = map[GlyphName]CharMetrics{
"A": {GlyphName: "A", Wx: 722.000000, Wy: 0.000000},
"AE": {GlyphName: "AE", Wx: 1000.000000, Wy: 0.000000},
"Aacute": {GlyphName: "Aacute", Wx: 722.000000, Wy: 0.000000},

View File

@ -38,7 +38,7 @@ func (font FontHelveticaOblique) SetEncoder(encoder textencoding.TextEncoder) {
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontHelveticaOblique) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontHelveticaOblique) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := HelveticaObliqueCharMetrics[glyph]
if !has {
return metrics, false
@ -60,7 +60,7 @@ func (font FontHelveticaOblique) ToPdfObject() core.PdfObject {
// HelveticaObliqueCharMetrics are the font metrics loaded from afms/Helvetica-Oblique.afm.
// See afms/MustRead.html for license information.
var HelveticaObliqueCharMetrics = map[string]CharMetrics{
var HelveticaObliqueCharMetrics = map[GlyphName]CharMetrics{
"A": {GlyphName: "A", Wx: 667.000000, Wy: 0.000000},
"AE": {GlyphName: "AE", Wx: 1000.000000, Wy: 0.000000},
"Aacute": {GlyphName: "Aacute", Wx: 667.000000, Wy: 0.000000},

View File

@ -39,7 +39,7 @@ func (font FontSymbol) SetEncoder(encoder textencoding.TextEncoder) {
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontSymbol) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontSymbol) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := SymbolCharMetrics[glyph]
if !has {
return metrics, false
@ -63,7 +63,7 @@ func (font FontSymbol) ToPdfObject() core.PdfObject {
// SymbolCharMetrics are the font metrics loaded from afms/Symbol.afm.
// See afms/MustRead.html for license information.
var SymbolCharMetrics = map[string]CharMetrics{
var SymbolCharMetrics = map[GlyphName]CharMetrics{
"Alpha": {GlyphName: "Alpha", Wx: 722.000000, Wy: 0.000000},
"Beta": {GlyphName: "Beta", Wx: 667.000000, Wy: 0.000000},
"Chi": {GlyphName: "Chi", Wx: 722.000000, Wy: 0.000000},

View File

@ -38,7 +38,7 @@ func (font FontTimesBold) SetEncoder(encoder textencoding.TextEncoder) {
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontTimesBold) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontTimesBold) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := TimesBoldCharMetrics[glyph]
if !has {
return metrics, false
@ -60,7 +60,7 @@ func (font FontTimesBold) ToPdfObject() core.PdfObject {
// TimesBoldCharMetrics are the font metrics loaded from afms/Times-Bold.afm.
// See afms/MustRead.html for license information.
var TimesBoldCharMetrics = map[string]CharMetrics{
var TimesBoldCharMetrics = map[GlyphName]CharMetrics{
"A": {GlyphName: "A", Wx: 722.000000, Wy: 0.000000},
"AE": {GlyphName: "AE", Wx: 1000.000000, Wy: 0.000000},
"Aacute": {GlyphName: "Aacute", Wx: 722.000000, Wy: 0.000000},

View File

@ -38,7 +38,7 @@ func (font FontTimesBoldItalic) SetEncoder(encoder textencoding.TextEncoder) {
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontTimesBoldItalic) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontTimesBoldItalic) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := TimesBoldItalicCharMetrics[glyph]
if !has {
return metrics, false
@ -60,7 +60,7 @@ func (font FontTimesBoldItalic) ToPdfObject() core.PdfObject {
// TimesBoldItalicCharMetrics are the font metrics loaded from afms/Times-BoldItalic.afm.
// See afms/MustRead.html for license information.
var TimesBoldItalicCharMetrics = map[string]CharMetrics{
var TimesBoldItalicCharMetrics = map[GlyphName]CharMetrics{
"A": {GlyphName: "A", Wx: 667.000000, Wy: 0.000000},
"AE": {GlyphName: "AE", Wx: 944.000000, Wy: 0.000000},
"Aacute": {GlyphName: "Aacute", Wx: 667.000000, Wy: 0.000000},

View File

@ -38,7 +38,7 @@ func (font FontTimesItalic) SetEncoder(encoder textencoding.TextEncoder) {
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontTimesItalic) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontTimesItalic) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := TimesItalicCharMetrics[glyph]
if !has {
return metrics, false
@ -60,7 +60,7 @@ func (font FontTimesItalic) ToPdfObject() core.PdfObject {
// TimesItalicCharMetrics font metrics loaded from afms/Times-Italic.afm.
// See afms/MustRead.html for license information.
var TimesItalicCharMetrics = map[string]CharMetrics{
var TimesItalicCharMetrics = map[GlyphName]CharMetrics{
"A": {GlyphName: "A", Wx: 611.000000, Wy: 0.000000},
"AE": {GlyphName: "AE", Wx: 889.000000, Wy: 0.000000},
"Aacute": {GlyphName: "Aacute", Wx: 611.000000, Wy: 0.000000},

View File

@ -38,7 +38,7 @@ func (font FontTimesRoman) SetEncoder(encoder textencoding.TextEncoder) {
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontTimesRoman) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontTimesRoman) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := TimesRomanCharMetrics[glyph]
if !has {
return metrics, false
@ -60,7 +60,7 @@ func (font FontTimesRoman) ToPdfObject() core.PdfObject {
// TimesRomanCharMetrics are the font metrics loaded from afms/Times-Roman.afm.
// See afms/MustRead.html for license information.
var TimesRomanCharMetrics = map[string]CharMetrics{
var TimesRomanCharMetrics = map[GlyphName]CharMetrics{
"A": {GlyphName: "A", Wx: 722.000000, Wy: 0.000000},
"AE": {GlyphName: "AE", Wx: 889.000000, Wy: 0.000000},
"Aacute": {GlyphName: "Aacute", Wx: 722.000000, Wy: 0.000000},

View File

@ -46,17 +46,19 @@ import (
// MakeEncoder returns an encoder built from the tables in `rec`.
func (rec *TtfType) MakeEncoder() (*textencoding.SimpleEncoder, error) {
encoding := map[uint16]string{}
for code := uint16(0); code <= 256; code++ {
gid, ok := rec.Chars[code]
encoding := make(map[textencoding.CharCode]GlyphName)
for code := textencoding.CharCode(0); code <= 256; code++ {
r := rune(code) // TODO(dennwc): make sure this conversion is valid
gid, ok := rec.Chars[r]
if !ok {
continue
}
glyph := ""
var glyph GlyphName
if int(gid) >= 0 && int(gid) < len(rec.GlyphNames) {
glyph = rec.GlyphNames[gid]
} else {
glyph = string(rune(gid))
// TODO(dennwc): shouldn't this be uniXXX?
glyph = GlyphName(rune(gid))
}
encoding[code] = glyph
}
@ -67,6 +69,12 @@ func (rec *TtfType) MakeEncoder() (*textencoding.SimpleEncoder, error) {
return textencoding.NewCustomSimpleTextEncoder(encoding, nil)
}
// GID is a glyph index.
type GID = textencoding.GID
// GlyphName is a name of a glyph.
type GlyphName = textencoding.GlyphName
// TtfType describes a TrueType font file.
// http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-chapter08
type TtfType struct {
@ -85,25 +93,27 @@ type TtfType struct {
// Chars maps rune values (unicode) to the indexes in GlyphNames. i.e. GlyphNames[Chars[r]] is
// the glyph corresponding to rune r.
Chars map[uint16]uint16
Chars map[rune]GID
// GlyphNames is a list of glyphs from the "post" section of the TrueType file.
GlyphNames []string
GlyphNames []GlyphName
}
// MakeToUnicode returns a ToUnicode CMap based on the encoding of `ttf`.
// XXX(peterwilliams97): This currently gives a bad text mapping for creator_test.go but leads to an
// otherwise valid PDF file that Adobe Reader displays without error.
func (ttf *TtfType) MakeToUnicode() *cmap.CMap {
codeToUnicode := map[cmap.CharCode]string{}
for code, idx := range ttf.Chars {
glyph := ttf.GlyphNames[idx]
codeToUnicode := make(map[cmap.CharCode]rune)
for code, gid := range ttf.Chars {
glyph := ttf.GlyphNames[gid]
// TODO(dennwc): 'code' is already a rune; do we need this extra lookup?
r, ok := textencoding.GlyphToRune(glyph)
if !ok {
common.Log.Debug("No rune. code=0x%04x glyph=%q", code, glyph)
r = textencoding.MissingCodeRune
}
codeToUnicode[cmap.CharCode(code)] = string(r)
// TODO(dennwc): implies rune <-> charcode identity?
codeToUnicode[cmap.CharCode(code)] = r
}
return cmap.NewToUnicodeCMap(codeToUnicode)
}
@ -322,11 +332,11 @@ func (t *ttfParser) ParseHmtx() error {
// parseCmapSubtable31 parses information from an (3,1) subtable (Windows Unicode).
func (t *ttfParser) parseCmapSubtable31(offset31 int64) error {
startCount := make([]uint16, 0, 8)
endCount := make([]uint16, 0, 8)
startCount := make([]rune, 0, 8)
endCount := make([]rune, 0, 8)
idDelta := make([]int16, 0, 8)
idRangeOffset := make([]uint16, 0, 8)
t.rec.Chars = make(map[uint16]uint16)
t.rec.Chars = make(map[rune]GID)
t.f.Seek(int64(t.tables["cmap"])+offset31, os.SEEK_SET)
format := t.ReadUShort()
if format != 4 {
@ -336,11 +346,11 @@ func (t *ttfParser) parseCmapSubtable31(offset31 int64) error {
segCount := int(t.ReadUShort() / 2)
t.Skip(3 * 2) // searchRange, entrySelector, rangeShift
for j := 0; j < segCount; j++ {
endCount = append(endCount, t.ReadUShort())
endCount = append(endCount, rune(t.ReadUShort()))
}
t.Skip(2) // reservedPad
for j := 0; j < segCount; j++ {
startCount = append(startCount, t.ReadUShort())
startCount = append(startCount, rune(t.ReadUShort()))
}
for j := 0; j < segCount; j++ {
idDelta = append(idDelta, t.ReadShort())
@ -374,7 +384,7 @@ func (t *ttfParser) parseCmapSubtable31(offset31 int64) error {
gid -= 65536
}
if gid > 0 {
t.rec.Chars[c] = uint16(gid)
t.rec.Chars[c] = GID(gid)
}
}
}
@ -385,7 +395,7 @@ func (t *ttfParser) parseCmapSubtable31(offset31 int64) error {
func (t *ttfParser) parseCmapSubtable10(offset10 int64) error {
if t.rec.Chars == nil {
t.rec.Chars = make(map[uint16]uint16)
t.rec.Chars = make(map[rune]GID)
}
t.f.Seek(int64(t.tables["cmap"])+offset10, os.SEEK_SET)
@ -412,10 +422,10 @@ func (t *ttfParser) parseCmapSubtable10(offset10 int64) error {
}
data := []byte(dataStr)
for code, glyphId := range data {
t.rec.Chars[uint16(code)] = uint16(glyphId)
if glyphId != 0 {
fmt.Printf("\t0x%02x ➞ 0x%02x=%c\n", code, glyphId, rune(glyphId))
for code, gid := range data {
t.rec.Chars[rune(code)] = GID(gid)
if gid != 0 {
fmt.Printf("\t0x%02x ➞ 0x%02x=%c\n", code, gid, rune(gid))
}
}
return nil
@ -468,7 +478,7 @@ func (t *ttfParser) parseCmapVersion(offset int64) error {
common.Log.Trace("parseCmapVersion: offset=%d", offset)
if t.rec.Chars == nil {
t.rec.Chars = make(map[uint16]uint16)
t.rec.Chars = make(map[rune]GID)
}
t.f.Seek(int64(t.tables["cmap"])+offset, os.SEEK_SET)
@ -507,7 +517,7 @@ func (t *ttfParser) parseCmapFormat0() error {
common.Log.Trace("parseCmapFormat0: %s\ndataStr=%+q\ndata=[% 02x]", t.rec.String(), dataStr, data)
for code, glyphId := range data {
t.rec.Chars[uint16(code)] = uint16(glyphId)
t.rec.Chars[rune(code)] = GID(glyphId)
}
return nil
}
@ -521,8 +531,8 @@ func (t *ttfParser) parseCmapFormat6() error {
t.rec.String(), firstCode, entryCount)
for i := 0; i < entryCount; i++ {
glyphId := t.ReadUShort()
t.rec.Chars[uint16(i+firstCode)] = glyphId
glyphId := GID(t.ReadUShort())
t.rec.Chars[rune(i+firstCode)] = glyphId
}
return nil
@ -557,7 +567,7 @@ func (t *ttfParser) parseCmapFormat12() error {
common.Log.Debug("Format 12 cmap contains character beyond UCS-4")
}
t.rec.Chars[uint16(i+firstCode)] = uint16(glyphId)
t.rec.Chars[rune(i+firstCode)] = GID(glyphId)
}
}
@ -646,7 +656,7 @@ func (t *ttfParser) ParsePost() error {
case 2.0:
numGlyphs := int(t.ReadUShort())
glyphNameIndex := make([]int, numGlyphs)
t.rec.GlyphNames = make([]string, numGlyphs)
t.rec.GlyphNames = make([]GlyphName, numGlyphs)
maxIndex := -1
for i := 0; i < numGlyphs; i++ {
index := int(t.ReadUShort())
@ -656,16 +666,16 @@ func (t *ttfParser) ParsePost() error {
maxIndex = index
}
}
var nameArray []string
var nameArray []GlyphName
if maxIndex >= len(macGlyphNames) {
nameArray = make([]string, maxIndex-len(macGlyphNames)+1)
nameArray = make([]GlyphName, maxIndex-len(macGlyphNames)+1)
for i := 0; i < maxIndex-len(macGlyphNames)+1; i++ {
numberOfChars := int(t.ReadByte())
names, err := t.ReadStr(numberOfChars)
if err != nil {
return err
}
nameArray[i] = names
nameArray[i] = GlyphName(names)
}
}
for i := 0; i < numGlyphs; i++ {
@ -684,7 +694,7 @@ func (t *ttfParser) ParsePost() error {
offset := int(t.ReadSByte())
glyphNameIndex[i] = i + 1 + offset
}
t.rec.GlyphNames = make([]string, len(glyphNameIndex))
t.rec.GlyphNames = make([]GlyphName, len(glyphNameIndex))
for i := 0; i < len(t.rec.GlyphNames); i++ {
name := macGlyphNames[glyphNameIndex[i]]
t.rec.GlyphNames[i] = name
@ -700,7 +710,7 @@ func (t *ttfParser) ParsePost() error {
}
// The 258 standard mac glyph names used in 'post' format 1 and 2.
var macGlyphNames = []string{
var macGlyphNames = []GlyphName{
".notdef", ".null", "nonmarkingreturn", "space", "exclam", "quotedbl",
"numbersign", "dollar", "percent", "ampersand", "quotesingle",
"parenleft", "parenright", "asterisk", "plus", "comma", "hyphen",

View File

@ -9,6 +9,8 @@ import (
const fontDir = `../../creator/testdata`
type charCode = textencoding.CharCode
var casesTTFParse = []struct {
path string
name string
@ -18,7 +20,7 @@ var casesTTFParse = []struct {
underlineTh int16
isFixed bool
bbox [4]int
runes map[rune]uint16
runes map[rune]charCode
widths map[rune]int
}{
{
@ -27,7 +29,7 @@ var casesTTFParse = []struct {
underlinePos: -151,
underlineTh: 50,
bbox: [4]int{-631, 1632, -462, 1230},
runes: map[rune]uint16{
runes: map[rune]charCode{
'x': 0x5d,
'ё': 0x32a,
},
@ -43,7 +45,7 @@ var casesTTFParse = []struct {
underlinePos: -150,
underlineTh: 100,
bbox: [4]int{-1488, 2439, -555, 2163},
runes: map[rune]uint16{
runes: map[rune]charCode{
'x': 0x5c,
'ё': 0x3cb,
},
@ -60,7 +62,7 @@ var casesTTFParse = []struct {
underlinePos: -150,
underlineTh: 100,
bbox: [4]int{-1459, 2467, -555, 2163},
runes: map[rune]uint16{
runes: map[rune]charCode{
'x': 0x5c,
'ё': 0x3cb,
},
@ -103,6 +105,7 @@ func TestTTFParse(t *testing.T) {
if ft.PostScriptName != c.name {
t.Errorf("%q %q", ft.PostScriptName, c.name)
}
enc := textencoding.NewTrueTypeFontEncoder(ft.Chars)
for _, r := range testRunes {
@ -113,7 +116,7 @@ func TestTTFParse(t *testing.T) {
} else if ind != c.runes[r] {
t.Fatalf("%x != %x", ind, c.runes[r])
}
w := ft.Widths[ft.Chars[uint16(r)]]
w := ft.Widths[ft.Chars[r]]
if int(w) != c.widths[r] {
t.Errorf("%d != %d", int(w), c.widths[r])
}

View File

@ -39,7 +39,7 @@ func (font FontZapfDingbats) SetEncoder(encoder textencoding.TextEncoder) {
}
// GetGlyphCharMetrics returns character metrics for a given glyph.
func (font FontZapfDingbats) GetGlyphCharMetrics(glyph string) (CharMetrics, bool) {
func (font FontZapfDingbats) GetGlyphCharMetrics(glyph GlyphName) (CharMetrics, bool) {
metrics, has := ZapfDingbatsCharMetrics[glyph]
if !has {
return metrics, false
@ -62,7 +62,7 @@ func (font FontZapfDingbats) ToPdfObject() core.PdfObject {
// ZapfDingbatsCharMetrics are the font metrics loaded from afms/ZapfDingbats.afm.
// See afms/MustRead.html for license information.
var ZapfDingbatsCharMetrics = map[string]CharMetrics{
var ZapfDingbatsCharMetrics = map[GlyphName]CharMetrics{
"a1": {GlyphName: "a1", Wx: 974.000000, Wy: 0.000000},
"a10": {GlyphName: "a10", Wx: 692.000000, Wy: 0.000000},
"a100": {GlyphName: "a100", Wx: 668.000000, Wy: 0.000000},