mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-01 22:17:29 +08:00
Merge pull request #185 from peterwilliams97/render.v3.hungarian
Render.v3.hungarian
This commit is contained in:
commit
688ded7dae
@ -144,11 +144,19 @@ func MakeFloat(val float64) *PdfObjectFloat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MakeString creates an PdfObjectString from a string.
|
// MakeString creates an PdfObjectString from a string.
|
||||||
|
// NOTE: PDF does not use utf-8 string encoding like Go so `s` will often not be a utf-8 encoded
|
||||||
|
// string.
|
||||||
func MakeString(s string) *PdfObjectString {
|
func MakeString(s string) *PdfObjectString {
|
||||||
str := PdfObjectString{val: s}
|
str := PdfObjectString{val: s}
|
||||||
return &str
|
return &str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MakeStringFromBytes creates an PdfObjectString from a byte array.
|
||||||
|
// This is more natural than MakeString as `data` is usually not utf-8 encoded.
|
||||||
|
func MakeStringFromBytes(data []byte) *PdfObjectString {
|
||||||
|
return MakeString(string(data))
|
||||||
|
}
|
||||||
|
|
||||||
// MakeHexString creates an PdfObjectString from a string intended for output as a hexadecimal string.
|
// MakeHexString creates an PdfObjectString from a string intended for output as a hexadecimal string.
|
||||||
func MakeHexString(s string) *PdfObjectString {
|
func MakeHexString(s string) *PdfObjectString {
|
||||||
str := PdfObjectString{val: s, isHex: true}
|
str := PdfObjectString{val: s, isHex: true}
|
||||||
|
@ -51,8 +51,8 @@ func NewBlock(width float64, height float64) *Block {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlockFromPage creates a Block from a PDF Page. Useful for loading template pages as blocks from a PDF document
|
// NewBlockFromPage creates a Block from a PDF Page. Useful for loading template pages as blocks
|
||||||
// and additional content with the creator.
|
// from a PDF document and additional content with the creator.
|
||||||
func NewBlockFromPage(page *model.PdfPage) (*Block, error) {
|
func NewBlockFromPage(page *model.PdfPage) (*Block, error) {
|
||||||
b := &Block{}
|
b := &Block{}
|
||||||
|
|
||||||
|
@ -10,11 +10,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/unidoc/unidoc/common"
|
"github.com/unidoc/unidoc/common"
|
||||||
"github.com/unidoc/unidoc/pdf/model/fonts"
|
"github.com/unidoc/unidoc/pdf/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Chapter is used to arrange multiple drawables (paragraphs, images, etc) into a single section. The concept is
|
// Chapter is used to arrange multiple drawables (paragraphs, images, etc) into a single section.
|
||||||
// the same as a book or a report chapter.
|
// The concept is the same as a book or a report chapter.
|
||||||
type Chapter struct {
|
type Chapter struct {
|
||||||
number int
|
number int
|
||||||
title string
|
title string
|
||||||
@ -57,7 +57,8 @@ func (c *Creator) NewChapter(title string) *Chapter {
|
|||||||
heading := fmt.Sprintf("%d. %s", c.chapters, title)
|
heading := fmt.Sprintf("%d. %s", c.chapters, title)
|
||||||
p := NewParagraph(heading)
|
p := NewParagraph(heading)
|
||||||
p.SetFontSize(16)
|
p.SetFontSize(16)
|
||||||
p.SetFont(fonts.NewFontHelvetica()) // bold?
|
helvetica, _ := model.NewStandard14Font("Helvetica")
|
||||||
|
p.SetFont(helvetica) // bold?
|
||||||
|
|
||||||
chap.heading = p
|
chap.heading = p
|
||||||
chap.contents = []Drawable{}
|
chap.contents = []Drawable{}
|
||||||
@ -113,7 +114,7 @@ func (chap *Chapter) Add(d Drawable) error {
|
|||||||
|
|
||||||
switch d.(type) {
|
switch d.(type) {
|
||||||
case *Chapter:
|
case *Chapter:
|
||||||
common.Log.Debug("Error: Cannot add chapter to a chapter")
|
common.Log.Debug("ERROR: Cannot add chapter to a chapter")
|
||||||
return errors.New("Type check error")
|
return errors.New("Type check error")
|
||||||
case *Paragraph, *Image, *Block, *Subchapter, *Table, *PageBreak:
|
case *Paragraph, *Image, *Block, *Subchapter, *Table, *PageBreak:
|
||||||
chap.contents = append(chap.contents, d)
|
chap.contents = append(chap.contents, d)
|
||||||
@ -125,8 +126,8 @@ func (chap *Chapter) Add(d Drawable) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GeneratePageBlocks generate the Page blocks. Multiple blocks are generated if the contents wrap over
|
// GeneratePageBlocks generate the Page blocks. Multiple blocks are generated if the contents wrap
|
||||||
// multiple pages.
|
// over multiple pages.
|
||||||
func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||||
origCtx := ctx
|
origCtx := ctx
|
||||||
|
|
||||||
@ -175,7 +176,6 @@ func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
|||||||
if chap.positioning.isAbsolute() {
|
if chap.positioning.isAbsolute() {
|
||||||
// If absolute: return original context.
|
// If absolute: return original context.
|
||||||
return blocks, origCtx, nil
|
return blocks, origCtx, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return blocks, ctx, nil
|
return blocks, ctx, nil
|
||||||
|
@ -46,28 +46,31 @@ type Creator struct {
|
|||||||
acroForm *model.PdfAcroForm
|
acroForm *model.PdfAcroForm
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetForms Add Acroforms to a PDF file. Sets the specified form for writing.
|
// SetForms adds an Acroform to a PDF file. Sets the specified form for writing.
|
||||||
func (c *Creator) SetForms(form *model.PdfAcroForm) error {
|
func (c *Creator) SetForms(form *model.PdfAcroForm) error {
|
||||||
c.acroForm = form
|
c.acroForm = form
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FrontpageFunctionArgs holds the input arguments to a front page drawing function.
|
// FrontpageFunctionArgs holds the input arguments to a front page drawing function.
|
||||||
// It is designed as a struct, so additional parameters can be added in the future with backwards compatibility.
|
// It is designed as a struct, so additional parameters can be added in the future with backwards
|
||||||
|
// compatibility.
|
||||||
type FrontpageFunctionArgs struct {
|
type FrontpageFunctionArgs struct {
|
||||||
PageNum int
|
PageNum int
|
||||||
TotalPages int
|
TotalPages int
|
||||||
}
|
}
|
||||||
|
|
||||||
// HeaderFunctionArgs holds the input arguments to a header drawing function.
|
// HeaderFunctionArgs holds the input arguments to a header drawing function.
|
||||||
// It is designed as a struct, so additional parameters can be added in the future with backwards compatibility.
|
// It is designed as a struct, so additional parameters can be added in the future with backwards
|
||||||
|
// compatibility.
|
||||||
type HeaderFunctionArgs struct {
|
type HeaderFunctionArgs struct {
|
||||||
PageNum int
|
PageNum int
|
||||||
TotalPages int
|
TotalPages int
|
||||||
}
|
}
|
||||||
|
|
||||||
// FooterFunctionArgs holds the input arguments to a footer drawing function.
|
// FooterFunctionArgs holds the input arguments to a footer drawing function.
|
||||||
// It is designed as a struct, so additional parameters can be added in the future with backwards compatibility.
|
// It is designed as a struct, so additional parameters can be added in the future with backwards
|
||||||
|
// compatibility.
|
||||||
type FooterFunctionArgs struct {
|
type FooterFunctionArgs struct {
|
||||||
PageNum int
|
PageNum int
|
||||||
TotalPages int
|
TotalPages int
|
||||||
@ -131,7 +134,8 @@ func (c *Creator) getActivePage() *model.PdfPage {
|
|||||||
return c.activePage
|
return c.activePage
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPageSize sets the Creator's page size. Pages that are added after this will be created with this Page size.
|
// SetPageSize sets the Creator's page size. Pages that are added after this will be created with
|
||||||
|
// this Page size.
|
||||||
// Does not affect pages already created.
|
// Does not affect pages already created.
|
||||||
//
|
//
|
||||||
// Common page sizes are defined as constants.
|
// Common page sizes are defined as constants.
|
||||||
@ -238,8 +242,8 @@ func (c *Creator) AddPage(page *model.PdfPage) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RotateDeg rotates the current active page by angle degrees. An error is returned on failure, which can be
|
// RotateDeg rotates the current active page by angle degrees. An error is returned on failure,
|
||||||
// if there is no currently active page, or the angleDeg is not a multiple of 90 degrees.
|
// which can be if there is no currently active page, or the angleDeg is not a multiple of 90 degrees.
|
||||||
func (c *Creator) RotateDeg(angleDeg int64) error {
|
func (c *Creator) RotateDeg(angleDeg int64) error {
|
||||||
page := c.getActivePage()
|
page := c.getActivePage()
|
||||||
if page == nil {
|
if page == nil {
|
||||||
@ -247,7 +251,7 @@ func (c *Creator) RotateDeg(angleDeg int64) error {
|
|||||||
return errors.New("No page active")
|
return errors.New("No page active")
|
||||||
}
|
}
|
||||||
if angleDeg%90 != 0 {
|
if angleDeg%90 != 0 {
|
||||||
common.Log.Debug("Error: Page rotation angle not a multiple of 90")
|
common.Log.Debug("ERROR: Page rotation angle not a multiple of 90")
|
||||||
return errors.New("Range check error")
|
return errors.New("Range check error")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,8 +271,8 @@ func (c *Creator) Context() DrawContext {
|
|||||||
return c.context
|
return c.context
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call before writing out. Takes care of adding headers and footers, as well as generating front Page and
|
// Call before writing out. Takes care of adding headers and footers, as well as generating front
|
||||||
// table of contents.
|
// Page and table of contents.
|
||||||
func (c *Creator) finalize() error {
|
func (c *Creator) finalize() error {
|
||||||
totPages := len(c.pages)
|
totPages := len(c.pages)
|
||||||
|
|
||||||
@ -356,8 +360,8 @@ func (c *Creator) finalize() error {
|
|||||||
c.setActivePage(page)
|
c.setActivePage(page)
|
||||||
if c.drawHeaderFunc != nil {
|
if c.drawHeaderFunc != nil {
|
||||||
// Prepare a block to draw on.
|
// Prepare a block to draw on.
|
||||||
// Header is drawn on the top of the page. Has width of the page, but height limited to the page
|
// Header is drawn on the top of the page. Has width of the page, but height limited to
|
||||||
// margin top height.
|
// the page margin top height.
|
||||||
headerBlock := NewBlock(c.pageWidth, c.pageMargins.top)
|
headerBlock := NewBlock(c.pageWidth, c.pageMargins.top)
|
||||||
args := HeaderFunctionArgs{
|
args := HeaderFunctionArgs{
|
||||||
PageNum: idx + 1,
|
PageNum: idx + 1,
|
||||||
@ -367,15 +371,15 @@ func (c *Creator) finalize() error {
|
|||||||
headerBlock.SetPos(0, 0)
|
headerBlock.SetPos(0, 0)
|
||||||
err := c.Draw(headerBlock)
|
err := c.Draw(headerBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("Error drawing header: %v", err)
|
common.Log.Debug("ERROR: drawing header: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if c.drawFooterFunc != nil {
|
if c.drawFooterFunc != nil {
|
||||||
// Prepare a block to draw on.
|
// Prepare a block to draw on.
|
||||||
// Footer is drawn on the bottom of the page. Has width of the page, but height limited to the page
|
// Footer is drawn on the bottom of the page. Has width of the page, but height limited
|
||||||
// margin bottom height.
|
// to the page margin bottom height.
|
||||||
footerBlock := NewBlock(c.pageWidth, c.pageMargins.bottom)
|
footerBlock := NewBlock(c.pageWidth, c.pageMargins.bottom)
|
||||||
args := FooterFunctionArgs{
|
args := FooterFunctionArgs{
|
||||||
PageNum: idx + 1,
|
PageNum: idx + 1,
|
||||||
@ -385,7 +389,7 @@ func (c *Creator) finalize() error {
|
|||||||
footerBlock.SetPos(0, c.pageHeight-footerBlock.height)
|
footerBlock.SetPos(0, c.pageHeight-footerBlock.height)
|
||||||
err := c.Draw(footerBlock)
|
err := c.Draw(footerBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("Error drawing footer: %v", err)
|
common.Log.Debug("ERROR: drawing footer: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -422,8 +426,8 @@ func (c *Creator) MoveDown(dy float64) {
|
|||||||
c.context.Y += dy
|
c.context.Y += dy
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw draws the Drawable widget to the document. This can span over 1 or more pages. Additional pages are added if
|
// Draw draws the Drawable widget to the document. This can span over 1 or more pages. Additional
|
||||||
// the contents go over the current Page.
|
// pages are added if the contents go over the current Page.
|
||||||
func (c *Creator) Draw(d Drawable) error {
|
func (c *Creator) Draw(d Drawable) error {
|
||||||
if c.getActivePage() == nil {
|
if c.getActivePage() == nil {
|
||||||
// Add a new Page if none added already.
|
// Add a new Page if none added already.
|
||||||
@ -464,10 +468,10 @@ func (c *Creator) Write(ws io.WriteSeeker) error {
|
|||||||
pdfWriter := model.NewPdfWriter()
|
pdfWriter := model.NewPdfWriter()
|
||||||
// Form fields.
|
// Form fields.
|
||||||
if c.acroForm != nil {
|
if c.acroForm != nil {
|
||||||
errF := pdfWriter.SetForms(c.acroForm)
|
err := pdfWriter.SetForms(c.acroForm)
|
||||||
if errF != nil {
|
if err != nil {
|
||||||
common.Log.Debug("Failure: %v", errF)
|
common.Log.Debug("Failure: %v", err)
|
||||||
return errF
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,7 +487,7 @@ func (c *Creator) Write(ws io.WriteSeeker) error {
|
|||||||
for _, page := range c.pages {
|
for _, page := range c.pages {
|
||||||
err := pdfWriter.AddPage(page)
|
err := pdfWriter.AddPage(page)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Error("Failed to add Page: %s", err)
|
common.Log.Error("Failed to add Page: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -519,13 +523,7 @@ func (c *Creator) WriteToFile(outputPath string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer fWrite.Close()
|
defer fWrite.Close()
|
||||||
|
|
||||||
err = c.Write(fWrite)
|
return c.Write(fWrite)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,10 @@ import (
|
|||||||
|
|
||||||
"github.com/boombuler/barcode"
|
"github.com/boombuler/barcode"
|
||||||
"github.com/boombuler/barcode/qr"
|
"github.com/boombuler/barcode/qr"
|
||||||
|
|
||||||
"github.com/unidoc/unidoc/common"
|
"github.com/unidoc/unidoc/common"
|
||||||
"github.com/unidoc/unidoc/pdf/contentstream/draw"
|
"github.com/unidoc/unidoc/pdf/contentstream/draw"
|
||||||
"github.com/unidoc/unidoc/pdf/core"
|
"github.com/unidoc/unidoc/pdf/core"
|
||||||
"github.com/unidoc/unidoc/pdf/model"
|
"github.com/unidoc/unidoc/pdf/model"
|
||||||
"github.com/unidoc/unidoc/pdf/model/fonts"
|
|
||||||
"github.com/unidoc/unidoc/pdf/model/textencoding"
|
"github.com/unidoc/unidoc/pdf/model/textencoding"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -234,7 +232,8 @@ func TestShapes1(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example drawing image and line shape on a block and applying to pages, also demonstrating block rotation.
|
// Example drawing image and line shape on a block and applying to pages, also demonstrating block
|
||||||
|
// rotation.
|
||||||
func TestShapesOnBlock(t *testing.T) {
|
func TestShapesOnBlock(t *testing.T) {
|
||||||
creator := New()
|
creator := New()
|
||||||
|
|
||||||
@ -421,9 +420,10 @@ func TestParagraph1(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test paragraph and page and text wrapping with left, justify, center and right modes.
|
// Test paragraph and page and text wrapping with left, justify, center and right modes.
|
||||||
// TODO: In the future we would like the paragraph to split up between pages. Split up on line, never allowing
|
// TODO: In the future we would like the paragraph to split up between pages. Split up on line,
|
||||||
// less than 2 lines to go over (common practice).
|
// never allowing less than 2 lines to go over (common practice).
|
||||||
// TODO: In the future we would like to implement Donald Knuth's line wrapping algorithm or something similar.
|
// TODO: In the future we would like to implement Donald Knuth's line wrapping algorithm or
|
||||||
|
// something similar.
|
||||||
func TestParagraphWrapping(t *testing.T) {
|
func TestParagraphWrapping(t *testing.T) {
|
||||||
creator := New()
|
creator := New()
|
||||||
|
|
||||||
@ -435,7 +435,8 @@ func TestParagraphWrapping(t *testing.T) {
|
|||||||
|
|
||||||
p.SetMargins(0, 0, 5, 0)
|
p.SetMargins(0, 0, 5, 0)
|
||||||
|
|
||||||
alignments := []TextAlignment{TextAlignmentLeft, TextAlignmentJustify, TextAlignmentCenter, TextAlignmentRight}
|
alignments := []TextAlignment{TextAlignmentLeft, TextAlignmentJustify, TextAlignmentCenter,
|
||||||
|
TextAlignmentRight}
|
||||||
for j := 0; j < 25; j++ {
|
for j := 0; j < 25; j++ {
|
||||||
//p.SetAlignment(alignments[j%4])
|
//p.SetAlignment(alignments[j%4])
|
||||||
p.SetTextAlignment(alignments[1])
|
p.SetTextAlignment(alignments[1])
|
||||||
@ -463,7 +464,8 @@ func TestParagraphWrapping2(t *testing.T) {
|
|||||||
"eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " +
|
"eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " +
|
||||||
"mollit anim id est laborum.")
|
"mollit anim id est laborum.")
|
||||||
|
|
||||||
alignments := []TextAlignment{TextAlignmentLeft, TextAlignmentJustify, TextAlignmentCenter, TextAlignmentRight}
|
alignments := []TextAlignment{TextAlignmentLeft, TextAlignmentJustify, TextAlignmentCenter,
|
||||||
|
TextAlignmentRight}
|
||||||
for j := 0; j < 25; j++ {
|
for j := 0; j < 25; j++ {
|
||||||
//p.SetAlignment(alignments[j%4])
|
//p.SetAlignment(alignments[j%4])
|
||||||
p.SetMargins(50, 50, 50, 50)
|
p.SetMargins(50, 50, 50, 50)
|
||||||
@ -499,7 +501,13 @@ func TestParagraphFonts(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fonts := []fonts.Font{roboto, robotoBold, fonts.NewFontHelvetica(), roboto, robotoBold, fonts.NewFontHelvetica()}
|
helvetica, err := model.NewStandard14Font("Helvetica")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Fail: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fonts := []*model.PdfFont{roboto, robotoBold, helvetica, roboto, robotoBold, helvetica}
|
||||||
for _, font := range fonts {
|
for _, font := range fonts {
|
||||||
p := NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" +
|
p := NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" +
|
||||||
"ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " +
|
"ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " +
|
||||||
@ -547,22 +555,7 @@ func TestParagraphStandardFonts(t *testing.T) {
|
|||||||
"Symbol",
|
"Symbol",
|
||||||
"ZapfDingbats",
|
"ZapfDingbats",
|
||||||
}
|
}
|
||||||
fonts := []fonts.Font{
|
|
||||||
fonts.NewFontCourier(),
|
|
||||||
fonts.NewFontCourierBold(),
|
|
||||||
fonts.NewFontCourierBoldOblique(),
|
|
||||||
fonts.NewFontCourierOblique(),
|
|
||||||
fonts.NewFontHelvetica(),
|
|
||||||
fonts.NewFontHelveticaBold(),
|
|
||||||
fonts.NewFontHelveticaBoldOblique(),
|
|
||||||
fonts.NewFontHelveticaOblique(),
|
|
||||||
fonts.NewFontTimesRoman(),
|
|
||||||
fonts.NewFontTimesBold(),
|
|
||||||
fonts.NewFontTimesBoldItalic(),
|
|
||||||
fonts.NewFontTimesItalic(),
|
|
||||||
fonts.NewFontSymbol(),
|
|
||||||
fonts.NewFontZapfDingbats(),
|
|
||||||
}
|
|
||||||
texts := []string{
|
texts := []string{
|
||||||
"Courier: Lorem ipsum dolor sit amet, consectetur adipiscing elit...",
|
"Courier: Lorem ipsum dolor sit amet, consectetur adipiscing elit...",
|
||||||
"Courier-Bold: Lorem ipsum dolor sit amet, consectetur adipiscing elit...",
|
"Courier-Bold: Lorem ipsum dolor sit amet, consectetur adipiscing elit...",
|
||||||
@ -582,8 +575,13 @@ func TestParagraphStandardFonts(t *testing.T) {
|
|||||||
"\u2702\u0020\u2709\u261e\u2711\u2714", // a2 (scissors) space a117 (mail) a12 (finger) a17 (pen) a20 (checkmark)
|
"\u2702\u0020\u2709\u261e\u2711\u2714", // a2 (scissors) space a117 (mail) a12 (finger) a17 (pen) a20 (checkmark)
|
||||||
}
|
}
|
||||||
|
|
||||||
for idx, font := range fonts {
|
for idx, name := range names {
|
||||||
p := NewParagraph(texts[idx])
|
p := NewParagraph(texts[idx])
|
||||||
|
font, err := model.NewStandard14Font(name)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Fail: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
p.SetFont(font)
|
p.SetFont(font)
|
||||||
p.SetFontSize(12)
|
p.SetFontSize(12)
|
||||||
p.SetLineHeight(1.2)
|
p.SetLineHeight(1.2)
|
||||||
@ -597,7 +595,7 @@ func TestParagraphStandardFonts(t *testing.T) {
|
|||||||
p.SetEncoder(textencoding.NewZapfDingbatsEncoder())
|
p.SetEncoder(textencoding.NewZapfDingbatsEncoder())
|
||||||
}
|
}
|
||||||
|
|
||||||
err := creator.Draw(p)
|
err = creator.Draw(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Fail: %v\n", err)
|
t.Errorf("Fail: %v\n", err)
|
||||||
return
|
return
|
||||||
@ -1235,7 +1233,7 @@ func TestBorderedTable2(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContent(text string, alignment TextAlignment, font fonts.Font, fontSize float64, color Color) *Paragraph {
|
func newContent(text string, alignment TextAlignment, font *model.PdfFont, fontSize float64, color Color) *Paragraph {
|
||||||
p := NewParagraph(text)
|
p := NewParagraph(text)
|
||||||
p.SetFontSize(fontSize)
|
p.SetFontSize(fontSize)
|
||||||
p.SetTextAlignment(alignment)
|
p.SetTextAlignment(alignment)
|
||||||
@ -1245,26 +1243,30 @@ func newContent(text string, alignment TextAlignment, font fonts.Font, fontSize
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newBillItem(t *Table, no, date, notes, amount, con, retApplied, ret, netBill string) {
|
func newBillItem(t *Table, no, date, notes, amount, con, retApplied, ret, netBill string) {
|
||||||
|
timesBold, _ := model.NewStandard14Font("Times-Bold")
|
||||||
|
|
||||||
billNo := t.NewCell()
|
billNo := t.NewCell()
|
||||||
billNo.SetContent(newContent(no, TextAlignmentLeft, fonts.NewFontTimesBold(), 8, ColorBlack))
|
billNo.SetContent(newContent(no, TextAlignmentLeft, timesBold, 8, ColorBlack))
|
||||||
billDate := t.NewCell()
|
billDate := t.NewCell()
|
||||||
billDate.SetContent(newContent(date, TextAlignmentCenter, fonts.NewFontTimesBold(), 8, ColorBlack))
|
billDate.SetContent(newContent(date, TextAlignmentCenter, timesBold, 8, ColorBlack))
|
||||||
billNotes := t.NewCell()
|
billNotes := t.NewCell()
|
||||||
billNotes.SetContent(newContent(notes, TextAlignmentLeft, fonts.NewFontTimesBold(), 8, ColorBlack))
|
billNotes.SetContent(newContent(notes, TextAlignmentLeft, timesBold, 8, ColorBlack))
|
||||||
billAmount := t.NewCell()
|
billAmount := t.NewCell()
|
||||||
billAmount.SetContent(newContent(amount, TextAlignmentRight, fonts.NewFontTimesBold(), 8, ColorBlack))
|
billAmount.SetContent(newContent(amount, TextAlignmentRight, timesBold, 8, ColorBlack))
|
||||||
billCon := t.NewCell()
|
billCon := t.NewCell()
|
||||||
billCon.SetContent(newContent(con, TextAlignmentLeft, fonts.NewFontTimesBold(), 8, ColorBlack))
|
billCon.SetContent(newContent(con, TextAlignmentLeft, timesBold, 8, ColorBlack))
|
||||||
billRetApplied := t.NewCell()
|
billRetApplied := t.NewCell()
|
||||||
billRetApplied.SetContent(newContent(retApplied, TextAlignmentRight, fonts.NewFontTimesBold(), 8, ColorBlack))
|
billRetApplied.SetContent(newContent(retApplied, TextAlignmentRight, timesBold, 8, ColorBlack))
|
||||||
billRet := t.NewCell()
|
billRet := t.NewCell()
|
||||||
billRet.SetContent(newContent(ret, TextAlignmentLeft, fonts.NewFontTimesBold(), 8, ColorBlack))
|
billRet.SetContent(newContent(ret, TextAlignmentLeft, timesBold, 8, ColorBlack))
|
||||||
billNetBill := t.NewCell()
|
billNetBill := t.NewCell()
|
||||||
billNetBill.SetContent(newContent(netBill, TextAlignmentRight, fonts.NewFontTimesBold(), 8, ColorBlack))
|
billNetBill.SetContent(newContent(netBill, TextAlignmentRight, timesBold, 8, ColorBlack))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test creating and drawing a table.
|
// Test creating and drawing a table.
|
||||||
func TestCreatorHendricksReq1(t *testing.T) {
|
func TestCreatorHendricksReq1(t *testing.T) {
|
||||||
|
timesRoman, _ := model.NewStandard14Font("Times-Roman")
|
||||||
|
timesBold, _ := model.NewStandard14Font("Times-Bold")
|
||||||
table := NewTable(3) // Mx4 table
|
table := NewTable(3) // Mx4 table
|
||||||
// Default, equal column sizes (4x0.25)...
|
// Default, equal column sizes (4x0.25)...
|
||||||
table.SetColumnWidths(0.35, 0.30, 0.35)
|
table.SetColumnWidths(0.35, 0.30, 0.35)
|
||||||
@ -1273,146 +1275,146 @@ func TestCreatorHendricksReq1(t *testing.T) {
|
|||||||
projectColorTwo := ColorRed
|
projectColorTwo := ColorRed
|
||||||
|
|
||||||
companyTitle := table.NewCell()
|
companyTitle := table.NewCell()
|
||||||
companyTitle.SetContent(newContent("Hendricks Consulting LLC", TextAlignmentLeft, fonts.NewFontTimesBold(), 12, projectColorOne))
|
companyTitle.SetContent(newContent("Hendricks Consulting LLC", TextAlignmentLeft, timesBold, 12, projectColorOne))
|
||||||
|
|
||||||
table.SkipCells(1)
|
table.SkipCells(1)
|
||||||
|
|
||||||
pageHeader := table.NewCell()
|
pageHeader := table.NewCell()
|
||||||
pageHeader.SetContent(newContent("Billing Schedule by Project", TextAlignmentCenter, fonts.NewFontTimesBold(), 12, ColorBlack))
|
pageHeader.SetContent(newContent("Billing Schedule by Project", TextAlignmentCenter, timesBold, 12, ColorBlack))
|
||||||
pageHeader.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 3)
|
pageHeader.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 3)
|
||||||
pageHeader.SetBorderLineStyle(draw.LineStyleSolid)
|
pageHeader.SetBorderLineStyle(draw.LineStyleSolid)
|
||||||
|
|
||||||
companyAddress := table.NewCell()
|
companyAddress := table.NewCell()
|
||||||
companyAddress.SetContent(newContent("2666 Airport Drive, Apt. 309", TextAlignmentLeft, fonts.NewFontTimesRoman(), 8, ColorBlack))
|
companyAddress.SetContent(newContent("2666 Airport Drive, Apt. 309", TextAlignmentLeft, timesRoman, 8, ColorBlack))
|
||||||
|
|
||||||
table.SkipCells(2)
|
table.SkipCells(2)
|
||||||
|
|
||||||
companyLocation := table.NewCell()
|
companyLocation := table.NewCell()
|
||||||
companyLocation.SetContent(newContent("Portland, Oregon, 92019", TextAlignmentLeft, fonts.NewFontTimesRoman(), 8, ColorBlack))
|
companyLocation.SetContent(newContent("Portland, Oregon, 92019", TextAlignmentLeft, timesRoman, 8, ColorBlack))
|
||||||
|
|
||||||
table.SkipCells(1)
|
table.SkipCells(1)
|
||||||
|
|
||||||
printingDate := table.NewCell()
|
printingDate := table.NewCell()
|
||||||
printingDate.SetContent(newContent("Printed on: 22/02/2011", TextAlignmentRight, fonts.NewFontTimesRoman(), 8, ColorBlack))
|
printingDate.SetContent(newContent("Printed on: 22/02/2011", TextAlignmentRight, timesRoman, 8, ColorBlack))
|
||||||
|
|
||||||
companyTelAndFax := table.NewCell()
|
companyTelAndFax := table.NewCell()
|
||||||
companyTelAndFax.SetContent(newContent("Tel: (999) 609-4032 Fax: (999) 999-9922", TextAlignmentLeft, fonts.NewFontTimesRoman(), 8, ColorBlack))
|
companyTelAndFax.SetContent(newContent("Tel: (999) 609-4032 Fax: (999) 999-9922", TextAlignmentLeft, timesRoman, 8, ColorBlack))
|
||||||
|
|
||||||
table.SkipCells(1)
|
table.SkipCells(1)
|
||||||
|
|
||||||
pageOf := table.NewCell()
|
pageOf := table.NewCell()
|
||||||
pageOf.SetContent(newContent("Page 10 of 10", TextAlignmentRight, fonts.NewFontTimesRoman(), 8, ColorBlack))
|
pageOf.SetContent(newContent("Page 10 of 10", TextAlignmentRight, timesRoman, 8, ColorBlack))
|
||||||
|
|
||||||
email := table.NewCell()
|
email := table.NewCell()
|
||||||
email.SetContent(newContent("admin@hendricks.com", TextAlignmentLeft, fonts.NewFontTimesRoman(), 8, ColorBlack))
|
email.SetContent(newContent("admin@hendricks.com", TextAlignmentLeft, timesRoman, 8, ColorBlack))
|
||||||
|
|
||||||
table.SkipCells(2)
|
table.SkipCells(2)
|
||||||
|
|
||||||
website := table.NewCell()
|
website := table.NewCell()
|
||||||
website.SetContent(newContent("www.hendricks.com", TextAlignmentLeft, fonts.NewFontTimesRoman(), 8, ColorBlack))
|
website.SetContent(newContent("www.hendricks.com", TextAlignmentLeft, timesRoman, 8, ColorBlack))
|
||||||
|
|
||||||
table2 := NewTable(5)
|
table2 := NewTable(5)
|
||||||
table2.SetColumnWidths(0.20, 0.20, 0.20, 0.20, 0.20)
|
table2.SetColumnWidths(0.20, 0.20, 0.20, 0.20, 0.20)
|
||||||
table2.SkipCells(5)
|
table2.SkipCells(5)
|
||||||
|
|
||||||
projectName := table2.NewCell()
|
projectName := table2.NewCell()
|
||||||
projectName.SetContent(newContent("Project Name (ID):", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, projectColorOne))
|
projectName.SetContent(newContent("Project Name (ID):", TextAlignmentLeft, timesBold, 8, projectColorOne))
|
||||||
|
|
||||||
projectNameValue := table2.NewCell()
|
projectNameValue := table2.NewCell()
|
||||||
projectNameValue.SetContent(newContent("Biggi Group", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, ColorBlack))
|
projectNameValue.SetContent(newContent("Biggi Group", TextAlignmentLeft, timesBold, 8, ColorBlack))
|
||||||
|
|
||||||
table2.SkipCells(3)
|
table2.SkipCells(3)
|
||||||
|
|
||||||
projectID := table2.NewCell()
|
projectID := table2.NewCell()
|
||||||
projectID.SetContent(newContent("Project ID:", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, projectColorOne))
|
projectID.SetContent(newContent("Project ID:", TextAlignmentLeft, timesBold, 8, projectColorOne))
|
||||||
|
|
||||||
projectIDValue := table2.NewCell()
|
projectIDValue := table2.NewCell()
|
||||||
projectIDValue.SetContent(newContent("BG:01", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, ColorBlack))
|
projectIDValue.SetContent(newContent("BG:01", TextAlignmentLeft, timesBold, 8, ColorBlack))
|
||||||
|
|
||||||
table2.SkipCells(1)
|
table2.SkipCells(1)
|
||||||
|
|
||||||
contractType := table2.NewCell()
|
contractType := table2.NewCell()
|
||||||
contractType.SetContent(newContent("Contract Type:", TextAlignmentRight, fonts.NewFontTimesBold(), 8, projectColorOne))
|
contractType.SetContent(newContent("Contract Type:", TextAlignmentRight, timesBold, 8, projectColorOne))
|
||||||
|
|
||||||
contractTypeValue := table2.NewCell()
|
contractTypeValue := table2.NewCell()
|
||||||
contractTypeValue.SetContent(newContent("Percentage", TextAlignmentLeft, fonts.NewFontTimesRoman(), 8, ColorBlack))
|
contractTypeValue.SetContent(newContent("Percentage", TextAlignmentLeft, timesRoman, 8, ColorBlack))
|
||||||
|
|
||||||
projectManager := table2.NewCell()
|
projectManager := table2.NewCell()
|
||||||
projectManager.SetContent(newContent("Manager:", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, projectColorOne))
|
projectManager.SetContent(newContent("Manager:", TextAlignmentLeft, timesBold, 8, projectColorOne))
|
||||||
|
|
||||||
projectManagerValue := table2.NewCell()
|
projectManagerValue := table2.NewCell()
|
||||||
projectManagerValue.SetContent(newContent("SHH", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, ColorBlack))
|
projectManagerValue.SetContent(newContent("SHH", TextAlignmentLeft, timesBold, 8, ColorBlack))
|
||||||
|
|
||||||
table2.SkipCells(1)
|
table2.SkipCells(1)
|
||||||
|
|
||||||
contractAmount := table2.NewCell()
|
contractAmount := table2.NewCell()
|
||||||
contractAmount.SetContent(newContent("Contract Amount:", TextAlignmentRight, fonts.NewFontTimesBold(), 8, projectColorOne))
|
contractAmount.SetContent(newContent("Contract Amount:", TextAlignmentRight, timesBold, 8, projectColorOne))
|
||||||
|
|
||||||
contractAmountValue := table2.NewCell()
|
contractAmountValue := table2.NewCell()
|
||||||
contractAmountValue.SetContent(newContent("$2,975.00", TextAlignmentLeft, fonts.NewFontTimesRoman(), 8, ColorBlack))
|
contractAmountValue.SetContent(newContent("$2,975.00", TextAlignmentLeft, timesRoman, 8, ColorBlack))
|
||||||
|
|
||||||
clientID := table2.NewCell()
|
clientID := table2.NewCell()
|
||||||
clientID.SetContent(newContent("Client ID:", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, projectColorOne))
|
clientID.SetContent(newContent("Client ID:", TextAlignmentLeft, timesBold, 8, projectColorOne))
|
||||||
|
|
||||||
clientIDValue := table2.NewCell()
|
clientIDValue := table2.NewCell()
|
||||||
clientIDValue.SetContent(newContent("Baggi ehf", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, ColorBlack))
|
clientIDValue.SetContent(newContent("Baggi ehf", TextAlignmentLeft, timesBold, 8, ColorBlack))
|
||||||
|
|
||||||
table2.SkipCells(1)
|
table2.SkipCells(1)
|
||||||
|
|
||||||
retainerAmount := table2.NewCell()
|
retainerAmount := table2.NewCell()
|
||||||
retainerAmount.SetContent(newContent("Retainer Amount:", TextAlignmentRight, fonts.NewFontTimesBold(), 8, projectColorOne))
|
retainerAmount.SetContent(newContent("Retainer Amount:", TextAlignmentRight, timesBold, 8, projectColorOne))
|
||||||
|
|
||||||
retainerAmountValue := table2.NewCell()
|
retainerAmountValue := table2.NewCell()
|
||||||
retainerAmountValue.SetContent(newContent("", TextAlignmentLeft, fonts.NewFontTimesRoman(), 8, ColorBlack))
|
retainerAmountValue.SetContent(newContent("", TextAlignmentLeft, timesRoman, 8, ColorBlack))
|
||||||
|
|
||||||
table3 := NewTable(8)
|
table3 := NewTable(8)
|
||||||
table3.SetColumnWidths(0.05, 0.10, 0.35, 0.10, 0.10, 0.10, 0.10, 0.10)
|
table3.SetColumnWidths(0.05, 0.10, 0.35, 0.10, 0.10, 0.10, 0.10, 0.10)
|
||||||
table3.SkipCells(8)
|
table3.SkipCells(8)
|
||||||
|
|
||||||
billNo := table3.NewCell()
|
billNo := table3.NewCell()
|
||||||
billNo.SetContent(newContent("Bill #", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, projectColorOne))
|
billNo.SetContent(newContent("Bill #", TextAlignmentLeft, timesBold, 8, projectColorOne))
|
||||||
billNo.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
billNo.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
||||||
billNo.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
billNo.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
||||||
billNo.SetBorderColor(projectColorOne)
|
billNo.SetBorderColor(projectColorOne)
|
||||||
|
|
||||||
billDate := table3.NewCell()
|
billDate := table3.NewCell()
|
||||||
billDate.SetContent(newContent("Date", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, projectColorOne))
|
billDate.SetContent(newContent("Date", TextAlignmentLeft, timesBold, 8, projectColorOne))
|
||||||
billDate.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
billDate.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
||||||
billDate.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
billDate.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
||||||
billDate.SetBorderColor(projectColorOne)
|
billDate.SetBorderColor(projectColorOne)
|
||||||
|
|
||||||
billNotes := table3.NewCell()
|
billNotes := table3.NewCell()
|
||||||
billNotes.SetContent(newContent("Notes", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, projectColorOne))
|
billNotes.SetContent(newContent("Notes", TextAlignmentLeft, timesBold, 8, projectColorOne))
|
||||||
billNotes.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
billNotes.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
||||||
billNotes.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
billNotes.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
||||||
billNotes.SetBorderColor(projectColorOne)
|
billNotes.SetBorderColor(projectColorOne)
|
||||||
|
|
||||||
billAmount := table3.NewCell()
|
billAmount := table3.NewCell()
|
||||||
billAmount.SetContent(newContent("Bill Amount", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, projectColorOne))
|
billAmount.SetContent(newContent("Bill Amount", TextAlignmentLeft, timesBold, 8, projectColorOne))
|
||||||
billAmount.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
billAmount.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
||||||
billAmount.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
billAmount.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
||||||
billAmount.SetBorderColor(projectColorOne)
|
billAmount.SetBorderColor(projectColorOne)
|
||||||
|
|
||||||
billCon := table3.NewCell()
|
billCon := table3.NewCell()
|
||||||
billCon.SetContent(newContent("% Con", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, projectColorOne))
|
billCon.SetContent(newContent("% Con", TextAlignmentLeft, timesBold, 8, projectColorOne))
|
||||||
billCon.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
billCon.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
||||||
billCon.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
billCon.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
||||||
billCon.SetBorderColor(projectColorOne)
|
billCon.SetBorderColor(projectColorOne)
|
||||||
|
|
||||||
billRetApplied := table3.NewCell()
|
billRetApplied := table3.NewCell()
|
||||||
billRetApplied.SetContent(newContent("Ret Applied", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, projectColorOne))
|
billRetApplied.SetContent(newContent("Ret Applied", TextAlignmentLeft, timesBold, 8, projectColorOne))
|
||||||
billRetApplied.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
billRetApplied.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
||||||
billRetApplied.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
billRetApplied.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
||||||
billRetApplied.SetBorderColor(projectColorOne)
|
billRetApplied.SetBorderColor(projectColorOne)
|
||||||
|
|
||||||
billRet := table3.NewCell()
|
billRet := table3.NewCell()
|
||||||
billRet.SetContent(newContent("% Ret", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, projectColorOne))
|
billRet.SetContent(newContent("% Ret", TextAlignmentLeft, timesBold, 8, projectColorOne))
|
||||||
billRet.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
billRet.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
||||||
billRet.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
billRet.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
||||||
billRet.SetBorderColor(projectColorOne)
|
billRet.SetBorderColor(projectColorOne)
|
||||||
|
|
||||||
billNetBill := table3.NewCell()
|
billNetBill := table3.NewCell()
|
||||||
billNetBill.SetContent(newContent("Net Bill Amt", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, projectColorOne))
|
billNetBill.SetContent(newContent("Net Bill Amt", TextAlignmentLeft, timesBold, 8, projectColorOne))
|
||||||
billNetBill.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
billNetBill.SetBorder(CellBorderSideTop, CellBorderStyleSingle, 2)
|
||||||
billNetBill.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
billNetBill.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
||||||
billNetBill.SetBorderColor(projectColorOne)
|
billNetBill.SetBorderColor(projectColorOne)
|
||||||
@ -1427,24 +1429,24 @@ func TestCreatorHendricksReq1(t *testing.T) {
|
|||||||
table3.SkipCells(2 + 8)
|
table3.SkipCells(2 + 8)
|
||||||
|
|
||||||
totalBill := table3.NewCell()
|
totalBill := table3.NewCell()
|
||||||
totalBill.SetContent(newContent("Total: ", TextAlignmentRight, fonts.NewFontTimesBold(), 8, projectColorTwo))
|
totalBill.SetContent(newContent("Total: ", TextAlignmentRight, timesBold, 8, projectColorTwo))
|
||||||
|
|
||||||
totalBillAmount := table3.NewCell()
|
totalBillAmount := table3.NewCell()
|
||||||
totalBillAmount.SetContent(newContent("$3,272.50", TextAlignmentRight, fonts.NewFontTimesBold(), 8, projectColorTwo))
|
totalBillAmount.SetContent(newContent("$3,272.50", TextAlignmentRight, timesBold, 8, projectColorTwo))
|
||||||
totalBillAmount.SetBorder(CellBorderSideTop, CellBorderStyleDouble, 1)
|
totalBillAmount.SetBorder(CellBorderSideTop, CellBorderStyleDouble, 1)
|
||||||
totalBillAmount.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1, )
|
totalBillAmount.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
||||||
|
|
||||||
table3.SkipCells(1)
|
table3.SkipCells(1)
|
||||||
|
|
||||||
totalRetAmount := table3.NewCell()
|
totalRetAmount := table3.NewCell()
|
||||||
totalRetAmount.SetContent(newContent("$0.00", TextAlignmentRight, fonts.NewFontTimesBold(), 8, projectColorTwo))
|
totalRetAmount.SetContent(newContent("$0.00", TextAlignmentRight, timesBold, 8, projectColorTwo))
|
||||||
totalRetAmount.SetBorder(CellBorderSideTop, CellBorderStyleDouble, 1)
|
totalRetAmount.SetBorder(CellBorderSideTop, CellBorderStyleDouble, 1)
|
||||||
totalRetAmount.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
totalRetAmount.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
||||||
|
|
||||||
table3.SkipCells(1)
|
table3.SkipCells(1)
|
||||||
|
|
||||||
totalNetAmount := table3.NewCell()
|
totalNetAmount := table3.NewCell()
|
||||||
totalNetAmount.SetContent(newContent("$3,272.50", TextAlignmentRight, fonts.NewFontTimesBold(), 8, projectColorTwo))
|
totalNetAmount.SetContent(newContent("$3,272.50", TextAlignmentRight, timesBold, 8, projectColorTwo))
|
||||||
totalNetAmount.SetBorder(CellBorderSideTop, CellBorderStyleDouble, 1)
|
totalNetAmount.SetBorder(CellBorderSideTop, CellBorderStyleDouble, 1)
|
||||||
totalNetAmount.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
totalNetAmount.SetBorder(CellBorderSideBottom, CellBorderStyleSingle, 1)
|
||||||
totalNetAmount.SetBorderLineStyle(draw.LineStyleSolid)
|
totalNetAmount.SetBorderLineStyle(draw.LineStyleSolid)
|
||||||
@ -1462,11 +1464,12 @@ func TestCreatorHendricksReq1(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCreatorTableBorderReq1(t *testing.T) {
|
func TestCreatorTableBorderReq1(t *testing.T) {
|
||||||
|
timesRoman, _ := model.NewStandard14Font("Times-Roman")
|
||||||
table := NewTable(1) // Mx4 table
|
table := NewTable(1) // Mx4 table
|
||||||
table.SetColumnWidths(1)
|
table.SetColumnWidths(1)
|
||||||
|
|
||||||
fullLengthCell := table.NewCell()
|
fullLengthCell := table.NewCell()
|
||||||
fullLengthCell.SetContent(newContent("boxed, solid, default width", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
fullLengthCell.SetContent(newContent("boxed, solid, default width", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
fullLengthCell.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
fullLengthCell.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
|
|
||||||
table2 := NewTable(4) // Mx4 table
|
table2 := NewTable(4) // Mx4 table
|
||||||
@ -1475,43 +1478,43 @@ func TestCreatorTableBorderReq1(t *testing.T) {
|
|||||||
table2.SkipCells(4)
|
table2.SkipCells(4)
|
||||||
|
|
||||||
a := table2.NewCell()
|
a := table2.NewCell()
|
||||||
a.SetContent(newContent("A", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
a.SetContent(newContent("A", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
a.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
a.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
|
|
||||||
b := table2.NewCell()
|
b := table2.NewCell()
|
||||||
b.SetContent(newContent("B", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
b.SetContent(newContent("B", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
b.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
b.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
|
|
||||||
cc := table2.NewCell()
|
cc := table2.NewCell()
|
||||||
cc.SetContent(newContent("C", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
cc.SetContent(newContent("C", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
cc.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
cc.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
|
|
||||||
d := table2.NewCell()
|
d := table2.NewCell()
|
||||||
d.SetContent(newContent("D", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
d.SetContent(newContent("D", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
d.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
d.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
|
|
||||||
e := table2.NewCell()
|
e := table2.NewCell()
|
||||||
e.SetContent(newContent("E", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
e.SetContent(newContent("E", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
e.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
e.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
|
|
||||||
f := table2.NewCell()
|
f := table2.NewCell()
|
||||||
f.SetContent(newContent("F", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
f.SetContent(newContent("F", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
f.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
f.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
|
|
||||||
g := table2.NewCell()
|
g := table2.NewCell()
|
||||||
g.SetContent(newContent("G", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
g.SetContent(newContent("G", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
g.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
g.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
|
|
||||||
h := table2.NewCell()
|
h := table2.NewCell()
|
||||||
h.SetContent(newContent("H", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
h.SetContent(newContent("H", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
h.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
h.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
|
|
||||||
i := table2.NewCell()
|
i := table2.NewCell()
|
||||||
i.SetContent(newContent("I", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
i.SetContent(newContent("I", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
i.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
i.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
|
|
||||||
j := table2.NewCell()
|
j := table2.NewCell()
|
||||||
j.SetContent(newContent("J", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
j.SetContent(newContent("J", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
j.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
j.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
|
|
||||||
table3 := NewTable(1) // Mx4 table
|
table3 := NewTable(1) // Mx4 table
|
||||||
@ -1520,7 +1523,7 @@ func TestCreatorTableBorderReq1(t *testing.T) {
|
|||||||
table3.SkipCells(1)
|
table3.SkipCells(1)
|
||||||
|
|
||||||
dash := table3.NewCell()
|
dash := table3.NewCell()
|
||||||
dash.SetContent(newContent("boxed, dashed, default width", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
dash.SetContent(newContent("boxed, dashed, default width", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
dash.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
dash.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
dash.SetBorderLineStyle(draw.LineStyleDashed)
|
dash.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
@ -1530,71 +1533,71 @@ func TestCreatorTableBorderReq1(t *testing.T) {
|
|||||||
table4.SkipCells(4)
|
table4.SkipCells(4)
|
||||||
|
|
||||||
ad := table4.NewCell()
|
ad := table4.NewCell()
|
||||||
ad.SetContent(newContent("A", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
ad.SetContent(newContent("A", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
ad.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
ad.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
ad.SetBorderLineStyle(draw.LineStyleDashed)
|
ad.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
bd := table4.NewCell()
|
bd := table4.NewCell()
|
||||||
bd.SetContent(newContent("B", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
bd.SetContent(newContent("B", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
bd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
bd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
bd.SetBorderLineStyle(draw.LineStyleDashed)
|
bd.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
table4.SkipCells(2)
|
table4.SkipCells(2)
|
||||||
|
|
||||||
ccd := table4.NewCell()
|
ccd := table4.NewCell()
|
||||||
ccd.SetContent(newContent("C", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
ccd.SetContent(newContent("C", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
ccd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
ccd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
ccd.SetBorderLineStyle(draw.LineStyleDashed)
|
ccd.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
dd := table4.NewCell()
|
dd := table4.NewCell()
|
||||||
dd.SetContent(newContent("D", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
dd.SetContent(newContent("D", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
dd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
dd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
dd.SetBorderLineStyle(draw.LineStyleDashed)
|
dd.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
table4.SkipCells(2)
|
table4.SkipCells(2)
|
||||||
|
|
||||||
ed := table4.NewCell()
|
ed := table4.NewCell()
|
||||||
ed.SetContent(newContent("E", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
ed.SetContent(newContent("E", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
ed.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
ed.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
ed.SetBorderLineStyle(draw.LineStyleDashed)
|
ed.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
fd := table4.NewCell()
|
fd := table4.NewCell()
|
||||||
fd.SetContent(newContent("F", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
fd.SetContent(newContent("F", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
fd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
fd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
fd.SetBorderLineStyle(draw.LineStyleDashed)
|
fd.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
gd := table4.NewCell()
|
gd := table4.NewCell()
|
||||||
gd.SetContent(newContent("G", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
gd.SetContent(newContent("G", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
gd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
gd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
gd.SetBorderLineStyle(draw.LineStyleDashed)
|
gd.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
hd := table4.NewCell()
|
hd := table4.NewCell()
|
||||||
hd.SetContent(newContent("H", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
hd.SetContent(newContent("H", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
hd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
hd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
hd.SetBorderLineStyle(draw.LineStyleDashed)
|
hd.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
id := table4.NewCell()
|
id := table4.NewCell()
|
||||||
id.SetContent(newContent("I", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
id.SetContent(newContent("I", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
id.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
id.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
id.SetBorderLineStyle(draw.LineStyleDashed)
|
id.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
jd := table4.NewCell()
|
jd := table4.NewCell()
|
||||||
jd.SetContent(newContent("J", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
jd.SetContent(newContent("J", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
jd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
jd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
jd.SetBorderLineStyle(draw.LineStyleDashed)
|
jd.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
kd := table4.NewCell()
|
kd := table4.NewCell()
|
||||||
kd.SetContent(newContent("K", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
kd.SetContent(newContent("K", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
kd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
kd.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
kd.SetBorderLineStyle(draw.LineStyleDashed)
|
kd.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
ld := table4.NewCell()
|
ld := table4.NewCell()
|
||||||
ld.SetContent(newContent("L", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
ld.SetContent(newContent("L", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
ld.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
ld.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
ld.SetBorderLineStyle(draw.LineStyleDashed)
|
ld.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
md := table4.NewCell()
|
md := table4.NewCell()
|
||||||
md.SetContent(newContent("M", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
md.SetContent(newContent("M", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
md.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
md.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)
|
||||||
md.SetBorderLineStyle(draw.LineStyleDashed)
|
md.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
@ -1604,7 +1607,7 @@ func TestCreatorTableBorderReq1(t *testing.T) {
|
|||||||
table5.SkipCells(1)
|
table5.SkipCells(1)
|
||||||
|
|
||||||
doubled := table5.NewCell()
|
doubled := table5.NewCell()
|
||||||
doubled.SetContent(newContent("boxed, double, default width", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
doubled.SetContent(newContent("boxed, double, default width", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
doubled.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
doubled.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
||||||
|
|
||||||
table6 := NewTable(4) // Mx4 table
|
table6 := NewTable(4) // Mx4 table
|
||||||
@ -1613,43 +1616,43 @@ func TestCreatorTableBorderReq1(t *testing.T) {
|
|||||||
table6.SkipCells(4)
|
table6.SkipCells(4)
|
||||||
|
|
||||||
add := table6.NewCell()
|
add := table6.NewCell()
|
||||||
add.SetContent(newContent("A", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
add.SetContent(newContent("A", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
add.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
add.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
||||||
|
|
||||||
bdd := table6.NewCell()
|
bdd := table6.NewCell()
|
||||||
bdd.SetContent(newContent("B", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
bdd.SetContent(newContent("B", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
bdd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
bdd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
||||||
|
|
||||||
ccdd := table6.NewCell()
|
ccdd := table6.NewCell()
|
||||||
ccdd.SetContent(newContent("C", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
ccdd.SetContent(newContent("C", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
ccdd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
ccdd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
||||||
|
|
||||||
ddd := table6.NewCell()
|
ddd := table6.NewCell()
|
||||||
ddd.SetContent(newContent("D", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
ddd.SetContent(newContent("D", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
ddd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
ddd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
||||||
|
|
||||||
edd := table6.NewCell()
|
edd := table6.NewCell()
|
||||||
edd.SetContent(newContent("E", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
edd.SetContent(newContent("E", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
edd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
edd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
||||||
|
|
||||||
fdd := table6.NewCell()
|
fdd := table6.NewCell()
|
||||||
fdd.SetContent(newContent("F", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
fdd.SetContent(newContent("F", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
fdd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
fdd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
||||||
|
|
||||||
gdd := table6.NewCell()
|
gdd := table6.NewCell()
|
||||||
gdd.SetContent(newContent("G", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
gdd.SetContent(newContent("G", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
gdd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
gdd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
||||||
|
|
||||||
hdd := table6.NewCell()
|
hdd := table6.NewCell()
|
||||||
hdd.SetContent(newContent("H", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
hdd.SetContent(newContent("H", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
hdd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
hdd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
||||||
|
|
||||||
idd := table6.NewCell()
|
idd := table6.NewCell()
|
||||||
idd.SetContent(newContent("I", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
idd.SetContent(newContent("I", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
idd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
idd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
||||||
|
|
||||||
jdd := table6.NewCell()
|
jdd := table6.NewCell()
|
||||||
jdd.SetContent(newContent("J", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
jdd.SetContent(newContent("J", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
jdd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
jdd.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
||||||
|
|
||||||
table7 := NewTable(1) // Mx4 table
|
table7 := NewTable(1) // Mx4 table
|
||||||
@ -1658,7 +1661,7 @@ func TestCreatorTableBorderReq1(t *testing.T) {
|
|||||||
table7.SkipCells(1)
|
table7.SkipCells(1)
|
||||||
|
|
||||||
fullLengthCell7 := table7.NewCell()
|
fullLengthCell7 := table7.NewCell()
|
||||||
fullLengthCell7.SetContent(newContent("boxed, solid, thick", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
fullLengthCell7.SetContent(newContent("boxed, solid, thick", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
fullLengthCell7.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
fullLengthCell7.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
|
|
||||||
table8 := NewTable(4) // Mx4 table
|
table8 := NewTable(4) // Mx4 table
|
||||||
@ -1667,43 +1670,43 @@ func TestCreatorTableBorderReq1(t *testing.T) {
|
|||||||
table8.SkipCells(4)
|
table8.SkipCells(4)
|
||||||
|
|
||||||
a8 := table8.NewCell()
|
a8 := table8.NewCell()
|
||||||
a8.SetContent(newContent("A", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
a8.SetContent(newContent("A", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
a8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
a8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
|
|
||||||
b8 := table8.NewCell()
|
b8 := table8.NewCell()
|
||||||
b8.SetContent(newContent("B", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
b8.SetContent(newContent("B", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
b8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
b8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
|
|
||||||
cc8 := table8.NewCell()
|
cc8 := table8.NewCell()
|
||||||
cc8.SetContent(newContent("C", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
cc8.SetContent(newContent("C", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
cc8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
cc8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
|
|
||||||
d8 := table8.NewCell()
|
d8 := table8.NewCell()
|
||||||
d8.SetContent(newContent("D", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
d8.SetContent(newContent("D", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
d8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
d8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
|
|
||||||
e8 := table8.NewCell()
|
e8 := table8.NewCell()
|
||||||
e8.SetContent(newContent("E", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
e8.SetContent(newContent("E", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
e8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
e8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
|
|
||||||
f8 := table8.NewCell()
|
f8 := table8.NewCell()
|
||||||
f8.SetContent(newContent("F", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
f8.SetContent(newContent("F", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
f8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
f8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
|
|
||||||
g8 := table8.NewCell()
|
g8 := table8.NewCell()
|
||||||
g8.SetContent(newContent("G", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
g8.SetContent(newContent("G", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
g8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
g8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
|
|
||||||
h8 := table8.NewCell()
|
h8 := table8.NewCell()
|
||||||
h8.SetContent(newContent("H", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
h8.SetContent(newContent("H", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
h8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
h8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
|
|
||||||
i8 := table8.NewCell()
|
i8 := table8.NewCell()
|
||||||
i8.SetContent(newContent("I", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
i8.SetContent(newContent("I", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
i8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
i8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
|
|
||||||
j8 := table8.NewCell()
|
j8 := table8.NewCell()
|
||||||
j8.SetContent(newContent("J", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
j8.SetContent(newContent("J", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
j8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
j8.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
|
|
||||||
table9 := NewTable(1) // Mx4 table
|
table9 := NewTable(1) // Mx4 table
|
||||||
@ -1712,7 +1715,7 @@ func TestCreatorTableBorderReq1(t *testing.T) {
|
|||||||
table9.SkipCells(1)
|
table9.SkipCells(1)
|
||||||
|
|
||||||
fullLengthCell9 := table9.NewCell()
|
fullLengthCell9 := table9.NewCell()
|
||||||
fullLengthCell9.SetContent(newContent("boxed, dashed, thick", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
fullLengthCell9.SetContent(newContent("boxed, dashed, thick", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
fullLengthCell9.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
fullLengthCell9.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
fullLengthCell9.SetBorderLineStyle(draw.LineStyleDashed)
|
fullLengthCell9.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
@ -1722,52 +1725,52 @@ func TestCreatorTableBorderReq1(t *testing.T) {
|
|||||||
table10.SkipCells(4)
|
table10.SkipCells(4)
|
||||||
|
|
||||||
a10 := table10.NewCell()
|
a10 := table10.NewCell()
|
||||||
a10.SetContent(newContent("A", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
a10.SetContent(newContent("A", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
a10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
a10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
a10.SetBorderLineStyle(draw.LineStyleDashed)
|
a10.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
b10 := table10.NewCell()
|
b10 := table10.NewCell()
|
||||||
b10.SetContent(newContent("B", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
b10.SetContent(newContent("B", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
b10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
b10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
b10.SetBorderLineStyle(draw.LineStyleDashed)
|
b10.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
cc10 := table10.NewCell()
|
cc10 := table10.NewCell()
|
||||||
cc10.SetContent(newContent("C", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
cc10.SetContent(newContent("C", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
cc10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
cc10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
cc10.SetBorderLineStyle(draw.LineStyleDashed)
|
cc10.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
d10 := table10.NewCell()
|
d10 := table10.NewCell()
|
||||||
d10.SetContent(newContent("D", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
d10.SetContent(newContent("D", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
d10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
d10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
d10.SetBorderLineStyle(draw.LineStyleDashed)
|
d10.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
e10 := table10.NewCell()
|
e10 := table10.NewCell()
|
||||||
e10.SetContent(newContent("E", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
e10.SetContent(newContent("E", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
e10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
e10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
e10.SetBorderLineStyle(draw.LineStyleDashed)
|
e10.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
f10 := table10.NewCell()
|
f10 := table10.NewCell()
|
||||||
f10.SetContent(newContent("F", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
f10.SetContent(newContent("F", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
f10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
f10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
f10.SetBorderLineStyle(draw.LineStyleDashed)
|
f10.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
g10 := table10.NewCell()
|
g10 := table10.NewCell()
|
||||||
g10.SetContent(newContent("G", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
g10.SetContent(newContent("G", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
g10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
g10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
g10.SetBorderLineStyle(draw.LineStyleDashed)
|
g10.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
h10 := table10.NewCell()
|
h10 := table10.NewCell()
|
||||||
h10.SetContent(newContent("H", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
h10.SetContent(newContent("H", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
h10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
h10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
h10.SetBorderLineStyle(draw.LineStyleDashed)
|
h10.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
i10 := table10.NewCell()
|
i10 := table10.NewCell()
|
||||||
i10.SetContent(newContent("I", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
i10.SetContent(newContent("I", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
i10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
i10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
i10.SetBorderLineStyle(draw.LineStyleDashed)
|
i10.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
j10 := table10.NewCell()
|
j10 := table10.NewCell()
|
||||||
j10.SetContent(newContent("J", TextAlignmentLeft, fonts.NewFontTimesRoman(), 10, ColorBlack))
|
j10.SetContent(newContent("J", TextAlignmentLeft, timesRoman, 10, ColorBlack))
|
||||||
j10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
j10.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 2)
|
||||||
j10.SetBorderLineStyle(draw.LineStyleDashed)
|
j10.SetBorderLineStyle(draw.LineStyleDashed)
|
||||||
|
|
||||||
@ -1791,11 +1794,13 @@ func TestCreatorTableBorderReq1(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCellBorder(t *testing.T) {
|
func TestCellBorder(t *testing.T) {
|
||||||
|
timesBold, _ := model.NewStandard14Font("Times-Bold")
|
||||||
|
|
||||||
table := NewTable(2)
|
table := NewTable(2)
|
||||||
table.SetColumnWidths(0.50, 0.50)
|
table.SetColumnWidths(0.50, 0.50)
|
||||||
|
|
||||||
cell1 := table.NewCell()
|
cell1 := table.NewCell()
|
||||||
cell1.SetContent(newContent("Cell 1", TextAlignmentLeft, fonts.NewFontTimesBold(), 8, ColorRed))
|
cell1.SetContent(newContent("Cell 1", TextAlignmentLeft, timesBold, 8, ColorRed))
|
||||||
cell1.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
cell1.SetBorder(CellBorderSideAll, CellBorderStyleDouble, 1)
|
||||||
|
|
||||||
c := New()
|
c := New()
|
||||||
@ -1811,8 +1816,16 @@ func TestCellBorder(t *testing.T) {
|
|||||||
func TestTableInSubchapter(t *testing.T) {
|
func TestTableInSubchapter(t *testing.T) {
|
||||||
c := New()
|
c := New()
|
||||||
|
|
||||||
fontRegular := fonts.NewFontHelvetica()
|
fontRegular, err := model.NewStandard14Font("Helvetica")
|
||||||
fontBold := fonts.NewFontHelveticaBold()
|
if err != nil {
|
||||||
|
t.Errorf("Fail: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fontBold, err := model.NewStandard14Font("Helvetica-Bold")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Fail: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ch := c.NewChapter("Document control")
|
ch := c.NewChapter("Document control")
|
||||||
ch.SetMargins(0, 0, 40, 0)
|
ch.SetMargins(0, 0, 40, 0)
|
||||||
@ -1894,7 +1907,7 @@ func TestTableInSubchapter(t *testing.T) {
|
|||||||
myPara.SetLineHeight(1.5)
|
myPara.SetLineHeight(1.5)
|
||||||
sc.Add(myPara)
|
sc.Add(myPara)
|
||||||
|
|
||||||
err := c.Draw(ch)
|
err = c.Draw(ch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Fail: %v\n", err)
|
t.Errorf("Fail: %v\n", err)
|
||||||
return
|
return
|
||||||
|
@ -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
|
||||||
|
@ -13,18 +13,17 @@ import (
|
|||||||
"github.com/unidoc/unidoc/pdf/contentstream"
|
"github.com/unidoc/unidoc/pdf/contentstream"
|
||||||
"github.com/unidoc/unidoc/pdf/core"
|
"github.com/unidoc/unidoc/pdf/core"
|
||||||
"github.com/unidoc/unidoc/pdf/model"
|
"github.com/unidoc/unidoc/pdf/model"
|
||||||
"github.com/unidoc/unidoc/pdf/model/fonts"
|
|
||||||
"github.com/unidoc/unidoc/pdf/model/textencoding"
|
"github.com/unidoc/unidoc/pdf/model/textencoding"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Paragraph represents text drawn with a specified font and can wrap across lines and pages.
|
// Paragraph represents text drawn with a specified font and can wrap across lines and pages.
|
||||||
// By default occupies the available width in the drawing context.
|
// By default it occupies the available width in the drawing context.
|
||||||
type Paragraph struct {
|
type Paragraph struct {
|
||||||
// The input utf-8 text as a string (series of runes).
|
// The input utf-8 text as a string (series of runes).
|
||||||
text string
|
text string
|
||||||
|
|
||||||
// The font to be used to draw the text.
|
// The font to be used to draw the text.
|
||||||
textFont fonts.Font
|
textFont *model.PdfFont
|
||||||
|
|
||||||
// The font size (points).
|
// The font size (points).
|
||||||
fontSize float64
|
fontSize float64
|
||||||
@ -67,18 +66,26 @@ type Paragraph struct {
|
|||||||
textLines []string
|
textLines []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParagraph create a new text paragraph. Uses default parameters: Helvetica, WinAnsiEncoding and wrap enabled
|
// NewParagraph create a new text paragraph. Uses default parameters: Helvetica, WinAnsiEncoding and
|
||||||
// with a wrap width of 100 points.
|
// wrap enabled with a wrap width of 100 points.
|
||||||
func NewParagraph(text string) *Paragraph {
|
func NewParagraph(text string) *Paragraph {
|
||||||
p := &Paragraph{}
|
p := &Paragraph{}
|
||||||
p.text = text
|
p.text = text
|
||||||
p.textFont = fonts.NewFontHelvetica()
|
|
||||||
p.SetEncoder(textencoding.NewWinAnsiTextEncoder())
|
font, encoder, err := model.NewStandard14FontWithEncoding("Helvetica", model.GetAlphabet(text))
|
||||||
|
if err != nil {
|
||||||
|
common.Log.Debug("ERROR: NewStandard14FontWithEncoding failed err=%v. Falling back.", err)
|
||||||
|
p.textFont = model.DefaultFont()
|
||||||
|
}
|
||||||
|
p.textFont = font
|
||||||
|
p.SetEncoder(encoder)
|
||||||
|
|
||||||
p.fontSize = 10
|
p.fontSize = 10
|
||||||
p.lineHeight = 1.0
|
p.lineHeight = 1.0
|
||||||
|
|
||||||
// TODO: Can we wrap intellectually, only if given width is known?
|
// TODO: Can we wrap intellectually, only if given width is known?
|
||||||
p.enableWrap = true
|
|
||||||
|
p.enableWrap = false
|
||||||
p.defaultWrap = true
|
p.defaultWrap = true
|
||||||
p.SetColor(ColorRGBFrom8bit(0, 0, 0))
|
p.SetColor(ColorRGBFrom8bit(0, 0, 0))
|
||||||
p.alignment = TextAlignmentLeft
|
p.alignment = TextAlignmentLeft
|
||||||
@ -93,7 +100,7 @@ func NewParagraph(text string) *Paragraph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetFont sets the Paragraph's font.
|
// SetFont sets the Paragraph's font.
|
||||||
func (p *Paragraph) SetFont(font fonts.Font) {
|
func (p *Paragraph) SetFont(font *model.PdfFont) {
|
||||||
p.textFont = font
|
p.textFont = font
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +140,7 @@ func (p *Paragraph) SetEnableWrap(enableWrap bool) {
|
|||||||
p.defaultWrap = false
|
p.defaultWrap = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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")
|
||||||
@ -176,10 +183,11 @@ func (p *Paragraph) GetMargins() (float64, float64, float64, float64) {
|
|||||||
return p.margins.left, p.margins.right, p.margins.top, p.margins.bottom
|
return p.margins.left, p.margins.right, p.margins.top, p.margins.bottom
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetWidth sets the the Paragraph width. This is essentially the wrapping width, i.e. the width the text can extend to
|
// SetWidth sets the the Paragraph width. This is essentially the wrapping width, i.e. the width the
|
||||||
// prior to wrapping over to next line.
|
// text can extend to prior to wrapping over to next line.
|
||||||
func (p *Paragraph) SetWidth(width float64) {
|
func (p *Paragraph) SetWidth(width float64) {
|
||||||
p.wrapWidth = width
|
p.wrapWidth = width
|
||||||
|
p.enableWrap = true
|
||||||
p.wrapText()
|
p.wrapText()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,30 +195,28 @@ func (p *Paragraph) SetWidth(width float64) {
|
|||||||
func (p *Paragraph) Width() float64 {
|
func (p *Paragraph) Width() float64 {
|
||||||
if p.enableWrap {
|
if p.enableWrap {
|
||||||
return p.wrapWidth
|
return p.wrapWidth
|
||||||
} else {
|
|
||||||
return p.getTextWidth() / 1000.0
|
|
||||||
}
|
}
|
||||||
|
return p.getTextWidth() / 1000.0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Height returns the height of the Paragraph. The height is calculated based on the input text and how it is wrapped
|
// Height returns the height of the Paragraph. The height is calculated based on the input text and
|
||||||
// within the container. Does not include Margins.
|
// how it is wrapped within the container. Does not include Margins.
|
||||||
func (p *Paragraph) Height() float64 {
|
func (p *Paragraph) Height() float64 {
|
||||||
if p.textLines == nil || len(p.textLines) == 0 {
|
if p.textLines == nil || len(p.textLines) == 0 {
|
||||||
p.wrapText()
|
p.wrapText()
|
||||||
}
|
}
|
||||||
|
|
||||||
h := float64(len(p.textLines)) * p.lineHeight * p.fontSize
|
return float64(len(p.textLines)) * p.lineHeight * p.fontSize
|
||||||
return h
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the text width (if not wrapped).
|
// Calculate the text width (if not wrapped).
|
||||||
func (p *Paragraph) getTextWidth() float64 {
|
func (p *Paragraph) getTextWidth() float64 {
|
||||||
w := float64(0.0)
|
w := 0.0
|
||||||
|
|
||||||
for _, rune := range p.text {
|
for _, r := range p.text {
|
||||||
glyph, found := p.textFont.Encoder().RuneToGlyph(rune)
|
glyph, found := p.textFont.Encoder().RuneToGlyph(r)
|
||||||
if !found {
|
if !found {
|
||||||
common.Log.Debug("Error! Glyph not found for rune: %s\n", rune)
|
common.Log.Debug("ERROR: Glyph not found for rune: 0x%04x=%c", r, r)
|
||||||
return -1 // XXX/FIXME: return error.
|
return -1 // XXX/FIXME: return error.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +227,7 @@ func (p *Paragraph) getTextWidth() float64 {
|
|||||||
|
|
||||||
metrics, found := p.textFont.GetGlyphCharMetrics(glyph)
|
metrics, found := p.textFont.GetGlyphCharMetrics(glyph)
|
||||||
if !found {
|
if !found {
|
||||||
common.Log.Debug("Glyph char metrics not found! %s\n", glyph)
|
common.Log.Debug("ERROR: Glyph char metrics not found! %q (rune 0x%04x=%c)", glyph, r, r)
|
||||||
return -1 // XXX/FIXME: return error.
|
return -1 // XXX/FIXME: return error.
|
||||||
}
|
}
|
||||||
w += p.fontSize * metrics.Wx
|
w += p.fontSize * metrics.Wx
|
||||||
@ -234,12 +240,12 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
line := []rune{}
|
line := []rune{}
|
||||||
lineWidth := float64(0.0)
|
lineWidth := 0.0
|
||||||
p.textLines = []string{}
|
p.textLines = []string{}
|
||||||
|
|
||||||
runes := []rune(p.text)
|
runes := []rune(p.text)
|
||||||
@ -249,8 +255,8 @@ func (p *Paragraph) wrapText() error {
|
|||||||
for _, val := range runes {
|
for _, val := range runes {
|
||||||
glyph, found := p.textFont.Encoder().RuneToGlyph(val)
|
glyph, found := p.textFont.Encoder().RuneToGlyph(val)
|
||||||
if !found {
|
if !found {
|
||||||
common.Log.Debug("Error! Glyph not found for rune: %v\n", val)
|
common.Log.Debug("ERROR: Glyph not found for rune: %c", val)
|
||||||
return errors.New("Glyph not found for rune") // XXX/FIXME: return error.
|
return errors.New("Glyph not found for rune")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Newline wrapping.
|
// Newline wrapping.
|
||||||
@ -266,46 +272,40 @@ func (p *Paragraph) wrapText() error {
|
|||||||
|
|
||||||
metrics, found := p.textFont.GetGlyphCharMetrics(glyph)
|
metrics, found := p.textFont.GetGlyphCharMetrics(glyph)
|
||||||
if !found {
|
if !found {
|
||||||
common.Log.Debug("Glyph char metrics not found! %s (%s)\n", glyph, string(val))
|
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("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") // XXX/FIXME: return error.
|
return errors.New("Glyph char metrics missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
w := p.fontSize * metrics.Wx
|
w := p.fontSize * metrics.Wx
|
||||||
if lineWidth+w > p.wrapWidth*1000.0 {
|
if lineWidth+w > p.wrapWidth*1000.0 {
|
||||||
// Goes out of bounds: Wrap.
|
// Goes out of bounds: Wrap.
|
||||||
// Breaks on the character.
|
// Breaks on the character.
|
||||||
// XXX/TODO: when goes outside: back up to next space, otherwise break on the character.
|
|
||||||
idx := -1
|
idx := -1
|
||||||
for i := len(glyphs) - 1; i >= 0; i-- {
|
for i := len(glyphs) - 1; i >= 0; i-- {
|
||||||
if glyphs[i] == "space" {
|
if glyphs[i] == "space" { // XXX: What about other space glyphs like controlHT?
|
||||||
idx = i
|
idx = i
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if idx > 0 {
|
if idx > 0 {
|
||||||
|
// Back up to last space.
|
||||||
p.textLines = append(p.textLines, string(line[0:idx+1]))
|
p.textLines = append(p.textLines, string(line[0:idx+1]))
|
||||||
|
|
||||||
line = line[idx+1:]
|
// Remainder of line.
|
||||||
line = append(line, val)
|
line = append(line[idx+1:], val)
|
||||||
|
glyphs = append(glyphs[idx+1:], glyph)
|
||||||
glyphs = glyphs[idx+1:]
|
widths = append(widths[idx+1:], w)
|
||||||
glyphs = append(glyphs, glyph)
|
lineWidth = sum(widths)
|
||||||
widths = widths[idx+1:]
|
|
||||||
widths = append(widths, w)
|
|
||||||
|
|
||||||
lineWidth = 0
|
|
||||||
for _, width := range widths {
|
|
||||||
lineWidth += width
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
p.textLines = append(p.textLines, string(line))
|
p.textLines = append(p.textLines, string(line))
|
||||||
line = []rune{val}
|
line = []rune{val}
|
||||||
lineWidth = w
|
|
||||||
widths = []float64{w}
|
|
||||||
glyphs = []string{glyph}
|
glyphs = []string{glyph}
|
||||||
|
widths = []float64{w}
|
||||||
|
lineWidth = w
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
line = append(line, val)
|
line = append(line, val)
|
||||||
@ -321,15 +321,24 @@ func (p *Paragraph) wrapText() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GeneratePageBlocks generates the page blocks. Multiple blocks are generated if the contents wrap over
|
// sum returns the sums of the elements in `widths`.
|
||||||
// multiple pages. Implements the Drawable interface.
|
func sum(widths []float64) float64 {
|
||||||
|
total := 0.0
|
||||||
|
for _, w := range widths {
|
||||||
|
total += w
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeneratePageBlocks generates the page blocks. Multiple blocks are generated if the contents wrap
|
||||||
|
// over multiple pages. Implements the Drawable interface.
|
||||||
func (p *Paragraph) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
func (p *Paragraph) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||||
origContext := ctx
|
origContext := ctx
|
||||||
blocks := []*Block{}
|
blocks := []*Block{}
|
||||||
|
|
||||||
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
|
||||||
@ -339,8 +348,8 @@ func (p *Paragraph) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
|||||||
p.SetWidth(ctx.Width)
|
p.SetWidth(ctx.Width)
|
||||||
|
|
||||||
if p.Height() > ctx.Height {
|
if p.Height() > ctx.Height {
|
||||||
// Goes out of the bounds. Write on a new template instead and create a new context at upper
|
// Goes out of the bounds. Write on a new template instead and create a new context at
|
||||||
// left corner.
|
// upper left corner.
|
||||||
// XXX/TODO: Handle case when Paragraph is larger than the Page...
|
// XXX/TODO: Handle case when Paragraph is larger than the Page...
|
||||||
// Should be fine if we just break on the paragraph, i.e. splitting it up over 2+ pages
|
// Should be fine if we just break on the paragraph, i.e. splitting it up over 2+ pages
|
||||||
|
|
||||||
@ -384,7 +393,8 @@ func (p *Paragraph) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw block on specified location on Page, adding to the content stream.
|
// drawParagraphOnBlock draws Paragraph `p` on Block `blk` at the specified location on the page,
|
||||||
|
// adding it to the content stream.
|
||||||
func drawParagraphOnBlock(blk *Block, p *Paragraph, ctx DrawContext) (DrawContext, error) {
|
func drawParagraphOnBlock(blk *Block, p *Paragraph, ctx DrawContext) (DrawContext, error) {
|
||||||
// Find a free name for the font.
|
// Find a free name for the font.
|
||||||
num := 1
|
num := 1
|
||||||
@ -428,12 +438,12 @@ func drawParagraphOnBlock(blk *Block, p *Paragraph, ctx DrawContext) (DrawContex
|
|||||||
runes := []rune(line)
|
runes := []rune(line)
|
||||||
|
|
||||||
// Get width of the line (excluding spaces).
|
// Get width of the line (excluding spaces).
|
||||||
w := float64(0)
|
w := 0.0
|
||||||
spaces := 0
|
spaces := 0
|
||||||
for _, runeVal := range runes {
|
for i, r := range runes {
|
||||||
glyph, found := p.textFont.Encoder().RuneToGlyph(runeVal)
|
glyph, found := p.textFont.Encoder().RuneToGlyph(r)
|
||||||
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", r)
|
||||||
return ctx, errors.New("Unsupported rune in text encoding")
|
return ctx, errors.New("Unsupported rune in text encoding")
|
||||||
}
|
}
|
||||||
if glyph == "space" {
|
if glyph == "space" {
|
||||||
@ -445,7 +455,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\n", glyph)
|
common.Log.Debug("Unsupported glyph %q i=%d rune=0x%04x=%c in font %s %s",
|
||||||
|
glyph, i, r, r,
|
||||||
|
p.textFont.BaseFont(), p.textFont.Subtype())
|
||||||
return ctx, errors.New("Unsupported text glyph")
|
return ctx, errors.New("Unsupported text glyph")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,47 +471,51 @@ func drawParagraphOnBlock(blk *Block, p *Paragraph, ctx DrawContext) (DrawContex
|
|||||||
return ctx, errors.New("The font does not have a space glyph")
|
return ctx, errors.New("The font does not have a space glyph")
|
||||||
}
|
}
|
||||||
spaceWidth := spaceMetrics.Wx
|
spaceWidth := spaceMetrics.Wx
|
||||||
if p.alignment == TextAlignmentJustify {
|
switch p.alignment {
|
||||||
|
case TextAlignmentJustify:
|
||||||
if spaces > 0 && idx < len(p.textLines)-1 { // Not to justify last line.
|
if spaces > 0 && idx < len(p.textLines)-1 { // Not to justify last line.
|
||||||
spaceWidth = (p.wrapWidth*1000.0 - w) / float64(spaces) / p.fontSize
|
spaceWidth = (p.wrapWidth*1000.0 - w) / float64(spaces) / p.fontSize
|
||||||
}
|
}
|
||||||
} else if p.alignment == TextAlignmentCenter {
|
case TextAlignmentCenter:
|
||||||
// Start with a shift.
|
// Start with a shift.
|
||||||
textWidth := w + float64(spaces)*spaceWidth*p.fontSize
|
textWidth := w + float64(spaces)*spaceWidth*p.fontSize
|
||||||
shift := (p.wrapWidth*1000.0 - textWidth) / 2 / p.fontSize
|
shift := (p.wrapWidth*1000.0 - textWidth) / 2 / p.fontSize
|
||||||
objs = append(objs, core.MakeFloat(-shift))
|
objs = append(objs, core.MakeFloat(-shift))
|
||||||
} else if p.alignment == TextAlignmentRight {
|
case TextAlignmentRight:
|
||||||
textWidth := w + float64(spaces)*spaceWidth*p.fontSize
|
textWidth := w + float64(spaces)*spaceWidth*p.fontSize
|
||||||
shift := (p.wrapWidth*1000.0 - textWidth) / p.fontSize
|
shift := (p.wrapWidth*1000.0 - textWidth) / p.fontSize
|
||||||
objs = append(objs, core.MakeFloat(-shift))
|
objs = append(objs, core.MakeFloat(-shift))
|
||||||
}
|
}
|
||||||
|
|
||||||
encStr := ""
|
encoded := []byte{}
|
||||||
for _, runeVal := range runes {
|
isCID := p.textFont.IsCID()
|
||||||
//creator.Add_Tj(core.PdfObjectString(tb.Encoder.Encode(line)))
|
for _, r := range runes {
|
||||||
glyph, found := p.textFont.Encoder().RuneToGlyph(runeVal)
|
glyph, ok := p.textFont.Encoder().RuneToGlyph(r)
|
||||||
if !found {
|
if !ok {
|
||||||
common.Log.Debug("Rune 0x%x not supported by text encoder", runeVal)
|
common.Log.Debug("Rune 0x%x not supported by text encoder", r)
|
||||||
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 {
|
if len(encoded) > 0 {
|
||||||
common.Log.Debug("Unsupported glyph %s in font\n", glyph)
|
objs = append(objs, core.MakeStringFromBytes(encoded))
|
||||||
return ctx, errors.New("Unsupported text glyph")
|
encoded = []byte{}
|
||||||
}
|
|
||||||
|
|
||||||
if len(encStr) > 0 {
|
|
||||||
objs = append(objs, core.MakeString(encStr))
|
|
||||||
encStr = ""
|
|
||||||
}
|
}
|
||||||
objs = append(objs, core.MakeFloat(-spaceWidth))
|
objs = append(objs, core.MakeFloat(-spaceWidth))
|
||||||
} else {
|
} else {
|
||||||
encStr += string(p.textFont.Encoder().Encode(string(runeVal)))
|
code, ok := p.textFont.Encoder().RuneToCharcode(r)
|
||||||
|
if ok {
|
||||||
|
if isCID {
|
||||||
|
hi, lo := code>>8, code&0xff
|
||||||
|
encoded = append(encoded, byte(hi), byte(lo))
|
||||||
|
} else {
|
||||||
|
encoded = append(encoded, byte(code))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(encStr) > 0 {
|
if len(encoded) > 0 {
|
||||||
objs = append(objs, core.MakeString(encStr))
|
objs = append(objs, core.MakeStringFromBytes(encoded))
|
||||||
}
|
}
|
||||||
|
|
||||||
cc.Add_TJ(objs...)
|
cc.Add_TJ(objs...)
|
||||||
|
@ -9,11 +9,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/unidoc/unidoc/common"
|
"github.com/unidoc/unidoc/common"
|
||||||
"github.com/unidoc/unidoc/pdf/model/fonts"
|
"github.com/unidoc/unidoc/pdf/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Subchapter simply represents a sub chapter pertaining to a specific Chapter. It can contain multiple
|
// Subchapter simply represents a sub chapter pertaining to a specific Chapter. It can contain
|
||||||
// Drawables, just like a chapter.
|
// multiple Drawables, just like a chapter.
|
||||||
type Subchapter struct {
|
type Subchapter struct {
|
||||||
chapterNum int
|
chapterNum int
|
||||||
subchapterNum int
|
subchapterNum int
|
||||||
@ -56,7 +56,8 @@ func (c *Creator) NewSubchapter(ch *Chapter, title string) *Subchapter {
|
|||||||
p := NewParagraph(heading)
|
p := NewParagraph(heading)
|
||||||
|
|
||||||
p.SetFontSize(14)
|
p.SetFontSize(14)
|
||||||
p.SetFont(fonts.NewFontHelvetica()) // bold?
|
helvetica, _ := model.NewStandard14Font("Helvetica")
|
||||||
|
p.SetFont(helvetica) // bold?
|
||||||
|
|
||||||
subchap.showNumbering = true
|
subchap.showNumbering = true
|
||||||
subchap.includeInTOC = true
|
subchap.includeInTOC = true
|
||||||
@ -131,8 +132,8 @@ func (subchap *Subchapter) Add(d Drawable) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GeneratePageBlocks generates the page blocks. Multiple blocks are generated if the contents wrap over
|
// GeneratePageBlocks generates the page blocks. Multiple blocks are generated if the contents wrap
|
||||||
// multiple pages. Implements the Drawable interface.
|
// over multiple pages. Implements the Drawable interface.
|
||||||
func (subchap *Subchapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
func (subchap *Subchapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||||
origCtx := ctx
|
origCtx := ctx
|
||||||
|
|
||||||
@ -180,7 +181,6 @@ func (subchap *Subchapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawCo
|
|||||||
if subchap.positioning.isAbsolute() {
|
if subchap.positioning.isAbsolute() {
|
||||||
// If absolute: return original context.
|
// If absolute: return original context.
|
||||||
return blocks, origCtx, nil
|
return blocks, origCtx, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return blocks, ctx, nil
|
return blocks, ctx, nil
|
||||||
|
@ -9,8 +9,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/unidoc/unidoc/common"
|
"github.com/unidoc/unidoc/common"
|
||||||
"github.com/unidoc/unidoc/pdf/model"
|
|
||||||
"github.com/unidoc/unidoc/pdf/contentstream/draw"
|
"github.com/unidoc/unidoc/pdf/contentstream/draw"
|
||||||
|
"github.com/unidoc/unidoc/pdf/core"
|
||||||
|
"github.com/unidoc/unidoc/pdf/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Table allows organizing content in an rows X columns matrix, which can spawn across multiple pages.
|
// Table allows organizing content in an rows X columns matrix, which can spawn across multiple pages.
|
||||||
@ -131,7 +132,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) {
|
||||||
@ -140,7 +142,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{}
|
||||||
@ -265,6 +268,7 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
|||||||
r := cell.backgroundColor.R()
|
r := cell.backgroundColor.R()
|
||||||
g := cell.backgroundColor.G()
|
g := cell.backgroundColor.G()
|
||||||
b := cell.backgroundColor.B()
|
b := cell.backgroundColor.B()
|
||||||
|
|
||||||
border.SetFillColor(ColorRGBFromArithmetic(r, g, b))
|
border.SetFillColor(ColorRGBFromArithmetic(r, g, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,7 +299,7 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
|||||||
|
|
||||||
err := block.Draw(border)
|
err := block.Draw(border)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("Error: %v\n", err)
|
common.Log.Debug("ERROR: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cell.content != nil {
|
if cell.content != nil {
|
||||||
@ -340,7 +344,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +384,7 @@ type CellBorderSide int
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// Left side border.
|
// Left side border.
|
||||||
CellBorderSideLeft CellBorderSide = iota
|
CellBorderSideLeft CellBorderSide = iota
|
||||||
CellBorderSideRight
|
CellBorderSideRight
|
||||||
CellBorderSideTop
|
CellBorderSideTop
|
||||||
CellBorderSideBottom
|
CellBorderSideBottom
|
||||||
@ -635,8 +639,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
|
||||||
|
@ -8,6 +8,7 @@ package model
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/unidoc/unidoc/common"
|
"github.com/unidoc/unidoc/common"
|
||||||
@ -50,6 +51,11 @@ func (font PdfFont) Subtype() string {
|
|||||||
return subtype
|
return subtype
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsCID returns true if the underlying font is CID.
|
||||||
|
func (font PdfFont) IsCID() bool {
|
||||||
|
return font.baseFields().isCIDFont()
|
||||||
|
}
|
||||||
|
|
||||||
// ToUnicode returns the name of the font's "ToUnicode" field if there is one, or "" if there isn't.
|
// ToUnicode returns the name of the font's "ToUnicode" field if there is one, or "" if there isn't.
|
||||||
func (font PdfFont) ToUnicode() string {
|
func (font PdfFont) ToUnicode() string {
|
||||||
if font.baseFields().toUnicodeCmap == nil {
|
if font.baseFields().toUnicodeCmap == nil {
|
||||||
@ -58,6 +64,12 @@ func (font PdfFont) ToUnicode() string {
|
|||||||
return font.baseFields().toUnicodeCmap.Name()
|
return font.baseFields().toUnicodeCmap.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultFont returns the default font, which is currently the built in Helvetica.
|
||||||
|
func DefaultFont() *PdfFont {
|
||||||
|
std := standard14Fonts["Helvetica"]
|
||||||
|
return &PdfFont{context: &std}
|
||||||
|
}
|
||||||
|
|
||||||
// NewStandard14Font returns the standard 14 font named `basefont` as a *PdfFont, or an error if it
|
// NewStandard14Font returns the standard 14 font named `basefont` as a *PdfFont, or an error if it
|
||||||
// `basefont` is not one the standard 14 font names.
|
// `basefont` is not one the standard 14 font names.
|
||||||
func NewStandard14Font(basefont string) (*PdfFont, error) {
|
func NewStandard14Font(basefont string) (*PdfFont, error) {
|
||||||
@ -68,6 +80,104 @@ func NewStandard14Font(basefont string) (*PdfFont, error) {
|
|||||||
return &PdfFont{context: &std}, nil
|
return &PdfFont{context: &std}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewStandard14FontWithEncoding returns the standard 14 font named `basefont` as a *PdfFont and an
|
||||||
|
// a SimpleEncoder that encodes all the runes in `alphabet`, or an error if this is not possible.
|
||||||
|
// An error can occur if`basefont` is not one the standard 14 font names.
|
||||||
|
func NewStandard14FontWithEncoding(basefont string, alphabet map[rune]int) (*PdfFont, *textencoding.SimpleEncoder, error) {
|
||||||
|
baseEncoder := "MacRomanEncoding"
|
||||||
|
common.Log.Trace("NewStandard14FontWithEncoding: basefont=%#q baseEncoder=%#q alphabet=%q",
|
||||||
|
basefont, baseEncoder, string(sortedAlphabet(alphabet)))
|
||||||
|
|
||||||
|
std, ok := standard14Fonts[basefont]
|
||||||
|
if !ok {
|
||||||
|
return nil, nil, ErrFontNotSupported
|
||||||
|
}
|
||||||
|
encoder, err := textencoding.NewSimpleTextEncoder(baseEncoder, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// glyphCode are the encoding glyphs. We need to match them to the font glyphs.
|
||||||
|
glyphCode := map[string]byte{}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
// Don't overwrite space
|
||||||
|
if glyph != "space" {
|
||||||
|
|
||||||
|
slots1 = append(slots1, byte(code))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
slots = append(slots, byte(code))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slots = append(slots, slots1...)
|
||||||
|
|
||||||
|
// `glyphs` are the font glyphs that we need to encode.
|
||||||
|
glyphs := []string{}
|
||||||
|
for _, r := range sortedAlphabet(alphabet) {
|
||||||
|
glyph, ok := textencoding.RuneToGlyph(r)
|
||||||
|
if !ok {
|
||||||
|
common.Log.Debug("No glyph for rune 0x%02x=%c", r, r)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok = std.fontMetrics[glyph]; !ok {
|
||||||
|
common.Log.Trace("Glyph %q (0x%04x=%c)not in font", glyph, r, r)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(glyphs) >= 255 {
|
||||||
|
common.Log.Debug("Too many characters for encoding")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
glyphs = append(glyphs, glyph)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the slots, starting with the empty ones.
|
||||||
|
slotIdx := 0
|
||||||
|
differences := map[byte]string{}
|
||||||
|
for _, glyph := range glyphs {
|
||||||
|
if _, ok := glyphCode[glyph]; !ok {
|
||||||
|
differences[slots[slotIdx]] = glyph
|
||||||
|
slotIdx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
encoder, err = textencoding.NewSimpleTextEncoder(baseEncoder, differences)
|
||||||
|
|
||||||
|
return &PdfFont{context: &std}, encoder, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAlphabet returns a map of the runes in `text`.
|
||||||
|
func GetAlphabet(text string) map[rune]int {
|
||||||
|
alphabet := map[rune]int{}
|
||||||
|
for _, r := range text {
|
||||||
|
alphabet[r]++
|
||||||
|
}
|
||||||
|
return alphabet
|
||||||
|
}
|
||||||
|
|
||||||
|
// sortedAlphabet the runes in `alphabet` sorted by frequency.
|
||||||
|
func sortedAlphabet(alphabet map[rune]int) []rune {
|
||||||
|
runes := []rune{}
|
||||||
|
for r := range alphabet {
|
||||||
|
runes = append(runes, r)
|
||||||
|
}
|
||||||
|
sort.Slice(runes, func(i, j int) bool {
|
||||||
|
ri, rj := runes[i], runes[j]
|
||||||
|
ni, nj := alphabet[ri], alphabet[rj]
|
||||||
|
if ni != nj {
|
||||||
|
return ni < nj
|
||||||
|
}
|
||||||
|
return ri < rj
|
||||||
|
})
|
||||||
|
return runes
|
||||||
|
}
|
||||||
|
|
||||||
// NewPdfFontFromPdfObject loads a PdfFont from the dictionary `fontObj`. If there is a problem an
|
// NewPdfFontFromPdfObject loads a PdfFont from the dictionary `fontObj`. If there is a problem an
|
||||||
// error is returned.
|
// error is returned.
|
||||||
func NewPdfFontFromPdfObject(fontObj core.PdfObject) (*PdfFont, error) {
|
func NewPdfFontFromPdfObject(fontObj core.PdfObject) (*PdfFont, error) {
|
||||||
@ -301,18 +411,18 @@ func (font PdfFont) baseFields() *fontCommon {
|
|||||||
|
|
||||||
// fontCommon represents the fields that are common to all PDF fonts.
|
// fontCommon represents the fields that are common to all PDF fonts.
|
||||||
type fontCommon struct {
|
type fontCommon struct {
|
||||||
// All fonts have these fields
|
// All fonts have these fields.
|
||||||
basefont string // The font's "BaseFont" field.
|
basefont string // The font's "BaseFont" field.
|
||||||
subtype string // The font's "Subtype" field.
|
subtype string // The font's "Subtype" field.
|
||||||
|
|
||||||
// These are optional fields in the PDF font
|
// These are optional fields in the PDF font
|
||||||
toUnicode core.PdfObject // The stream containing toUnicodeCmap. We keep it around for ToPdfObject.
|
toUnicode core.PdfObject // The stream containing toUnicodeCmap. We keep it around for ToPdfObject.
|
||||||
|
|
||||||
// These objects are computed from optional fields in the PDF font
|
// These objects are computed from optional fields in the PDF font.
|
||||||
toUnicodeCmap *cmap.CMap // Computed from "ToUnicode"
|
toUnicodeCmap *cmap.CMap // Computed from "ToUnicode"
|
||||||
fontDescriptor *PdfFontDescriptor // Computed from "FontDescriptor"
|
fontDescriptor *PdfFontDescriptor // Computed from "FontDescriptor"
|
||||||
|
|
||||||
// objectNumber helps us find the font in the PDF being processed. This helps with debugging
|
// objectNumber helps us find the font in the PDF being processed. This helps with debugging.
|
||||||
objectNumber int64
|
objectNumber int64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,6 +458,7 @@ func (base fontCommon) String() string {
|
|||||||
return fmt.Sprintf("FONT{%s}", base.coreString())
|
return fmt.Sprintf("FONT{%s}", base.coreString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// coreString returns the contents of fontCommon.String() without the FONT{} wrapper.
|
||||||
func (base fontCommon) coreString() string {
|
func (base fontCommon) coreString() string {
|
||||||
descriptor := ""
|
descriptor := ""
|
||||||
if base.fontDescriptor != nil {
|
if base.fontDescriptor != nil {
|
||||||
|
@ -140,9 +140,12 @@ func (font *pdfFontType0) ToPdfObject() core.PdfObject {
|
|||||||
|
|
||||||
font.container.PdfObject = d
|
font.container.PdfObject = d
|
||||||
|
|
||||||
if font.encoder != nil {
|
if font.Encoding != nil {
|
||||||
|
d.Set("Encoding", font.Encoding)
|
||||||
|
} else if font.encoder != nil {
|
||||||
d.Set("Encoding", font.encoder.ToPdfObject())
|
d.Set("Encoding", font.encoder.ToPdfObject())
|
||||||
}
|
}
|
||||||
|
|
||||||
if font.DescendantFont != nil {
|
if font.DescendantFont != nil {
|
||||||
// Shall be 1 element array.
|
// Shall be 1 element array.
|
||||||
d.Set("DescendantFonts", core.MakeArray(font.DescendantFont.ToPdfObject()))
|
d.Set("DescendantFonts", core.MakeArray(font.DescendantFont.ToPdfObject()))
|
||||||
@ -194,8 +197,7 @@ type pdfCIDFontType0 struct {
|
|||||||
encoder textencoding.TextEncoder
|
encoder textencoding.TextEncoder
|
||||||
|
|
||||||
// Table 117 – Entries in a CIDFont dictionary (page 269)
|
// Table 117 – Entries in a CIDFont dictionary (page 269)
|
||||||
CIDSystemInfo *core.PdfObjectDictionary // (Required) Dictionary that defines the character collection of the CIDFont. See Table 116.
|
CIDSystemInfo *core.PdfObjectDictionary // (Required) Dictionary that defines the character collection of the CIDFont. See Table 116.
|
||||||
FontDescriptor core.PdfObject // (Required) Describes the CIDFont’s default metrics other than its glyph widths
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pdfCIDFontType0FromSkeleton returns a pdfCIDFontType0 with its common fields initalized.
|
// pdfCIDFontType0FromSkeleton returns a pdfCIDFontType0 with its common fields initalized.
|
||||||
@ -305,15 +307,19 @@ func (font pdfCIDFontType2) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics
|
|||||||
enc := textencoding.NewTrueTypeFontEncoder(font.ttfParser.Chars)
|
enc := textencoding.NewTrueTypeFontEncoder(font.ttfParser.Chars)
|
||||||
|
|
||||||
// Convert the glyph to character code.
|
// Convert the glyph to character code.
|
||||||
rune, found := enc.GlyphToRune(glyph)
|
r, found := enc.GlyphToRune(glyph)
|
||||||
if !found {
|
if !found {
|
||||||
common.Log.Debug("Unable to convert glyph %q to charcode (identity)", glyph)
|
common.Log.Debug("Unable to convert glyph %q to charcode (identity)", glyph)
|
||||||
return metrics, false
|
return metrics, false
|
||||||
}
|
}
|
||||||
|
|
||||||
w, found := font.runeToWidthMap[uint16(rune)]
|
w, found := font.runeToWidthMap[uint16(r)]
|
||||||
if !found {
|
if !found {
|
||||||
return metrics, false
|
dw, ok := core.GetInt(font.DW)
|
||||||
|
if !ok {
|
||||||
|
return metrics, false
|
||||||
|
}
|
||||||
|
w = int(*dw)
|
||||||
}
|
}
|
||||||
metrics.GlyphName = glyph
|
metrics.GlyphName = glyph
|
||||||
metrics.Wx = float64(w)
|
metrics.Wx = float64(w)
|
||||||
@ -432,8 +438,8 @@ func NewCompositePdfFontFromTTFFile(filePath string) (*PdfFont, error) {
|
|||||||
|
|
||||||
// Construct W array. Stores character code to width mappings.
|
// Construct W array. Stores character code to width mappings.
|
||||||
wArr := &core.PdfObjectArray{}
|
wArr := &core.PdfObjectArray{}
|
||||||
i := uint16(0)
|
|
||||||
for int(i) < len(runes) {
|
for i := uint16(0); int(i) < len(runes); {
|
||||||
|
|
||||||
j := i + 1
|
j := i + 1
|
||||||
for int(j) < len(runes) {
|
for int(j) < len(runes) {
|
||||||
@ -505,12 +511,14 @@ func NewCompositePdfFontFromTTFFile(filePath string) (*PdfFont, error) {
|
|||||||
}
|
}
|
||||||
descriptor.Flags = core.MakeInteger(int64(flags))
|
descriptor.Flags = core.MakeInteger(int64(flags))
|
||||||
|
|
||||||
|
cidfont.basefont = ttf.PostScriptName
|
||||||
|
cidfont.fontDescriptor = descriptor
|
||||||
|
|
||||||
// Make root Type0 font.
|
// Make root Type0 font.
|
||||||
type0 := pdfFontType0{
|
type0 := pdfFontType0{
|
||||||
fontCommon: fontCommon{
|
fontCommon: fontCommon{
|
||||||
subtype: "Type0",
|
subtype: "Type0",
|
||||||
basefont: ttf.PostScriptName,
|
basefont: ttf.PostScriptName,
|
||||||
fontDescriptor: descriptor,
|
|
||||||
},
|
},
|
||||||
DescendantFont: &PdfFont{
|
DescendantFont: &PdfFont{
|
||||||
context: cidfont,
|
context: cidfont,
|
||||||
|
@ -180,11 +180,12 @@ func newSimpleFontFromPdfObject(d *core.PdfObjectDictionary, base *fontCommon, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// addEncoding adds the encoding to the font.
|
// addEncoding adds the encoding to the font.
|
||||||
// The order of precedence is important
|
// The order of precedence is important.
|
||||||
func (font *pdfFontSimple) addEncoding() error {
|
func (font *pdfFontSimple) addEncoding() error {
|
||||||
var baseEncoder string
|
var baseEncoder string
|
||||||
var differences map[byte]string
|
var differences map[byte]string
|
||||||
var err error
|
var err error
|
||||||
|
var encoder *textencoding.SimpleEncoder
|
||||||
|
|
||||||
if font.Encoding != nil {
|
if font.Encoding != nil {
|
||||||
baseEncoder, differences, err = getFontEncoding(font.Encoding)
|
baseEncoder, differences, err = getFontEncoding(font.Encoding)
|
||||||
@ -197,42 +198,42 @@ func (font *pdfFontSimple) addEncoding() error {
|
|||||||
common.Log.Trace("addEncoding: BaseFont=%q Subtype=%q Encoding=%s (%T)", base.basefont,
|
common.Log.Trace("addEncoding: BaseFont=%q Subtype=%q Encoding=%s (%T)", base.basefont,
|
||||||
base.subtype, font.Encoding, font.Encoding)
|
base.subtype, font.Encoding, font.Encoding)
|
||||||
|
|
||||||
encoder, err := textencoding.NewSimpleTextEncoder(baseEncoder, differences)
|
encoder, err = textencoding.NewSimpleTextEncoder(baseEncoder, differences)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
font.SetEncoder(encoder)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if font.Encoder() == nil {
|
if encoder == nil {
|
||||||
descriptor := font.fontDescriptor
|
descriptor := font.fontDescriptor
|
||||||
if descriptor != nil {
|
if descriptor != nil {
|
||||||
switch font.subtype {
|
switch font.subtype {
|
||||||
case "Type1":
|
case "Type1":
|
||||||
if descriptor.fontFile != nil && descriptor.fontFile.encoder != nil {
|
if descriptor.fontFile != nil && descriptor.fontFile.encoder != nil {
|
||||||
common.Log.Debug("Using fontFile")
|
common.Log.Debug("Using fontFile")
|
||||||
font.SetEncoder(descriptor.fontFile.encoder)
|
encoder = descriptor.fontFile.encoder
|
||||||
}
|
}
|
||||||
case "TrueType":
|
case "TrueType":
|
||||||
if descriptor.fontFile2 != nil {
|
if descriptor.fontFile2 != nil {
|
||||||
common.Log.Debug("Using FontFile2")
|
common.Log.Debug("Using FontFile2")
|
||||||
encoder, err := descriptor.fontFile2.MakeEncoder()
|
enc, err := descriptor.fontFile2.MakeEncoder()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
font.SetEncoder(encoder)
|
encoder = enc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// At the end, apply the differences.
|
if encoder != nil {
|
||||||
if differences != nil {
|
// At the end, apply the differences.
|
||||||
common.Log.Trace("differences=%+v font=%s", differences, font.baseFields())
|
if differences != nil {
|
||||||
if se, ok := font.Encoder().(textencoding.SimpleEncoder); ok {
|
common.Log.Trace("differences=%+v font=%s", differences, font.baseFields())
|
||||||
se.ApplyDifferences(differences)
|
encoder.ApplyDifferences(differences)
|
||||||
font.SetEncoder(se)
|
|
||||||
}
|
}
|
||||||
|
font.SetEncoder(encoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/unidoc/unidoc/pdf/core"
|
"github.com/unidoc/unidoc/pdf/core"
|
||||||
"github.com/unidoc/unidoc/pdf/model"
|
"github.com/unidoc/unidoc/pdf/model"
|
||||||
"github.com/unidoc/unidoc/pdf/model/fonts"
|
"github.com/unidoc/unidoc/pdf/model/fonts"
|
||||||
|
"github.com/unidoc/unidoc/pdf/model/textencoding"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -184,7 +185,7 @@ var charcodeBytesToUnicodeTest = []fontFragmentTest{
|
|||||||
185, 186, 187, 188, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204,
|
185, 186, 187, 188, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204,
|
||||||
205, 206, 207, 208, 209, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225,
|
205, 206, 207, 208, 209, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225,
|
||||||
229, 241, 242, 243, 245},
|
229, 241, 242, 243, 245},
|
||||||
" !∀#∃%&∋()∗+,−./0123456789:;<=>?≅ΑΒΧΔΕΦΓΗΙϑΚΛΜΝΟΠΘΡΣΤΥςΩΞΨΖ[∴]⊥_αβχδεφγηιϕκλμνοπθρστυϖω" +
|
" !∀#∃%&∋()∗+,−./0123456789:;<=>?≅ΑΒΧ∆ΕΦΓΗΙϑΚΛΜΝΟΠΘΡΣΤΥςΩΞΨΖ[∴]⊥_αβχδεφγηιϕκλµνοπθρστυϖω" +
|
||||||
"ξψζ{|}∼€ϒ′≤⁄∞ƒ♣♦♥♠↔←↑→↓°±″≥×∝∂•÷≠≡≈…↵ℵℑℜ℘⊗⊕∅∩∪⊃⊇⊄⊂⊆∈∉∠∇∏√⋅¬∧∨⇔⇐⇑⇒⇓◊〈∑〉∫⌠⌡",
|
"ξψζ{|}∼€ϒ′≤⁄∞ƒ♣♦♥♠↔←↑→↓°±″≥×∝∂•÷≠≡≈…↵ℵℑℜ℘⊗⊕∅∩∪⊃⊇⊄⊂⊆∈∉∠∇∏√⋅¬∧∨⇔⇐⇑⇒⇓◊〈∑〉∫⌠⌡",
|
||||||
},
|
},
|
||||||
fontFragmentTest{"ZapfDingbats built-in",
|
fontFragmentTest{"ZapfDingbats built-in",
|
||||||
@ -252,6 +253,70 @@ var charcodeBytesToUnicodeTest = []fontFragmentTest{
|
|||||||
177, 151, 178, 179, 183, 185, 188, 205, 184, 189},
|
177, 151, 178, 179, 183, 185, 188, 205, 184, 189},
|
||||||
"‘ł’ “Ł” Ø `o´ it's ˝ˆ˜¯˘˙¨˚ˇªº‹ı›—–—†‡•„…˛¸‰",
|
"‘ł’ “Ł” Ø `o´ it's ˝ˆ˜¯˘˙¨˚ˇªº‹ı›—–—†‡•„…˛¸‰",
|
||||||
},
|
},
|
||||||
|
fontFragmentTest{"base glyphs′",
|
||||||
|
"./testdata/font/cover.txt", 11,
|
||||||
|
[]byte{44, 45, 46, 48, 49, 50, 51, 53, 54, 55, 56, 58, 59,
|
||||||
|
65, 66, 67, 68, 69, 70, 71, 72,
|
||||||
|
84, 85,
|
||||||
|
97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111,
|
||||||
|
114, 115, 116, 117},
|
||||||
|
",-.01235678:;ABCDEFGHTUabcdefghijlmnorstu",
|
||||||
|
},
|
||||||
|
fontFragmentTest{"tex glyphs 48->′",
|
||||||
|
"./testdata/font/noise-contrast.txt", 36,
|
||||||
|
[]byte{33, 48, 65, 104, 149, 253},
|
||||||
|
"!′Ah•ý",
|
||||||
|
},
|
||||||
|
fontFragmentTest{"tex2 glyphs ",
|
||||||
|
"./testdata/font/Weil.txt", 30,
|
||||||
|
[]byte{55, 0, 1, 2, 20, 24, 33, 50, 102, 103, 104, 105},
|
||||||
|
"↦−·×≤∼→∈{}⟨⟩",
|
||||||
|
},
|
||||||
|
fontFragmentTest{"additional glyphs",
|
||||||
|
"./testdata/font/noise-contrast.txt", 34,
|
||||||
|
[]byte{32, 40, 48, 64, 80, 88, 65, 104, 149, 253},
|
||||||
|
"({∑∑h•ý",
|
||||||
|
},
|
||||||
|
fontFragmentTest{".notdef glyphs",
|
||||||
|
"./testdata/font/lec10.txt", 6,
|
||||||
|
[]byte{59, 66},
|
||||||
|
string([]rune{textencoding.MissingCodeRune, textencoding.MissingCodeRune}),
|
||||||
|
},
|
||||||
|
fontFragmentTest{"Numbered glyphs pattern 1",
|
||||||
|
"./testdata/font/v14.txt", 14,
|
||||||
|
[]byte{24, 25, 26, 27, 29},
|
||||||
|
" ffifflfffi",
|
||||||
|
},
|
||||||
|
fontFragmentTest{"Glyph aliases",
|
||||||
|
"./testdata/font/townes.txt", 10,
|
||||||
|
[]byte{2, 3, 4, 5, 6, 7, 1, 8, 9, 5, 1, 10, 9, 5, 48},
|
||||||
|
"Townes van Zan…",
|
||||||
|
},
|
||||||
|
fontFragmentTest{"Glyph `.` extensions. e.g. `integral.disp`",
|
||||||
|
"./testdata/font/preview.txt", 156,
|
||||||
|
[]byte{83, 0, 4, 67, 62, 64, 100, 65},
|
||||||
|
"∫=≈≥∈<d>",
|
||||||
|
},
|
||||||
|
fontFragmentTest{"A potpourri of glyph naming conventions",
|
||||||
|
"./testdata/font/Ingmar.txt", 144,
|
||||||
|
[]byte{18, 20, 10, 11, 13, 14, 15, 16, 21, 22, 23, 25, 26, 27, 28, 29, 30,
|
||||||
|
31, 33, 12, 17, 19, 24},
|
||||||
|
"ʼ8ČŽĆřćĐĭűőftffiflfffičž!fbfkffl\u00a0",
|
||||||
|
},
|
||||||
|
fontFragmentTest{"Zapf Dingbats",
|
||||||
|
"./testdata/font/estimation.txt", 122,
|
||||||
|
[]byte{2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14},
|
||||||
|
"✏✮✁☛❄❍❥❇◆✟✙",
|
||||||
|
},
|
||||||
|
fontFragmentTest{"Found these by trial and error",
|
||||||
|
"./testdata/font/helminths.txt", 19,
|
||||||
|
[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||||
|
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||||
|
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
|
||||||
|
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
|
||||||
|
75, 76, 77},
|
||||||
|
" *ﺏﻁﻝﺍﺔﻴﻠﻜ،ﺕﺭﺘﻌﻤﺎﺠﻲﻨﻘﺩﻬ/ﻙﻭﻕﺃﻡﻋﻓﺴ٢٠٣ﻯﻥﺒﺸﺌﺱﻷ,ﺯﺤﺄﻀـﺓﺫ.)٤(٩ل٥٧٨ﻸﻰ%١ﺇ٦ﺡﻫﻱﻅﻐﺼﻑﺨﺀﻊLM",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type fontFragmentTest struct {
|
type fontFragmentTest struct {
|
||||||
@ -294,6 +359,18 @@ func (f *fontFragmentTest) check(t *testing.T) {
|
|||||||
if actualText != f.expected {
|
if actualText != f.expected {
|
||||||
t.Errorf("Incorrect decoding. %s\nexpected=%q\n actual=%q",
|
t.Errorf("Incorrect decoding. %s\nexpected=%q\n actual=%q",
|
||||||
f, f.expected, actualText)
|
f, f.expected, actualText)
|
||||||
|
act, exp := []rune(actualText), []rune(f.expected)
|
||||||
|
if len(act) != len(exp) {
|
||||||
|
t.Errorf("\texpected=%d actual=%d", len(exp), len(act))
|
||||||
|
} else {
|
||||||
|
for i, a := range act {
|
||||||
|
e := exp[i]
|
||||||
|
if a != e {
|
||||||
|
t.Errorf("\ti=%d expected=0x%04x=%c actual=0x%04x=%c", i, e, e, a, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if numChars != len([]rune(actualText)) {
|
if numChars != len([]rune(actualText)) {
|
||||||
t.Errorf("Incorrect numChars. %s numChars=%d expected=%d\n%+v\n%c",
|
t.Errorf("Incorrect numChars. %s numChars=%d expected=%d\n%+v\n%c",
|
||||||
|
@ -33,7 +33,7 @@ import (
|
|||||||
type fontFile struct {
|
type fontFile struct {
|
||||||
name string
|
name string
|
||||||
subtype string
|
subtype string
|
||||||
encoder textencoding.TextEncoder
|
encoder *textencoding.SimpleEncoder
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a human readable description of `fontfile`.
|
// String returns a human readable description of `fontfile`.
|
||||||
|
@ -44,7 +44,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// MakeEncoder returns an encoder built from the tables in `rec`.
|
// MakeEncoder returns an encoder built from the tables in `rec`.
|
||||||
func (rec *TtfType) MakeEncoder() (textencoding.SimpleEncoder, error) {
|
func (rec *TtfType) MakeEncoder() (*textencoding.SimpleEncoder, error) {
|
||||||
encoding := map[uint16]string{}
|
encoding := map[uint16]string{}
|
||||||
for code := uint16(0); code <= 256; code++ {
|
for code := uint16(0); code <= 256; code++ {
|
||||||
gid, ok := rec.Chars[code]
|
gid, ok := rec.Chars[code]
|
||||||
@ -151,7 +151,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
|
||||||
@ -379,7 +380,7 @@ func (t *ttfParser) parseCmapSubtable10(offset10 int64) error {
|
|||||||
length = t.ReadULong()
|
length = t.ReadULong()
|
||||||
language = t.ReadULong()
|
language = t.ReadULong()
|
||||||
}
|
}
|
||||||
common.Log.Debug("parseCmapSubtable10: format=%d length=%d language=%d",
|
common.Log.Trace("parseCmapSubtable10: format=%d length=%d language=%d",
|
||||||
format, length, language)
|
format, length, language)
|
||||||
|
|
||||||
if format != 0 {
|
if format != 0 {
|
||||||
@ -407,7 +408,7 @@ func (t *ttfParser) ParseCmap() error {
|
|||||||
if err := t.Seek("cmap"); err != nil {
|
if err := t.Seek("cmap"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
common.Log.Debug("ParseCmap")
|
common.Log.Trace("ParseCmap")
|
||||||
t.ReadUShort() // version is ignored.
|
t.ReadUShort() // version is ignored.
|
||||||
numTables := int(t.ReadUShort())
|
numTables := int(t.ReadUShort())
|
||||||
offset10 := int64(0)
|
offset10 := int64(0)
|
||||||
@ -465,6 +466,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.
|
||||||
@ -501,6 +504,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
|
||||||
|
BIN
pdf/model/testdata/font/Ingmar.txt
vendored
Executable file
BIN
pdf/model/testdata/font/Ingmar.txt
vendored
Executable file
Binary file not shown.
BIN
pdf/model/testdata/font/Weil.txt
vendored
Executable file
BIN
pdf/model/testdata/font/Weil.txt
vendored
Executable file
Binary file not shown.
BIN
pdf/model/testdata/font/cover.txt
vendored
Executable file
BIN
pdf/model/testdata/font/cover.txt
vendored
Executable file
Binary file not shown.
BIN
pdf/model/testdata/font/estimation.txt
vendored
Executable file
BIN
pdf/model/testdata/font/estimation.txt
vendored
Executable file
Binary file not shown.
BIN
pdf/model/testdata/font/helminths.txt
vendored
Executable file
BIN
pdf/model/testdata/font/helminths.txt
vendored
Executable file
Binary file not shown.
BIN
pdf/model/testdata/font/lec10.txt
vendored
Executable file
BIN
pdf/model/testdata/font/lec10.txt
vendored
Executable file
Binary file not shown.
BIN
pdf/model/testdata/font/noise-contrast.txt
vendored
Executable file
BIN
pdf/model/testdata/font/noise-contrast.txt
vendored
Executable file
Binary file not shown.
BIN
pdf/model/testdata/font/preview.txt
vendored
Executable file
BIN
pdf/model/testdata/font/preview.txt
vendored
Executable file
Binary file not shown.
BIN
pdf/model/testdata/font/townes.txt
vendored
Executable file
BIN
pdf/model/testdata/font/townes.txt
vendored
Executable file
Binary file not shown.
BIN
pdf/model/testdata/font/v14.txt
vendored
Executable file
BIN
pdf/model/testdata/font/v14.txt
vendored
Executable file
Binary file not shown.
@ -16,7 +16,7 @@ type TextEncoder interface {
|
|||||||
String() string
|
String() string
|
||||||
|
|
||||||
// Encode converts the Go unicode string `raw` to a PDF encoded string.
|
// Encode converts the Go unicode string `raw` to a PDF encoded string.
|
||||||
Encode(raw string) string
|
Encode(raw string) []byte
|
||||||
|
|
||||||
// CharcodeToGlyph returns the glyph name for character code `code`.
|
// CharcodeToGlyph returns the glyph name for character code `code`.
|
||||||
// The bool return flag is true if there was a match, and false otherwise.
|
// The bool return flag is true if there was a match, and false otherwise.
|
||||||
@ -51,17 +51,17 @@ type TextEncoder interface {
|
|||||||
// Convenience functions
|
// Convenience functions
|
||||||
|
|
||||||
// doEncode converts a Go unicode string `raw` to a PDF encoded string using the encoder `enc`.
|
// doEncode converts a Go unicode string `raw` to a PDF encoded string using the encoder `enc`.
|
||||||
func doEncode(enc TextEncoder, raw string) string {
|
func doEncode(enc TextEncoder, raw string) []byte {
|
||||||
encoded := []byte{}
|
encoded := []byte{}
|
||||||
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))
|
||||||
}
|
}
|
||||||
return string(encoded)
|
return encoded
|
||||||
}
|
}
|
||||||
|
|
||||||
// doRuneToCharcode converts rune `r` to a PDF character code.
|
// doRuneToCharcode converts rune `r` to a PDF character code.
|
||||||
|
4648
pdf/model/textencoding/glyphlist/Unicode.txt
Normal file
4648
pdf/model/textencoding/glyphlist/Unicode.txt
Normal file
File diff suppressed because it is too large
Load Diff
146
pdf/model/textencoding/glyphlist/additional.txt
Normal file
146
pdf/model/textencoding/glyphlist/additional.txt
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
#
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
# contributor license agreements. See the NOTICE file distributed with
|
||||||
|
# this work for additional information regarding copyright ownership.
|
||||||
|
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
# (the "License"); you may not use this file except in compliance with
|
||||||
|
# the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
# Format: Semicolon-delimited fields:
|
||||||
|
# (1) glyph name
|
||||||
|
# (2) Unicode scalar value
|
||||||
|
#
|
||||||
|
# These mappings are missing in glyphlist.txt
|
||||||
|
#
|
||||||
|
angbracketleft;3008
|
||||||
|
angbracketright;3009
|
||||||
|
circlecopyrt;00A9
|
||||||
|
controlNULL;0000
|
||||||
|
#
|
||||||
|
# TeX-related mappings using named values
|
||||||
|
#
|
||||||
|
angbracketleftbig;2329
|
||||||
|
angbracketleftBig;2329
|
||||||
|
angbracketleftbigg;2329
|
||||||
|
angbracketleftBigg;2329
|
||||||
|
angbracketrightBig;232A
|
||||||
|
angbracketrightbig;232A
|
||||||
|
angbracketrightBigg;232A
|
||||||
|
angbracketrightbigg;232A
|
||||||
|
arrowhookleft;21AA
|
||||||
|
arrowhookright;21A9
|
||||||
|
arrowlefttophalf;21BC
|
||||||
|
arrowleftbothalf;21BD
|
||||||
|
arrownortheast;2197
|
||||||
|
arrownorthwest;2196
|
||||||
|
arrowrighttophalf;21C0
|
||||||
|
arrowrightbothalf;21C1
|
||||||
|
arrowsoutheast;2198
|
||||||
|
arrowsouthwest;2199
|
||||||
|
backslashbig;2216
|
||||||
|
backslashBig;2216
|
||||||
|
backslashBigg;2216
|
||||||
|
backslashbigg;2216
|
||||||
|
bardbl;2016
|
||||||
|
bracehtipdownleft;FE37
|
||||||
|
bracehtipdownright;FE37
|
||||||
|
bracehtipupleft;FE38
|
||||||
|
bracehtipupright;FE38
|
||||||
|
braceleftBig;007B
|
||||||
|
braceleftbig;007B
|
||||||
|
braceleftbigg;007B
|
||||||
|
braceleftBigg;007B
|
||||||
|
bracerightBig;007D
|
||||||
|
bracerightbig;007D
|
||||||
|
bracerightbigg;007D
|
||||||
|
bracerightBigg;007D
|
||||||
|
bracketleftbig;005B
|
||||||
|
bracketleftBig;005B
|
||||||
|
bracketleftbigg;005B
|
||||||
|
bracketleftBigg;005B
|
||||||
|
bracketrightBig;005D
|
||||||
|
bracketrightbig;005D
|
||||||
|
bracketrightbigg;005D
|
||||||
|
bracketrightBigg;005D
|
||||||
|
ceilingleftbig;2308
|
||||||
|
ceilingleftBig;2308
|
||||||
|
ceilingleftBigg;2308
|
||||||
|
ceilingleftbigg;2308
|
||||||
|
ceilingrightbig;2309
|
||||||
|
ceilingrightBig;2309
|
||||||
|
ceilingrightbigg;2309
|
||||||
|
ceilingrightBigg;2309
|
||||||
|
circledotdisplay;2299
|
||||||
|
circledottext;2299
|
||||||
|
circlemultiplydisplay;2297
|
||||||
|
circlemultiplytext;2297
|
||||||
|
circleplusdisplay;2295
|
||||||
|
circleplustext;2295
|
||||||
|
contintegraldisplay;222E
|
||||||
|
contintegraltext;222E
|
||||||
|
coproductdisplay;2210
|
||||||
|
coproducttext;2210
|
||||||
|
floorleftBig;230A
|
||||||
|
floorleftbig;230A
|
||||||
|
floorleftbigg;230A
|
||||||
|
floorleftBigg;230A
|
||||||
|
floorrightbig;230B
|
||||||
|
floorrightBig;230B
|
||||||
|
floorrightBigg;230B
|
||||||
|
floorrightbigg;230B
|
||||||
|
hatwide;0302
|
||||||
|
hatwider;0302
|
||||||
|
hatwidest;0302
|
||||||
|
intercal;1D40
|
||||||
|
integraldisplay;222B
|
||||||
|
integraltext;222B
|
||||||
|
intersectiondisplay;22C2
|
||||||
|
intersectiontext;22C2
|
||||||
|
logicalanddisplay;2227
|
||||||
|
logicalandtext;2227
|
||||||
|
logicalordisplay;2228
|
||||||
|
logicalortext;2228
|
||||||
|
parenleftBig;0028
|
||||||
|
parenleftbig;0028
|
||||||
|
parenleftBigg;0028
|
||||||
|
parenleftbigg;0028
|
||||||
|
parenrightBig;0029
|
||||||
|
parenrightbig;0029
|
||||||
|
parenrightBigg;0029
|
||||||
|
parenrightbigg;0029
|
||||||
|
prime;2032
|
||||||
|
productdisplay;220F
|
||||||
|
producttext;220F
|
||||||
|
radicalbig;221A
|
||||||
|
radicalBig;221A
|
||||||
|
radicalBigg;221A
|
||||||
|
radicalbigg;221A
|
||||||
|
radicalbt;221A
|
||||||
|
radicaltp;221A
|
||||||
|
radicalvertex;221A
|
||||||
|
slashbig;002F
|
||||||
|
slashBig;002F
|
||||||
|
slashBigg;002F
|
||||||
|
slashbigg;002F
|
||||||
|
summationdisplay;2211
|
||||||
|
summationtext;2211
|
||||||
|
tildewide;02DC
|
||||||
|
tildewider;02DC
|
||||||
|
tildewidest;02DC
|
||||||
|
uniondisplay;22C3
|
||||||
|
unionmultidisplay;228E
|
||||||
|
unionmultitext;228E
|
||||||
|
unionsqdisplay;2294
|
||||||
|
unionsqtext;2294
|
||||||
|
uniontext;22C3
|
||||||
|
vextenddouble;2225
|
||||||
|
vextendsingle;2223
|
||||||
|
#END
|
2864
pdf/model/textencoding/glyphlist/unimathsymbols.txt
Normal file
2864
pdf/model/textencoding/glyphlist/unimathsymbols.txt
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,7 @@ func (enc IdentityEncoder) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Encode converts the Go unicode string `raw` to a PDF encoded string.
|
// Encode converts the Go unicode string `raw` to a PDF encoded string.
|
||||||
func (enc IdentityEncoder) Encode(raw string) string {
|
func (enc IdentityEncoder) Encode(raw string) []byte {
|
||||||
// runes -> character codes -> bytes
|
// runes -> character codes -> bytes
|
||||||
var encoded bytes.Buffer
|
var encoded bytes.Buffer
|
||||||
for _, r := range raw {
|
for _, r := range raw {
|
||||||
@ -44,7 +44,7 @@ func (enc IdentityEncoder) Encode(raw string) string {
|
|||||||
encoded.WriteByte(byte((code & 0xff00) >> 8))
|
encoded.WriteByte(byte((code & 0xff00) >> 8))
|
||||||
encoded.WriteByte(byte(code & 0xff))
|
encoded.WriteByte(byte(code & 0xff))
|
||||||
}
|
}
|
||||||
return encoded.String()
|
return encoded.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CharcodeToGlyph returns the glyph name matching character code `code`.
|
// CharcodeToGlyph returns the glyph name matching character code `code`.
|
||||||
|
File diff suppressed because it is too large
Load Diff
68
pdf/model/textencoding/simple_test.go
Normal file
68
pdf/model/textencoding/simple_test.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* This file is subject to the terms and conditions defined in
|
||||||
|
* file 'LICENSE.md', which is part of this source code package.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package textencoding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/unidoc/unidoc/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This test covers all the standard encodings in simple.go
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.SetLogger(common.NewConsoleLogger(common.LogLevelDebug))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestBasicEncodings checks for known glyph->rune mappings in the standard encodings.
|
||||||
|
func TestBasicEncodings(t *testing.T) {
|
||||||
|
for _, test := range testCases {
|
||||||
|
test.check(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"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
type encodingTest struct {
|
||||||
|
encoding string
|
||||||
|
runes string
|
||||||
|
glyphs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *encodingTest) String() string {
|
||||||
|
return fmt.Sprintf("ENCODING_TEST{%#q}", f.encoding)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *encodingTest) check(t *testing.T) {
|
||||||
|
common.Log.Debug("encodingTest: %s", f)
|
||||||
|
runes := []rune(f.runes)
|
||||||
|
if len(runes) != len(f.glyphs) {
|
||||||
|
t.Fatalf("Bad test %s runes=%d glyphs=%d", f, len(runes), len(f.glyphs))
|
||||||
|
}
|
||||||
|
enc, err := NewSimpleTextEncoder(f.encoding, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewSimpleTextEncoder(%#q) failed. err=%v", f.encoding, err)
|
||||||
|
}
|
||||||
|
for i, glyph := range f.glyphs {
|
||||||
|
expected := runes[i]
|
||||||
|
r, ok := enc.GlyphToRune(glyph)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Encoding %#q has no glyph %q", f.encoding, glyph)
|
||||||
|
}
|
||||||
|
if r != expected {
|
||||||
|
t.Fatalf("%s: Expected 0x%04x=%c. Got 0x%04x=%c", f, r, r, expected, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,5 +8,5 @@ package textencoding
|
|||||||
// NewSymbolEncoder returns a SimpleEncoder that implements SymbolEncoding.
|
// NewSymbolEncoder returns a SimpleEncoder that implements SymbolEncoding.
|
||||||
func NewSymbolEncoder() SimpleEncoder {
|
func NewSymbolEncoder() SimpleEncoder {
|
||||||
enc, _ := NewSimpleTextEncoder("SymbolEncoding", nil)
|
enc, _ := NewSimpleTextEncoder("SymbolEncoding", nil)
|
||||||
return enc
|
return *enc
|
||||||
}
|
}
|
||||||
|
1126
pdf/model/textencoding/testdata/glyphlist/parse_all_glyphs.go
vendored
Normal file
1126
pdf/model/textencoding/testdata/glyphlist/parse_all_glyphs.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -63,7 +63,7 @@ func (enc TrueTypeFontEncoder) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Encode converts the Go unicode string `raw` to a PDF encoded string.
|
// Encode converts the Go unicode string `raw` to a PDF encoded string.
|
||||||
func (enc TrueTypeFontEncoder) Encode(raw string) string {
|
func (enc TrueTypeFontEncoder) Encode(raw string) []byte {
|
||||||
// runes -> character codes -> bytes
|
// runes -> character codes -> bytes
|
||||||
var encoded bytes.Buffer
|
var encoded bytes.Buffer
|
||||||
for _, r := range raw {
|
for _, r := range raw {
|
||||||
@ -77,7 +77,7 @@ func (enc TrueTypeFontEncoder) Encode(raw string) string {
|
|||||||
encoded.WriteByte(byte((code & 0xff00) >> 8))
|
encoded.WriteByte(byte((code & 0xff00) >> 8))
|
||||||
encoded.WriteByte(byte(code & 0xff))
|
encoded.WriteByte(byte(code & 0xff))
|
||||||
}
|
}
|
||||||
return encoded.String()
|
return encoded.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CharcodeToGlyph returns the glyph name matching character code `code`.
|
// CharcodeToGlyph returns the glyph name matching character code `code`.
|
||||||
|
@ -8,5 +8,5 @@ package textencoding
|
|||||||
// NewWinAnsiTextEncoder returns a SimpleEncoder that implements WinAnsiEncoding.
|
// NewWinAnsiTextEncoder returns a SimpleEncoder that implements WinAnsiEncoding.
|
||||||
func NewWinAnsiTextEncoder() SimpleEncoder {
|
func NewWinAnsiTextEncoder() SimpleEncoder {
|
||||||
enc, _ := NewSimpleTextEncoder("WinAnsiEncoding", nil)
|
enc, _ := NewSimpleTextEncoder("WinAnsiEncoding", nil)
|
||||||
return enc
|
return *enc
|
||||||
}
|
}
|
||||||
|
@ -8,5 +8,5 @@ package textencoding
|
|||||||
// NewZapfDingbatsEncoder returns a SimpleEncoder that implements ZapfDingbatsEncoding.
|
// NewZapfDingbatsEncoder returns a SimpleEncoder that implements ZapfDingbatsEncoding.
|
||||||
func NewZapfDingbatsEncoder() SimpleEncoder {
|
func NewZapfDingbatsEncoder() SimpleEncoder {
|
||||||
enc, _ := NewSimpleTextEncoder("ZapfDingbatsEncoding", nil)
|
enc, _ := NewSimpleTextEncoder("ZapfDingbatsEncoding", nil)
|
||||||
return enc
|
return *enc
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user