1 Star 0 Fork 0

coodder / unipdf

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
division.go 4.68 KB
一键复制 编辑 原始数据 按行查看 历史
jhonm 提交于 2023-08-07 15:31 . init
package creator
import (
"errors"
"gitee.com/coodder/unipdf/common"
)
// Division is a container component which can wrap across multiple pages (unlike Block).
// It can contain multiple Drawable components (currently supporting Paragraph and Image).
//
// The component stacking behavior is vertical, where the Drawables are drawn on top of each other.
// Also supports horizontal stacking by activating the inline mode.
type Division struct {
components []VectorDrawable
// Positioning: relative / absolute.
positioning positioning
// Margins to be applied around the block when drawing on Page.
margins margins
// Controls whether the components are stacked horizontally
inline bool
}
// newDivision returns a new Division container component.
func newDivision() *Division {
return &Division{
components: []VectorDrawable{},
}
}
// Inline returns whether the inline mode of the division is active.
func (div *Division) Inline() bool {
return div.inline
}
// SetInline sets the inline mode of the division.
func (div *Division) SetInline(inline bool) {
div.inline = inline
}
// Add adds a VectorDrawable to the Division container.
// Currently supported VectorDrawables: *Paragraph, *StyledParagraph, *Image.
func (div *Division) Add(d VectorDrawable) error {
supported := false
switch d.(type) {
case *Paragraph:
supported = true
case *StyledParagraph:
supported = true
case *Image:
supported = true
}
if !supported {
return errors.New("unsupported type in Division")
}
div.components = append(div.components, d)
return nil
}
// Height returns the height for the Division component assuming all stacked on top of each other.
func (div *Division) Height() float64 {
y := 0.0
yMax := 0.0
for _, component := range div.components {
compWidth, compHeight := component.Width(), component.Height()
switch t := component.(type) {
case *Paragraph:
p := t
compWidth += p.margins.left + p.margins.right
compHeight += p.margins.top + p.margins.bottom
case *StyledParagraph:
p := t
compWidth += p.margins.left + p.margins.right
compHeight += p.margins.top + p.margins.bottom
}
// Vertical stacking.
y += compHeight
yMax = y
}
return yMax
}
// Width is not used. Not used as a Division element is designed to fill into available width depending on
// context. Returns 0.
func (div *Division) Width() float64 {
return 0
}
// GeneratePageBlocks generates the page blocks for the Division component.
// Multiple blocks are generated if the contents wrap over multiple pages.
func (div *Division) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
var pageblocks []*Block
origCtx := ctx
if div.positioning.isRelative() {
// Update context.
ctx.X += div.margins.left
ctx.Y += div.margins.top
ctx.Width -= div.margins.left + div.margins.right
ctx.Height -= div.margins.top
}
// Set the inline mode of the division to the context.
ctx.Inline = div.inline
// Draw.
divCtx := ctx
tmpCtx := ctx
var lineHeight float64
for _, component := range div.components {
if ctx.Inline {
// Check whether the component fits on the current line.
if (ctx.X-divCtx.X)+component.Width() <= ctx.Width {
ctx.Y = tmpCtx.Y
ctx.Height = tmpCtx.Height
} else {
ctx.X = divCtx.X
ctx.Width = divCtx.Width
tmpCtx.Y += lineHeight
tmpCtx.Height -= lineHeight
lineHeight = 0
}
}
newblocks, updCtx, err := component.GeneratePageBlocks(ctx)
if err != nil {
common.Log.Debug("Error generating page blocks: %v", err)
return nil, ctx, err
}
if len(newblocks) < 1 {
continue
}
if len(pageblocks) > 0 {
// If there are pageblocks already in place.
// merge the first block in with current Block and append the rest.
pageblocks[len(pageblocks)-1].mergeBlocks(newblocks[0])
pageblocks = append(pageblocks, newblocks[1:]...)
} else {
pageblocks = append(pageblocks, newblocks[0:]...)
}
// Apply padding/margins.
if ctx.Inline {
// Recalculate positions on page change.
if ctx.Page != updCtx.Page {
divCtx.Y = ctx.Margins.top
divCtx.Height = ctx.PageHeight - ctx.Margins.top
tmpCtx.Y = divCtx.Y
tmpCtx.Height = divCtx.Height
lineHeight = updCtx.Height - divCtx.Height
} else {
// Calculate current line max height.
if dl := ctx.Height - updCtx.Height; dl > lineHeight {
lineHeight = dl
}
}
} else {
updCtx.X = ctx.X
}
ctx = updCtx
}
// Restore the original inline mode of the context.
ctx.Inline = origCtx.Inline
if div.positioning.isRelative() {
// Move back X to same start of line.
ctx.X = origCtx.X
}
if div.positioning.isAbsolute() {
// If absolute: return original context.
return pageblocks, origCtx, nil
}
return pageblocks, ctx, nil
}
Go
1
https://gitee.com/coodder/unipdf.git
git@gitee.com:coodder/unipdf.git
coodder
unipdf
unipdf
v1.2.0

搜索帮助