Fixed some issues in creator code

Stopped double converting from Go strings to PDF encoded strings
Added TTF parse table format 12
This commit is contained in:
Peter Williams 2018-08-17 08:41:35 +10:00
parent fefff56603
commit c2feafdfdc
6 changed files with 67 additions and 49 deletions

View File

@ -20,9 +20,9 @@ type VectorDrawable interface {
Height() float64 Height() float64
} }
// DrawContext defines the drawing context. The DrawContext is continuously used and updated when drawing the page // DrawContext defines the drawing context. The DrawContext is continuously used and updated when
// contents in relative mode. Keeps track of current X, Y position, available height as well as other page parameters // drawing the page contents in relative mode. Keeps track of current X, Y position, available
// such as margins and dimensions. // height as well as other page parameters such as margins and dimensions.
type DrawContext struct { type DrawContext struct {
// Current page number. // Current page number.
Page int Page int

View File

@ -125,7 +125,7 @@ func (p *Paragraph) SetEnableWrap(enableWrap bool) {
p.enableWrap = enableWrap p.enableWrap = enableWrap
} }
// SetColor set the color of the Paragraph text. // SetColor sets the color of the Paragraph text.
// //
// Example: // Example:
// 1. p := NewParagraph("Red paragraph") // 1. p := NewParagraph("Red paragraph")
@ -219,7 +219,7 @@ func (p *Paragraph) getTextWidth() float64 {
// XXX/TODO: Consider the Knuth/Plass algorithm or an alternative. // XXX/TODO: Consider the Knuth/Plass algorithm or an alternative.
func (p *Paragraph) wrapText() error { func (p *Paragraph) wrapText() error {
if !p.enableWrap { if !p.enableWrap {
p.textLines = []string{p.textFont.Encoder().Encode(p.text)} p.textLines = []string{p.text}
return nil return nil
} }
@ -240,8 +240,8 @@ func (p *Paragraph) wrapText() error {
metrics, found := p.textFont.GetGlyphCharMetrics(glyph) metrics, found := p.textFont.GetGlyphCharMetrics(glyph)
if !found { if !found {
common.Log.Debug("ERROR: Glyph char metrics not found! %q rune=0x%04x=%c font=%s", common.Log.Debug("ERROR: Glyph char metrics not found! %q rune=0x%04x=%c font=%s %#q",
glyph, val, val, p.textFont.BaseFont()) glyph, val, val, p.textFont.BaseFont(), p.textFont.Subtype())
common.Log.Trace("Font: %#v", p.textFont) common.Log.Trace("Font: %#v", p.textFont)
common.Log.Trace("Encoder: %#v", p.textFont.Encoder()) common.Log.Trace("Encoder: %#v", p.textFont.Encoder())
return errors.New("Glyph char metrics missing") return errors.New("Glyph char metrics missing")
@ -306,7 +306,7 @@ func (p *Paragraph) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
blk := NewBlock(ctx.PageWidth, ctx.PageHeight) blk := NewBlock(ctx.PageWidth, ctx.PageHeight)
if p.positioning.isRelative() { if p.positioning.isRelative() {
// Account for Paragraph Margins. // Account for Paragraph margins.
ctx.X += p.margins.left ctx.X += p.margins.left
ctx.Y += p.margins.top ctx.Y += p.margins.top
ctx.Width -= p.margins.left + p.margins.right ctx.Width -= p.margins.left + p.margins.right
@ -408,7 +408,7 @@ func drawParagraphOnBlock(blk *Block, p *Paragraph, ctx DrawContext) (DrawContex
// Get width of the line (excluding spaces). // Get width of the line (excluding spaces).
w := 0.0 w := 0.0
spaces := 0 spaces := 0
for _, runeVal := range runes { for i, runeVal := range runes {
glyph, found := p.textFont.Encoder().RuneToGlyph(runeVal) glyph, found := p.textFont.Encoder().RuneToGlyph(runeVal)
if !found { if !found {
common.Log.Debug("Rune 0x%x not supported by text encoder", runeVal) common.Log.Debug("Rune 0x%x not supported by text encoder", runeVal)
@ -420,7 +420,9 @@ func drawParagraphOnBlock(blk *Block, p *Paragraph, ctx DrawContext) (DrawContex
} }
metrics, found := p.textFont.GetGlyphCharMetrics(glyph) metrics, found := p.textFont.GetGlyphCharMetrics(glyph)
if !found { if !found {
common.Log.Debug("Unsupported glyph %s in font", glyph) common.Log.Debug("Unsupported glyph %q i=%d rune=0x%04x=%c in font %s %s",
glyph, i, runeVal, runeVal,
p.textFont.BaseFont(), p.textFont.Subtype())
return ctx, errors.New("Unsupported text glyph") return ctx, errors.New("Unsupported text glyph")
} }
@ -451,19 +453,13 @@ func drawParagraphOnBlock(blk *Block, p *Paragraph, ctx DrawContext) (DrawContex
encStr := "" encStr := ""
for _, runeVal := range runes { for _, runeVal := range runes {
//creator.Add_Tj(core.PdfObjectString(tb.Encoder.Encode(line)))
glyph, found := p.textFont.Encoder().RuneToGlyph(runeVal) glyph, found := p.textFont.Encoder().RuneToGlyph(runeVal)
if !found { if !found {
common.Log.Debug("Rune 0x%x not supported by text encoder", runeVal) common.Log.Debug("Rune 0x%x not supported by text encoder", runeVal)
return ctx, errors.New("Unsupported rune in text encoding") return ctx, errors.New("Unsupported rune in text encoding")
} }
if glyph == "space" { if glyph == "space" { // XXX: What about \t and other spaces.
if !found {
common.Log.Debug("Unsupported glyph %s in font", glyph)
return ctx, errors.New("Unsupported text glyph")
}
if len(encStr) > 0 { if len(encStr) > 0 {
objs = append(objs, core.MakeString(encStr)) objs = append(objs, core.MakeString(encStr))
encStr = "" encStr = ""

View File

@ -9,6 +9,7 @@ import (
"errors" "errors"
"github.com/unidoc/unidoc/common" "github.com/unidoc/unidoc/common"
"github.com/unidoc/unidoc/pdf/core"
"github.com/unidoc/unidoc/pdf/model" "github.com/unidoc/unidoc/pdf/model"
) )
@ -130,7 +131,8 @@ func (table *Table) CurCol() int {
return curCol return curCol
} }
// SetPos sets the Table's positioning to absolute mode and specifies the upper-left corner coordinates as (x,y). // SetPos sets the Table's positioning to absolute mode and specifies the upper-left corner
// coordinates as (x,y).
// Note that this is only sensible to use when the table does not wrap over multiple pages. // Note that this is only sensible to use when the table does not wrap over multiple pages.
// TODO: Should be able to set width too (not just based on context/relative positioning mode). // TODO: Should be able to set width too (not just based on context/relative positioning mode).
func (table *Table) SetPos(x, y float64) { func (table *Table) SetPos(x, y float64) {
@ -139,7 +141,8 @@ func (table *Table) SetPos(x, y float64) {
table.yPos = y table.yPos = y
} }
// GeneratePageBlocks generate the page blocks. Multiple blocks are generated if the contents wrap over multiple pages. // GeneratePageBlocks generate the page blocks. Multiple blocks are generated if the contents wrap
// over multiple pages.
// Implements the Drawable interface. // Implements the Drawable interface.
func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) { func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
blocks := []*Block{} blocks := []*Block{}
@ -232,7 +235,7 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
} }
err := block.Draw(rect) err := block.Draw(rect)
if err != nil { if err != nil {
common.Log.Debug("Error: %v\n", err) common.Log.Debug("ERROR: %v\n", err)
} }
} else if cell.borderStyle != CellBorderStyleNone { } else if cell.borderStyle != CellBorderStyleNone {
// Draw border (no fill). // Draw border (no fill).
@ -244,7 +247,7 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
rect.SetBorderColor(ColorRGBFromArithmetic(r, g, b)) rect.SetBorderColor(ColorRGBFromArithmetic(r, g, b))
err := block.Draw(rect) err := block.Draw(rect)
if err != nil { if err != nil {
common.Log.Debug("Error: %v\n", err) common.Log.Debug("ERROR: %v", err)
} }
} }
@ -290,7 +293,7 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
err := block.DrawWithContext(cell.content, ctx) err := block.DrawWithContext(cell.content, ctx)
if err != nil { if err != nil {
common.Log.Debug("Error: %v\n", err) common.Log.Debug("ERROR: %v", err)
} }
} }
@ -515,8 +518,8 @@ func (cell *TableCell) SetContent(vd VectorDrawable) error {
} }
cell.content = vd cell.content = vd
default: default:
common.Log.Debug("Error: unsupported cell content type %T\n", vd) common.Log.Debug("ERROR: unsupported cell content type %T", vd)
return errors.New("Type check error") return core.ErrTypeError
} }
return nil return nil

View File

@ -146,7 +146,8 @@ func (t *ttfParser) Parse() (TtfType, error) {
return TtfType{}, errors.New("fonts based on PostScript outlines are not supported") return TtfType{}, errors.New("fonts based on PostScript outlines are not supported")
} }
if version != "\x00\x01\x00\x00" { if version != "\x00\x01\x00\x00" {
common.Log.Debug("ERROR: Unrecognized TrueType file format. version=%q", version) // This is not an error. In the font_test.go example axes.txt we see version "true".
common.Log.Debug("Unrecognized TrueType file format. version=%q", version)
} }
numTables := int(t.ReadUShort()) numTables := int(t.ReadUShort())
t.Skip(3 * 2) // searchRange, entrySelector, rangeShift t.Skip(3 * 2) // searchRange, entrySelector, rangeShift
@ -460,6 +461,8 @@ func (t *ttfParser) parseCmapVersion(offset int64) error {
return t.parseCmapFormat0() return t.parseCmapFormat0()
case 6: case 6:
return t.parseCmapFormat6() return t.parseCmapFormat6()
case 12:
return t.parseCmapFormat12()
default: default:
common.Log.Debug("ERROR: Unsupported cmap format=%d", format) common.Log.Debug("ERROR: Unsupported cmap format=%d", format)
return nil // XXX: Can't return an error here if creator_test.go is to pass. return nil // XXX: Can't return an error here if creator_test.go is to pass.
@ -496,6 +499,43 @@ func (t *ttfParser) parseCmapFormat6() error {
return nil return nil
} }
func (t *ttfParser) parseCmapFormat12() error {
numGroups := t.ReadULong()
common.Log.Trace("parseCmapFormat12: %s numGroups=%d", t.rec.String(), numGroups)
for i := uint32(0); i < numGroups; i++ {
firstCode := t.ReadULong()
endCode := t.ReadULong()
startGlyph := t.ReadULong()
if firstCode > 0x0010FFFF || (0xD800 <= firstCode && firstCode <= 0xDFFF) {
return errors.New("Invalid characters codes")
}
if endCode < firstCode || endCode > 0x0010FFFF || (0xD800 <= endCode && endCode <= 0xDFFF) {
return errors.New("Invalid characters codes")
}
for j := uint32(0); j <= endCode-firstCode; j++ {
glyphId := startGlyph + j
// if glyphId >= numGlyphs {
// common.Log.Debug("ERROR: Format 12 cmap contains an invalid glyph index")
// break
// }
if firstCode+j > 0x10FFFF {
common.Log.Debug("Format 12 cmap contains character beyond UCS-4")
}
t.rec.Chars[uint16(i+firstCode)] = uint16(glyphId)
}
}
return nil
}
func (t *ttfParser) ParseName() error { func (t *ttfParser) ParseName() error {
if err := t.Seek("name"); err != nil { if err := t.Seek("name"); err != nil {
return err return err

View File

@ -55,7 +55,7 @@ func doEncode(enc TextEncoder, raw string) string {
for _, r := range raw { for _, r := range raw {
code, found := enc.RuneToCharcode(r) code, found := enc.RuneToCharcode(r)
if !found { if !found {
common.Log.Debug("Failed to map rune to charcode for rune 0x%X", r) common.Log.Debug("Failed to map rune to charcode for rune 0x%04x", r)
continue continue
} }
encoded = append(encoded, byte(code)) encoded = append(encoded, byte(code))

View File

@ -191,7 +191,8 @@ func (se *SimpleEncoder) computeTables() {
for code, glyph := range se.differences { for code, glyph := range se.differences {
r, ok := GlyphToRune(glyph) r, ok := GlyphToRune(glyph)
if !ok { if !ok {
common.Log.Debug("ERROR: No match for glyph=%q differences=%+v", glyph, se.differences) common.Log.Debug("ERROR: No match for glyph=%q differences=%+v", glyph,
se.differences)
} }
codeToRune[uint16(code)] = r codeToRune[uint16(code)] = r
} }
@ -208,28 +209,6 @@ func (se *SimpleEncoder) computeTables() {
se.codeToGlyph = codeToGlyph se.codeToGlyph = codeToGlyph
se.glyphToCode = glyphToCode se.glyphToCode = glyphToCode
se.codeToRune = codeToRune se.codeToRune = codeToRune
if se.baseName == "SymbolEncoding" {
fmt.Printf("differences=%+v\n", se.differences)
r, ok := se.baseEncoding[0xc6]
if !ok {
panic("`0")
}
fmt.Printf("r=0x%04x=%c\n", r, r)
r, ok = codeToRune[0xc6]
if !ok {
panic("`2")
}
fmt.Printf("r=0x%04x=%c\n", r, r)
g, ok := codeToGlyph[0xc6]
if !ok {
panic("`3")
}
fmt.Printf("g=%q\n", g)
if _, ok := glyphToCode["Delta"]; !ok {
panic("`1")
}
}
} }
// FromFontDifferences converts `diffList`, a /Differences array from an /Encoding object to a map // FromFontDifferences converts `diffList`, a /Differences array from an /Encoding object to a map