mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-02 22:17:06 +08:00
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:
parent
fefff56603
commit
c2feafdfdc
@ -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
|
||||||
|
@ -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 = ""
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user