diff --git a/pdf/creator/drawable.go b/pdf/creator/drawable.go index fed0ec18..4e2e8374 100644 --- a/pdf/creator/drawable.go +++ b/pdf/creator/drawable.go @@ -20,9 +20,9 @@ type VectorDrawable interface { Height() float64 } -// DrawContext defines the drawing context. The DrawContext is continuously used and updated when drawing the page -// contents in relative mode. Keeps track of current X, Y position, available height as well as other page parameters -// such as margins and dimensions. +// DrawContext defines the drawing context. The DrawContext is continuously used and updated when +// drawing the page contents in relative mode. Keeps track of current X, Y position, available +// height as well as other page parameters such as margins and dimensions. type DrawContext struct { // Current page number. Page int diff --git a/pdf/creator/paragraph.go b/pdf/creator/paragraph.go index a4bb4d72..0cbc19dc 100644 --- a/pdf/creator/paragraph.go +++ b/pdf/creator/paragraph.go @@ -125,7 +125,7 @@ func (p *Paragraph) SetEnableWrap(enableWrap bool) { p.enableWrap = enableWrap } -// SetColor set the color of the Paragraph text. +// SetColor sets the color of the Paragraph text. // // Example: // 1. p := NewParagraph("Red paragraph") @@ -219,7 +219,7 @@ func (p *Paragraph) getTextWidth() float64 { // XXX/TODO: Consider the Knuth/Plass algorithm or an alternative. func (p *Paragraph) wrapText() error { if !p.enableWrap { - p.textLines = []string{p.textFont.Encoder().Encode(p.text)} + p.textLines = []string{p.text} return nil } @@ -240,8 +240,8 @@ func (p *Paragraph) wrapText() error { metrics, found := p.textFont.GetGlyphCharMetrics(glyph) if !found { - common.Log.Debug("ERROR: Glyph char metrics not found! %q rune=0x%04x=%c font=%s", - glyph, val, val, p.textFont.BaseFont()) + common.Log.Debug("ERROR: Glyph char metrics not found! %q rune=0x%04x=%c font=%s %#q", + glyph, val, val, p.textFont.BaseFont(), p.textFont.Subtype()) common.Log.Trace("Font: %#v", p.textFont) common.Log.Trace("Encoder: %#v", p.textFont.Encoder()) 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) if p.positioning.isRelative() { - // Account for Paragraph Margins. + // Account for Paragraph margins. ctx.X += p.margins.left ctx.Y += p.margins.top 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). w := 0.0 spaces := 0 - for _, runeVal := range runes { + for i, runeVal := range runes { glyph, found := p.textFont.Encoder().RuneToGlyph(runeVal) if !found { 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) 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") } @@ -451,19 +453,13 @@ func drawParagraphOnBlock(blk *Block, p *Paragraph, ctx DrawContext) (DrawContex encStr := "" for _, runeVal := range runes { - //creator.Add_Tj(core.PdfObjectString(tb.Encoder.Encode(line))) glyph, found := p.textFont.Encoder().RuneToGlyph(runeVal) if !found { common.Log.Debug("Rune 0x%x not supported by text encoder", runeVal) return ctx, errors.New("Unsupported rune in text encoding") } - if glyph == "space" { - if !found { - common.Log.Debug("Unsupported glyph %s in font", glyph) - return ctx, errors.New("Unsupported text glyph") - } - + if glyph == "space" { // XXX: What about \t and other spaces. if len(encStr) > 0 { objs = append(objs, core.MakeString(encStr)) encStr = "" diff --git a/pdf/creator/table.go b/pdf/creator/table.go index a191fb94..edf2ac49 100644 --- a/pdf/creator/table.go +++ b/pdf/creator/table.go @@ -9,6 +9,7 @@ import ( "errors" "github.com/unidoc/unidoc/common" + "github.com/unidoc/unidoc/pdf/core" "github.com/unidoc/unidoc/pdf/model" ) @@ -130,7 +131,8 @@ func (table *Table) CurCol() int { 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. // TODO: Should be able to set width too (not just based on context/relative positioning mode). func (table *Table) SetPos(x, y float64) { @@ -139,7 +141,8 @@ func (table *Table) SetPos(x, y float64) { 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. func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) { blocks := []*Block{} @@ -232,7 +235,7 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, } err := block.Draw(rect) if err != nil { - common.Log.Debug("Error: %v\n", err) + common.Log.Debug("ERROR: %v\n", err) } } else if cell.borderStyle != CellBorderStyleNone { // Draw border (no fill). @@ -244,7 +247,7 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, rect.SetBorderColor(ColorRGBFromArithmetic(r, g, b)) err := block.Draw(rect) 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) 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 default: - common.Log.Debug("Error: unsupported cell content type %T\n", vd) - return errors.New("Type check error") + common.Log.Debug("ERROR: unsupported cell content type %T", vd) + return core.ErrTypeError } return nil diff --git a/pdf/model/fonts/ttfparser.go b/pdf/model/fonts/ttfparser.go index 6afd9eb6..15145c17 100644 --- a/pdf/model/fonts/ttfparser.go +++ b/pdf/model/fonts/ttfparser.go @@ -146,7 +146,8 @@ func (t *ttfParser) Parse() (TtfType, error) { return TtfType{}, errors.New("fonts based on PostScript outlines are not supported") } 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()) t.Skip(3 * 2) // searchRange, entrySelector, rangeShift @@ -460,6 +461,8 @@ func (t *ttfParser) parseCmapVersion(offset int64) error { return t.parseCmapFormat0() case 6: return t.parseCmapFormat6() + case 12: + return t.parseCmapFormat12() default: 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. @@ -496,6 +499,43 @@ func (t *ttfParser) parseCmapFormat6() error { 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 { if err := t.Seek("name"); err != nil { return err diff --git a/pdf/model/textencoding/encoder.go b/pdf/model/textencoding/encoder.go index ef391b7c..96c4f15a 100644 --- a/pdf/model/textencoding/encoder.go +++ b/pdf/model/textencoding/encoder.go @@ -55,7 +55,7 @@ func doEncode(enc TextEncoder, raw string) string { for _, r := range raw { code, found := enc.RuneToCharcode(r) 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 } encoded = append(encoded, byte(code)) diff --git a/pdf/model/textencoding/simple.go b/pdf/model/textencoding/simple.go index c25de63d..eae0d130 100644 --- a/pdf/model/textencoding/simple.go +++ b/pdf/model/textencoding/simple.go @@ -191,7 +191,8 @@ func (se *SimpleEncoder) computeTables() { 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) + common.Log.Debug("ERROR: No match for glyph=%q differences=%+v", glyph, + se.differences) } codeToRune[uint16(code)] = r } @@ -208,28 +209,6 @@ func (se *SimpleEncoder) computeTables() { se.codeToGlyph = codeToGlyph se.glyphToCode = glyphToCode 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