1 Star 0 Fork 0

coodder / unipdf

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
chapters.go 6.37 KB
一键复制 编辑 原始数据 按行查看 历史
jhonm 提交于 2023-08-07 15:31 . init
package creator
import (
"errors"
"fmt"
"strconv"
"gitee.com/coodder/unipdf/common"
"gitee.com/coodder/unipdf/model"
)
// Chapter is used to arrange multiple drawables (paragraphs, images, etc) into a single section.
// The concept is the same as a book or a report chapter.
type Chapter struct {
// The number of the chapter.
number int
// The title of the chapter.
title string
// The heading paragraph of the chapter.
heading *Paragraph
// The content components of the chapter.
contents []Drawable
// The number of subchapters the chapter has.
subchapters int
// Show chapter numbering
showNumbering bool
// Include in TOC.
includeInTOC bool
// Positioning: relative / absolute.
positioning positioning
// Absolute coordinates (when in absolute mode).
xPos, yPos float64
// Margins to be applied around the block when drawing on Page.
margins margins
// Reference to the parent chapter the current chapter belongs to.
parent *Chapter
// Reference to the TOC of the creator.
toc *TOC
// Reference to the outline of the creator.
outline *model.Outline
// The item of the chapter in the outline.
outlineItem *model.OutlineItem
// The level of the chapter in the chapters hierarchy.
level uint
}
// newChapter creates a new chapter with the specified title as the heading.
func newChapter(parent *Chapter, toc *TOC, outline *model.Outline, title string, number int, style TextStyle) *Chapter {
var level uint = 1
if parent != nil {
level = parent.level + 1
}
chapter := &Chapter{
number: number,
title: title,
showNumbering: true,
includeInTOC: true,
parent: parent,
toc: toc,
outline: outline,
contents: []Drawable{},
level: level,
}
p := newParagraph(chapter.headingText(), style)
p.SetFont(style.Font)
p.SetFontSize(style.FontSize)
chapter.heading = p
return chapter
}
// NewSubchapter creates a new child chapter with the specified title.
func (chap *Chapter) NewSubchapter(title string) *Chapter {
style := newTextStyle(chap.heading.textFont)
style.FontSize = 14
chap.subchapters++
subchapter := newChapter(chap, chap.toc, chap.outline, title, chap.subchapters, style)
chap.Add(subchapter)
return subchapter
}
// SetShowNumbering sets a flag to indicate whether or not to show chapter numbers as part of title.
func (chap *Chapter) SetShowNumbering(show bool) {
chap.showNumbering = show
chap.heading.SetText(chap.headingText())
}
// SetIncludeInTOC sets a flag to indicate whether or not to include in tOC.
func (chap *Chapter) SetIncludeInTOC(includeInTOC bool) {
chap.includeInTOC = includeInTOC
}
// GetHeading returns the chapter heading paragraph. Used to give access to address style: font, sizing etc.
func (chap *Chapter) GetHeading() *Paragraph {
return chap.heading
}
// SetMargins sets the Chapter margins: left, right, top, bottom.
// Typically not needed as the creator's page margins are used.
func (chap *Chapter) SetMargins(left, right, top, bottom float64) {
chap.margins.left = left
chap.margins.right = right
chap.margins.top = top
chap.margins.bottom = bottom
}
// GetMargins returns the Chapter's margin: left, right, top, bottom.
func (chap *Chapter) GetMargins() (float64, float64, float64, float64) {
return chap.margins.left, chap.margins.right, chap.margins.top, chap.margins.bottom
}
// Add adds a new Drawable to the chapter.
func (chap *Chapter) Add(d Drawable) error {
if Drawable(chap) == d {
common.Log.Debug("ERROR: Cannot add itself")
return errors.New("range check error")
}
switch d.(type) {
case *Paragraph, *StyledParagraph, *Image, *Block, *Table, *PageBreak, *Chapter, *HTMLContent:
chap.contents = append(chap.contents, d)
default:
common.Log.Debug("Unsupported: %T", d)
return errors.New("type check error")
}
return nil
}
// headingNumber returns the chapter heading number based on the chapter
// hierarchy and the showNumbering property.
func (chap *Chapter) headingNumber() string {
var chapNumber string
if chap.showNumbering {
if chap.number != 0 {
chapNumber = strconv.Itoa(chap.number) + "."
}
if chap.parent != nil {
parentChapNumber := chap.parent.headingNumber()
if parentChapNumber != "" {
chapNumber = parentChapNumber + chapNumber
}
}
}
return chapNumber
}
// headingText returns the chapter heading text content.
func (chap *Chapter) headingText() string {
heading := chap.title
if chapNumber := chap.headingNumber(); chapNumber != "" {
heading = fmt.Sprintf("%s %s", chapNumber, heading)
}
return heading
}
// GeneratePageBlocks generate the Page blocks. Multiple blocks are generated if the contents wrap
// over multiple pages.
func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
origCtx := ctx
if chap.positioning.isRelative() {
// Update context.
ctx.X += chap.margins.left
ctx.Y += chap.margins.top
ctx.Width -= chap.margins.left + chap.margins.right
ctx.Height -= chap.margins.top
}
blocks, c, err := chap.heading.GeneratePageBlocks(ctx)
if err != nil {
return blocks, ctx, err
}
ctx = c
// Generate chapter title and number.
posX := ctx.X
posY := ctx.Y - chap.heading.Height()
page := int64(ctx.Page)
chapNumber := chap.headingNumber()
chapTitle := chap.headingText()
// Add to TOC.
if chap.includeInTOC {
line := chap.toc.Add(chapNumber, chap.title, strconv.FormatInt(page, 10), chap.level)
if chap.toc.showLinks {
line.SetLink(page, posX, posY)
}
}
// Add to outline.
if chap.outlineItem == nil {
chap.outlineItem = model.NewOutlineItem(
chapTitle,
model.NewOutlineDest(page-1, posX, posY),
)
if chap.parent != nil {
chap.parent.outlineItem.Add(chap.outlineItem)
} else {
chap.outline.Add(chap.outlineItem)
}
} else {
outlineDest := &chap.outlineItem.Dest
outlineDest.Page = page - 1
outlineDest.X = posX
outlineDest.Y = posY
}
for _, d := range chap.contents {
newBlocks, c, err := d.GeneratePageBlocks(ctx)
if err != nil {
return blocks, ctx, err
}
if len(newBlocks) < 1 {
continue
}
// The first block is always appended to the last..
blocks[len(blocks)-1].mergeBlocks(newBlocks[0])
blocks = append(blocks, newBlocks[1:]...)
ctx = c
}
if chap.positioning.isRelative() {
// Move back X to same start of line.
ctx.X = origCtx.X
}
if chap.positioning.isAbsolute() {
// If absolute: return original context.
return blocks, origCtx, nil
}
return blocks, ctx, nil
}
Go
1
https://gitee.com/coodder/unipdf.git
git@gitee.com:coodder/unipdf.git
coodder
unipdf
unipdf
v1.2.0

搜索帮助