diff --git a/go.mod b/go.mod index 135d1f5..80dc584 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,10 @@ require ( golang.org/x/term v0.20.0 ) -require golang.org/x/sync v0.7.0 +require ( + github.com/jung-kurt/gofpdf v1.16.2 + golang.org/x/sync v0.7.0 +) require ( github.com/bytedance/sonic v1.11.6 // indirect diff --git a/go.sum b/go.sum index 6047c68..1f4dc1c 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,5 @@ filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= @@ -95,6 +96,9 @@ github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.16.2 h1:jgbatWHfRlPYiK85qgevsZTHviWXKwB1TTiKdz5PtRc= +github.com/jung-kurt/gofpdf v1.16.2/go.mod h1:1hl7y57EsiPAkLbOwzpzqgx1A30nQCk/YmFV8S2vmK0= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= @@ -143,6 +147,8 @@ github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtos github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -154,10 +160,12 @@ github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -213,6 +221,7 @@ golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= diff --git a/goextVersion.go b/goextVersion.go index dc7ca59..de94d13 100644 --- a/goextVersion.go +++ b/goextVersion.go @@ -1,5 +1,5 @@ package goext -const GoextVersion = "0.0.449" +const GoextVersion = "0.0.450" -const GoextVersionTimestamp = "2024-05-12T16:51:52+0200" +const GoextVersionTimestamp = "2024-05-14T11:52:56+0200" diff --git a/wpdf/wpdf.go b/wpdf/wpdf.go new file mode 100644 index 0000000..5d337e9 --- /dev/null +++ b/wpdf/wpdf.go @@ -0,0 +1,183 @@ +package wpdf + +import ( + "bytes" + "github.com/jung-kurt/gofpdf" +) + +type WPDFBuilder struct { + b *gofpdf.Fpdf + tr func(string) string + cellHeight float64 + fontName PDFFontFamily + fontStyle PDFFontStyle + fontSize float64 +} + +type PDFMargins struct { + Left float64 + Top float64 + Right float64 +} + +type PDFColor struct { + R int + G int + B int +} + +func NewPDFBuilder(orientation PDFOrientation, size PDFSize, unicode bool) *WPDFBuilder { + + fpdfbuilder := gofpdf.New(string(orientation), "mm", string(size), "") + + var tr func(string) string + if unicode { + tr = fpdfbuilder.UnicodeTranslatorFromDescriptor("") + } else { + tr = func(s string) string { return s } + } + + b := &WPDFBuilder{ + b: fpdfbuilder, + tr: tr, + cellHeight: 5, + } + + b.SetMargins(PDFMargins{Left: 15, Top: 25, Right: 15}) // default values + b.SetFont(FontHelvetica, Normal, 12) // ensures font is set + + return b +} + +func (b *WPDFBuilder) SetMargins(v PDFMargins) { + b.b.SetMargins(v.Left, v.Top, v.Right) +} + +func (b *WPDFBuilder) AddPage() { + b.b.AddPage() +} + +func (b *WPDFBuilder) SetTextColor(cr, cg, cb int) { + b.b.SetTextColor(cr, cg, cb) +} + +func (b *WPDFBuilder) GetTextColor() (cr, cg, cb int) { + return b.b.GetTextColor() +} + +func (b *WPDFBuilder) SetDrawColor(cr, cg, cb int) { + b.b.SetDrawColor(cr, cg, cb) +} + +func (b *WPDFBuilder) GetDrawColor() (cr, cg, cb int) { + return b.b.GetDrawColor() +} + +func (b *WPDFBuilder) SetFillColor(cr, cg, cb int) { + b.b.SetFillColor(cr, cg, cb) +} + +func (b *WPDFBuilder) GetFillColor() (cr, cg, cb int) { + return b.b.GetFillColor() +} + +func (b *WPDFBuilder) SetLineWidth(w float64) { + b.b.SetLineWidth(w) +} + +func (b *WPDFBuilder) GetLineWidth() float64 { + return b.b.GetLineWidth() +} + +func (b *WPDFBuilder) SetFont(fontName PDFFontFamily, fontStyle PDFFontStyle, fontSize float64) { + b.b.SetFont(string(fontName), string(fontStyle), fontSize) + + b.fontName = fontName + b.fontStyle = fontStyle + b.fontSize = fontSize + + b.cellHeight = b.b.PointConvert(fontSize) +} + +func (b *WPDFBuilder) Ln(h float64) { + b.b.Ln(h) +} + +func (b *WPDFBuilder) Build() ([]byte, error) { + buf := new(bytes.Buffer) + err := b.b.Output(buf) + if err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func (b *WPDFBuilder) SetX(x float64) { + b.b.SetX(x) +} + +func (b *WPDFBuilder) GetX() float64 { + return b.b.GetX() +} + +func (b *WPDFBuilder) SetY(y float64) { + b.b.SetY(y) +} + +func (b *WPDFBuilder) GetY() float64 { + return b.b.GetY() +} + +func (b *WPDFBuilder) SetXY(x float64, y float64) { + b.b.SetXY(x, y) +} + +func (b *WPDFBuilder) GetXY() (x float64, y float64) { + return b.b.GetXY() +} + +func (b *WPDFBuilder) GetMargins() (left, top, right, bottom float64) { + return b.b.GetMargins() +} + +func (b *WPDFBuilder) GetMarginLeft() float64 { + v, _, _, _ := b.b.GetMargins() + return v +} + +func (b *WPDFBuilder) GetMarginTop() float64 { + _, v, _, _ := b.b.GetMargins() + return v +} + +func (b *WPDFBuilder) GetMarginRight() float64 { + _, _, v, _ := b.b.GetMargins() + return v +} + +func (b *WPDFBuilder) GetMarginBottom() float64 { + _, _, _, v := b.b.GetMargins() + return v +} + +func (b *WPDFBuilder) GetPageSize() (width, height float64) { + return b.b.GetPageSize() +} + +func (b *WPDFBuilder) GetPageWidth() float64 { + v, _ := b.b.GetPageSize() + return v +} + +func (b *WPDFBuilder) GetPageHeight() float64 { + _, v := b.b.GetPageSize() + return v +} + +func (b *WPDFBuilder) GetWorkAreaWidth() float64 { + return b.GetPageWidth() - b.GetMarginLeft() - b.GetMarginRight() +} + +func (b *WPDFBuilder) GetStringWidth(str string) float64 { + return b.b.GetStringWidth(str) +} diff --git a/wpdf/wpdfCell.go b/wpdf/wpdfCell.go new file mode 100644 index 0000000..1de34da --- /dev/null +++ b/wpdf/wpdfCell.go @@ -0,0 +1,173 @@ +package wpdf + +import "gogs.mikescher.com/BlackForestBytes/goext/langext" + +type PDFCellOpt struct { + width *float64 + height *float64 + border *PDFBorder + ln *PDFTextBreak + align *PDFTextAlign + fill *bool + link *int + linkStr *string + fontNameOverride *PDFFontFamily + fontStyleOverride *PDFFontStyle + fontSizeOverride *float64 + extraLn *float64 + x *float64 + autoWidth *bool +} + +func NewPDFCellOpt() *PDFCellOpt { + return &PDFCellOpt{} +} + +func (opt *PDFCellOpt) Width(v float64) *PDFCellOpt { + opt.width = &v + return opt +} + +func (opt *PDFCellOpt) Height(v float64) *PDFCellOpt { + opt.height = &v + return opt +} + +func (opt *PDFCellOpt) Border(v PDFBorder) *PDFCellOpt { + opt.border = &v + return opt +} + +func (opt *PDFCellOpt) LnPos(v PDFTextBreak) *PDFCellOpt { + opt.ln = &v + return opt +} + +func (opt *PDFCellOpt) Align(v PDFTextAlign) *PDFCellOpt { + opt.align = &v + return opt +} + +func (opt *PDFCellOpt) FillBackground(v bool) *PDFCellOpt { + opt.fill = &v + return opt +} + +func (opt *PDFCellOpt) Link(v int) *PDFCellOpt { + opt.link = &v + return opt +} + +func (opt *PDFCellOpt) LinkStr(v string) *PDFCellOpt { + opt.linkStr = &v + return opt +} + +func (opt *PDFCellOpt) Font(fontName PDFFontFamily, fontStyle PDFFontStyle, fontSize float64) *PDFCellOpt { + opt.fontNameOverride = &fontName + opt.fontStyleOverride = &fontStyle + opt.fontSizeOverride = &fontSize + return opt +} + +func (opt *PDFCellOpt) FontName(v PDFFontFamily) *PDFCellOpt { + opt.fontNameOverride = &v + return opt +} + +func (opt *PDFCellOpt) FontStyle(v PDFFontStyle) *PDFCellOpt { + opt.fontStyleOverride = &v + return opt +} + +func (opt *PDFCellOpt) FontSize(v float64) *PDFCellOpt { + opt.fontSizeOverride = &v + return opt +} + +func (opt *PDFCellOpt) Bold() *PDFCellOpt { + opt.fontStyleOverride = langext.Ptr(Bold) + return opt +} + +func (opt *PDFCellOpt) Italic() *PDFCellOpt { + opt.fontStyleOverride = langext.Ptr(Italic) + return opt +} + +func (opt *PDFCellOpt) LnAfter(v float64) *PDFCellOpt { + opt.extraLn = &v + return opt +} + +func (opt *PDFCellOpt) X(v float64) *PDFCellOpt { + opt.x = &v + return opt +} + +func (opt *PDFCellOpt) AutoWidth() *PDFCellOpt { + opt.autoWidth = langext.PTrue + return opt +} + +func (b *WPDFBuilder) Cell(txt string, opts ...*PDFCellOpt) { + + txtTR := b.tr(txt) + + width := float64(0) + height := b.cellHeight + border := BorderNone + ln := BreakToNextLine + align := AlignLeft + fill := false + link := 0 + linkStr := "" + var fontNameOverride *PDFFontFamily + var fontStyleOverride *PDFFontStyle + var fontSizeOverride *float64 + extraLn := float64(0) + var x *float64 + autoWidth := false + + for _, opt := range opts { + width = langext.Coalesce(opt.width, width) + height = langext.Coalesce(opt.height, height) + border = langext.Coalesce(opt.border, border) + ln = langext.Coalesce(opt.ln, ln) + align = langext.Coalesce(opt.align, align) + fill = langext.Coalesce(opt.fill, fill) + link = langext.Coalesce(opt.link, link) + linkStr = langext.Coalesce(opt.linkStr, linkStr) + fontNameOverride = langext.CoalesceOpt(opt.fontNameOverride, fontNameOverride) + fontStyleOverride = langext.CoalesceOpt(opt.fontStyleOverride, fontStyleOverride) + fontSizeOverride = langext.CoalesceOpt(opt.fontSizeOverride, fontSizeOverride) + extraLn = langext.Coalesce(opt.extraLn, extraLn) + x = langext.CoalesceOpt(opt.x, x) + autoWidth = langext.Coalesce(opt.autoWidth, autoWidth) + } + + if fontNameOverride != nil || fontStyleOverride != nil || fontSizeOverride != nil { + oldFontName := b.fontName + oldFontStyle := b.fontStyle + oldFontSize := b.fontSize + newFontName := langext.Coalesce(fontNameOverride, oldFontName) + newFontStyle := langext.Coalesce(fontStyleOverride, oldFontStyle) + newFontSize := langext.Coalesce(fontSizeOverride, oldFontSize) + b.SetFont(newFontName, newFontStyle, newFontSize) + defer func() { b.SetFont(oldFontName, oldFontStyle, oldFontSize) }() + } + + if x != nil { + b.b.SetX(*x) + } + + if autoWidth { + width = b.b.GetStringWidth(txtTR) + } + + b.b.CellFormat(width, height, txtTR, string(border), int(ln), string(align), fill, link, linkStr) + + if extraLn != 0 { + b.b.Ln(extraLn) + } +} diff --git a/wpdf/wpdfConstants.go b/wpdf/wpdfConstants.go new file mode 100644 index 0000000..2cd9e82 --- /dev/null +++ b/wpdf/wpdfConstants.go @@ -0,0 +1,80 @@ +package wpdf + +type PDFOrientation string + +const ( + Portrait PDFOrientation = "P" + Landscape PDFOrientation = "L" +) + +type PDFSize string + +const ( + SizeA3 PDFSize = "A3" + SizeA4 PDFSize = "A4" + SizeA5 PDFSize = "A4" + SizeLetter PDFSize = "Letter" + SizeLegal PDFSize = "Legal" + SizeTabloid PDFSize = "Tabloid" +) + +type PDFFontFamily string + +const ( + FontCourier PDFFontFamily = "courier" + FontHelvetica PDFFontFamily = "helvetica" + FontTimes PDFFontFamily = "times" + FontZapfDingbats PDFFontFamily = "zapfdingbats" + FontSymbol PDFFontFamily = "symbol" +) + +type PDFFontStyle string + +const ( + Normal PDFFontStyle = "" + Bold PDFFontStyle = "B" + Italic PDFFontStyle = "I" + BoldItalic PDFFontStyle = "IB" +) + +type PDFBorder string + +const ( + BorderNone PDFBorder = "" + BorderFull PDFBorder = "1" + BorderLeft PDFBorder = "L" + BorderTop PDFBorder = "T" + BorderRight PDFBorder = "R" + BorderBottom PDFBorder = "B" + BorderTLR PDFBorder = "TLR" + BorderLR PDFBorder = "LR" +) + +type PDFTextBreak int + +const ( + BreakToRight PDFTextBreak = 0 + BreakToNextLine PDFTextBreak = 1 + BreakToBelow PDFTextBreak = 2 +) + +type PDFTextAlign string + +const ( + AlignLeft PDFTextAlign = "L" + AlignHorzCenter PDFTextAlign = "C" + AlignRight PDFTextAlign = "R" +) + +type PDFRectStyle string + +const ( + RectFill PDFRectStyle = "F" + RectOutline PDFRectStyle = "D" + RectFillOutline PDFRectStyle = "FD" +) + +const ( + BackgroundFill = true + BackgroundTransparent = false +) diff --git a/wpdf/wpdfImage.go b/wpdf/wpdfImage.go new file mode 100644 index 0000000..e1c0752 --- /dev/null +++ b/wpdf/wpdfImage.go @@ -0,0 +1,186 @@ +package wpdf + +import ( + "bytes" + "github.com/jung-kurt/gofpdf" + "gogs.mikescher.com/BlackForestBytes/goext/langext" + "net/http" +) + +type PDFImageRef struct { + Info *gofpdf.ImageInfoType + Name string +} + +type PDFImageRegisterOpt struct { + imageType *string + readDpi *bool + allowNegativePosition *bool + name *string +} + +func NewPDFImageRegisterOpt() *PDFImageRegisterOpt { + return &PDFImageRegisterOpt{} +} + +func (opt *PDFImageRegisterOpt) ImageType(v string) *PDFImageRegisterOpt { + opt.imageType = &v + return opt +} + +func (opt *PDFImageRegisterOpt) ReadDpi(v bool) *PDFImageRegisterOpt { + opt.readDpi = &v + return opt +} + +func (opt *PDFImageRegisterOpt) AllowNegativePosition(v bool) *PDFImageRegisterOpt { + opt.allowNegativePosition = &v + return opt +} + +func (opt *PDFImageRegisterOpt) Name(v string) *PDFImageRegisterOpt { + opt.name = &v + return opt +} + +func (b *WPDFBuilder) RegisterImage(bin []byte, opts ...*PDFImageRegisterOpt) *PDFImageRef { + imgName := "fpdf_img_" + langext.MustRawHexUUID() + imageType := "" + readDpi := false + allowNegativePosition := false + + for _, opt := range opts { + imageType = langext.Coalesce(opt.imageType, imageType) + readDpi = langext.Coalesce(opt.readDpi, readDpi) + allowNegativePosition = langext.Coalesce(opt.allowNegativePosition, allowNegativePosition) + imgName = langext.Coalesce(opt.name, imgName) + } + + if imageType == "" { + ct := http.DetectContentType(bin[:512]) + switch ct { + case "image/jpg": + imageType = "JPG" + case "image/jpeg": + imageType = "JPEG" + case "image/png": + imageType = "PNG" + case "image/gif": + imageType = "GIF" + } + } + + options := gofpdf.ImageOptions{ + ImageType: imageType, + ReadDpi: readDpi, + AllowNegativePosition: allowNegativePosition, + } + + info := b.b.RegisterImageOptionsReader(imgName, options, bytes.NewReader(bin)) + + return &PDFImageRef{ + Name: imgName, + Info: info, + } +} + +type PDFImageOpt struct { + x *float64 + y *float64 + width *float64 + height *float64 + flow *bool + link *int + linkStr *string + imageType *string + readDpi *bool + allowNegativePosition *bool +} + +func NewPDFImageOpt() *PDFImageOpt { + return &PDFImageOpt{} +} + +func (opt *PDFImageOpt) X(v float64) *PDFImageOpt { + opt.x = &v + return opt +} + +func (opt *PDFImageOpt) Y(v float64) *PDFImageOpt { + opt.y = &v + return opt +} + +func (opt *PDFImageOpt) Width(v float64) *PDFImageOpt { + opt.width = &v + return opt +} + +func (opt *PDFImageOpt) Height(v float64) *PDFImageOpt { + opt.height = &v + return opt +} + +func (opt *PDFImageOpt) Flow(v bool) *PDFImageOpt { + opt.flow = &v + return opt +} + +func (opt *PDFImageOpt) Link(v int) *PDFImageOpt { + opt.link = &v + return opt +} + +func (opt *PDFImageOpt) LinkStr(v string) *PDFImageOpt { + opt.linkStr = &v + return opt +} + +func (opt *PDFImageOpt) ImageType(v string) *PDFImageOpt { + opt.imageType = &v + return opt +} + +func (opt *PDFImageOpt) ReadDpi(v bool) *PDFImageOpt { + opt.readDpi = &v + return opt +} + +func (opt *PDFImageOpt) AllowNegativePosition(v bool) *PDFImageOpt { + opt.allowNegativePosition = &v + return opt +} + +func (b *WPDFBuilder) Image(img *PDFImageRef, opts ...*PDFImageOpt) { + x := b.GetX() + y := b.GetY() + w := img.Info.Width() + h := img.Info.Height() + flow := true + link := 0 + linkStr := "" + imageType := "" + readDpi := false + allowNegativePosition := false + + for _, opt := range opts { + x = langext.Coalesce(opt.x, x) + y = langext.Coalesce(opt.y, y) + w = langext.Coalesce(opt.width, w) + h = langext.Coalesce(opt.height, h) + flow = langext.Coalesce(opt.flow, flow) + link = langext.Coalesce(opt.link, link) + linkStr = langext.Coalesce(opt.linkStr, linkStr) + imageType = langext.Coalesce(opt.imageType, imageType) + readDpi = langext.Coalesce(opt.readDpi, readDpi) + allowNegativePosition = langext.Coalesce(opt.allowNegativePosition, allowNegativePosition) + } + + fpdfOpt := gofpdf.ImageOptions{ + ImageType: imageType, + ReadDpi: readDpi, + AllowNegativePosition: allowNegativePosition, + } + + b.b.ImageOptions(img.Name, x, y, w, h, flow, fpdfOpt, link, linkStr) +} diff --git a/wpdf/wpdfMultiCell.go b/wpdf/wpdfMultiCell.go new file mode 100644 index 0000000..428704f --- /dev/null +++ b/wpdf/wpdfMultiCell.go @@ -0,0 +1,137 @@ +package wpdf + +import "gogs.mikescher.com/BlackForestBytes/goext/langext" + +type PDFMultiCellOpt struct { + width *float64 + height *float64 + border *PDFBorder + align *PDFTextAlign + fill *bool + fontNameOverride *PDFFontFamily + fontStyleOverride *PDFFontStyle + fontSizeOverride *float64 + extraLn *float64 + x *float64 +} + +func NewPDFMultiCellOpt() *PDFMultiCellOpt { + return &PDFMultiCellOpt{} +} + +func (opt *PDFMultiCellOpt) Width(v float64) *PDFMultiCellOpt { + opt.width = &v + return opt +} + +func (opt *PDFMultiCellOpt) Height(v float64) *PDFMultiCellOpt { + opt.height = &v + return opt +} + +func (opt *PDFMultiCellOpt) Border(v PDFBorder) *PDFMultiCellOpt { + opt.border = &v + return opt +} + +func (opt *PDFMultiCellOpt) Align(v PDFTextAlign) *PDFMultiCellOpt { + opt.align = &v + return opt +} + +func (opt *PDFMultiCellOpt) FillBackground(v bool) *PDFMultiCellOpt { + opt.fill = &v + return opt +} + +func (opt *PDFMultiCellOpt) Font(fontName PDFFontFamily, fontStyle PDFFontStyle, fontSize float64) *PDFMultiCellOpt { + opt.fontNameOverride = &fontName + opt.fontStyleOverride = &fontStyle + opt.fontSizeOverride = &fontSize + return opt +} + +func (opt *PDFMultiCellOpt) FontName(v PDFFontFamily) *PDFMultiCellOpt { + opt.fontNameOverride = &v + return opt +} + +func (opt *PDFMultiCellOpt) FontStyle(v PDFFontStyle) *PDFMultiCellOpt { + opt.fontStyleOverride = &v + return opt +} + +func (opt *PDFMultiCellOpt) FontSize(v float64) *PDFMultiCellOpt { + opt.fontSizeOverride = &v + return opt +} + +func (opt *PDFMultiCellOpt) Bold() *PDFMultiCellOpt { + opt.fontStyleOverride = langext.Ptr(Bold) + return opt +} + +func (opt *PDFMultiCellOpt) Italic() *PDFMultiCellOpt { + opt.fontStyleOverride = langext.Ptr(Italic) + return opt +} + +func (opt *PDFMultiCellOpt) LnAfter(v float64) *PDFMultiCellOpt { + opt.extraLn = &v + return opt +} + +func (opt *PDFMultiCellOpt) X(v float64) *PDFMultiCellOpt { + opt.x = &v + return opt +} + +func (b *WPDFBuilder) MultiCell(txt string, opts ...*PDFMultiCellOpt) { + + txtTR := b.tr(txt) + + width := float64(0) + height := b.cellHeight + border := BorderNone + align := AlignLeft + fill := false + var fontNameOverride *PDFFontFamily + var fontStyleOverride *PDFFontStyle + var fontSizeOverride *float64 + extraLn := float64(0) + var x *float64 + + for _, opt := range opts { + width = langext.Coalesce(opt.width, width) + height = langext.Coalesce(opt.height, height) + border = langext.Coalesce(opt.border, border) + align = langext.Coalesce(opt.align, align) + fill = langext.Coalesce(opt.fill, fill) + fontNameOverride = langext.CoalesceOpt(opt.fontNameOverride, fontNameOverride) + fontStyleOverride = langext.CoalesceOpt(opt.fontStyleOverride, fontStyleOverride) + fontSizeOverride = langext.CoalesceOpt(opt.fontSizeOverride, fontSizeOverride) + extraLn = langext.Coalesce(opt.extraLn, extraLn) + x = langext.CoalesceOpt(opt.x, x) + } + + if fontNameOverride != nil || fontStyleOverride != nil || fontSizeOverride != nil { + oldFontName := b.fontName + oldFontStyle := b.fontStyle + oldFontSize := b.fontSize + newFontName := langext.Coalesce(fontNameOverride, oldFontName) + newFontStyle := langext.Coalesce(fontStyleOverride, oldFontStyle) + newFontSize := langext.Coalesce(fontSizeOverride, oldFontSize) + b.SetFont(newFontName, newFontStyle, newFontSize) + defer func() { b.SetFont(oldFontName, oldFontStyle, oldFontSize) }() + } + + if x != nil { + b.b.SetX(*x) + } + + b.b.MultiCell(width, height, txtTR, string(border), string(align), fill) + + if extraLn != 0 { + b.b.Ln(extraLn) + } +} diff --git a/wpdf/wpdfRect.go b/wpdf/wpdfRect.go new file mode 100644 index 0000000..890fbb7 --- /dev/null +++ b/wpdf/wpdfRect.go @@ -0,0 +1,126 @@ +package wpdf + +import "gogs.mikescher.com/BlackForestBytes/goext/langext" + +type PDFRectOpt struct { + x *float64 + y *float64 + lineWidth *float64 + drawColor *PDFColor + fillColor *PDFColor + radiusTL *float64 + radiusTR *float64 + radiusBR *float64 + radiusBL *float64 +} + +func NewPDFRectOpt() *PDFRectOpt { + return &PDFRectOpt{} +} + +func (opt *PDFRectOpt) X(v float64) *PDFRectOpt { + opt.x = &v + return opt +} + +func (opt *PDFRectOpt) Y(v float64) *PDFRectOpt { + opt.y = &v + return opt +} + +func (opt *PDFRectOpt) LineWidth(v float64) *PDFRectOpt { + opt.lineWidth = &v + return opt +} + +func (opt *PDFRectOpt) DrawColor(cr, cg, cb int) *PDFRectOpt { + opt.drawColor = &PDFColor{R: cr, G: cg, B: cb} + return opt +} + +func (opt *PDFRectOpt) DrawColorHex(c uint32) *PDFRectOpt { + opt.drawColor = &PDFColor{R: int((c >> 16) & 0xFF), G: int((c >> 8) & 0xFF), B: int((c >> 0) & 0xFF)} + return opt +} + +func (opt *PDFRectOpt) FillColor(cr, cg, cb int) *PDFRectOpt { + opt.fillColor = &PDFColor{R: cr, G: cg, B: cb} + return opt +} + +func (opt *PDFRectOpt) FillColorHex(c uint32) *PDFRectOpt { + opt.fillColor = &PDFColor{R: int((c >> 16) & 0xFF), G: int((c >> 8) & 0xFF), B: int((c >> 0) & 0xFF)} + return opt +} + +func (opt *PDFRectOpt) Rounded(radius float64) *PDFRectOpt { + opt.radiusTL = &radius + opt.radiusTR = &radius + opt.radiusBR = &radius + opt.radiusBL = &radius + return opt +} + +func (opt *PDFRectOpt) RadiusTL(radius float64) *PDFRectOpt { + opt.radiusTL = &radius + return opt +} + +func (opt *PDFRectOpt) RadiusTR(radius float64) *PDFRectOpt { + opt.radiusTR = &radius + return opt +} + +func (opt *PDFRectOpt) RadiusBL(radius float64) *PDFRectOpt { + opt.radiusBL = &radius + return opt +} + +func (opt *PDFRectOpt) RadiusBR(radius float64) *PDFRectOpt { + opt.radiusBR = &radius + return opt +} + +func (b *WPDFBuilder) Rect(w float64, h float64, styleStr PDFRectStyle, opts ...*PDFRectOpt) { + x := b.GetX() + y := b.GetY() + var lineWidth *float64 + var drawColor *PDFColor + var fillColor *PDFColor + radiusTL := float64(0) + radiusTR := float64(0) + radiusBR := float64(0) + radiusBL := float64(0) + + for _, opt := range opts { + x = langext.Coalesce(opt.x, x) + y = langext.Coalesce(opt.y, y) + lineWidth = langext.CoalesceOpt(opt.lineWidth, lineWidth) + drawColor = langext.CoalesceOpt(opt.drawColor, drawColor) + fillColor = langext.CoalesceOpt(opt.fillColor, fillColor) + radiusTL = langext.Coalesce(opt.radiusTL, radiusTL) + radiusTR = langext.Coalesce(opt.radiusTR, radiusTR) + radiusBR = langext.Coalesce(opt.radiusBR, radiusBR) + radiusBL = langext.Coalesce(opt.radiusBL, radiusBL) + } + + if lineWidth != nil { + old := b.GetLineWidth() + b.SetLineWidth(*lineWidth) + defer func() { b.SetLineWidth(old) }() + } + + if drawColor != nil { + oldR, oldG, oldB := b.GetDrawColor() + b.SetDrawColor(drawColor.R, drawColor.G, drawColor.B) + defer func() { b.SetDrawColor(oldR, oldG, oldB) }() + } + + if fillColor != nil { + oldR, oldG, oldB := b.GetFillColor() + b.SetFillColor(fillColor.R, fillColor.G, fillColor.B) + defer func() { b.SetFillColor(oldR, oldG, oldB) }() + } + + b.b.RoundedRectExt(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL, string(styleStr)) +}