From 1f5086d318a9732fc5c99ab5ce82adf1e255f736 Mon Sep 17 00:00:00 2001 From: John Fercher <4752636+johnfercher@users.noreply.github.com> Date: Sun, 1 Oct 2023 19:13:19 -0300 Subject: [PATCH] Refactor merge (#328) --- README.md | 2 +- docs/README.md | 4 +- .../examples/{addpdf => mergepdf}/v2/main.go | 24 +++++---- .../pdf/{addpdfv2.pdf => mergepdfv2.pdf} | Bin 274547 -> 274547 bytes docs/assets/text/addpdfv2.txt | 4 -- docs/assets/text/mergepdfv2.txt | 4 ++ docs/v2/features/_sidebar.md | 2 +- docs/v2/features/addpdf.md | 13 ----- docs/v2/features/mergepdf.md | 13 +++++ pkg/core/core.go | 2 +- pkg/core/pdf.go | 34 ++++++++++++ pkg/maroto.go | 51 +++--------------- pkg/merge/merge.go | 30 +++++++++++ pkg/metricsdecorator.go | 8 --- 14 files changed, 107 insertions(+), 84 deletions(-) rename docs/assets/examples/{addpdf => mergepdf}/v2/main.go (75%) rename docs/assets/pdf/{addpdfv2.pdf => mergepdfv2.pdf} (99%) delete mode 100644 docs/assets/text/addpdfv2.txt create mode 100644 docs/assets/text/mergepdfv2.txt delete mode 100644 docs/v2/features/addpdf.md create mode 100644 docs/v2/features/mergepdf.md create mode 100644 pkg/merge/merge.go diff --git a/README.md b/README.md index 68fba3ca..9943f70b 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ always when a new page appear, in this case, a header may have many rows, lines * With `go get`: ```bash -go get github.com/johnfercher/maroto/v2/pkg@v2.0.0-alpha.31 +go get github.com/johnfercher/maroto/v2/pkg@v2.0.0-alpha.32 ``` diff --git a/docs/README.md b/docs/README.md index 5b4a91dc..8abe94c9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,12 +2,12 @@ [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go#template-engines) [![Branch](https://img.shields.io/badge/V2-Branch-pink)](https://github.com/johnfercher/maroto/tree/v2) [![Roadmap](https://img.shields.io/badge/V2-Roadmap-purple)](https://github.com/users/johnfercher/projects/1) [![Discussion](https://img.shields.io/badge/V2-Discussion-blue)](https://github.com/johnfercher/maroto/issues/257) [![Release Notes](https://img.shields.io/badge/Release-Notes-cyan)](https://github.com/johnfercher/maroto/releases) [![Visits Badge](https://badges.pufler.dev/visits/johnfercher/maroto)](https://badges.pufler.dev) -#### Maroto`v2.0.0-alpha.31`is here! Try out: +#### Maroto`v2.0.0-alpha.32`is here! Try out: * Installation with`go get`: ```bash -go get github.com/johnfercher/maroto/v2/pkg@v2.0.0-alpha.31 +go get github.com/johnfercher/maroto/v2/pkg@v2.0.0-alpha.32 ``` The public API was completely redesigned with the aim of enhancing the diff --git a/docs/assets/examples/addpdf/v2/main.go b/docs/assets/examples/mergepdf/v2/main.go similarity index 75% rename from docs/assets/examples/addpdf/v2/main.go rename to docs/assets/examples/mergepdf/v2/main.go index 073bc98a..070391da 100644 --- a/docs/assets/examples/addpdf/v2/main.go +++ b/docs/assets/examples/mergepdf/v2/main.go @@ -4,11 +4,10 @@ import ( "log" "os" - "github.com/johnfercher/maroto/v2/pkg/components/text" - "github.com/johnfercher/maroto/v2/pkg/props" - "github.com/johnfercher/maroto/v2/pkg" + "github.com/johnfercher/maroto/v2/pkg/components/text" "github.com/johnfercher/maroto/v2/pkg/config" + "github.com/johnfercher/maroto/v2/pkg/props" ) var dummyText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac condimentum sem." @@ -21,28 +20,31 @@ func main() { mrt := pkg.NewMaroto(cfg) m := pkg.NewMetricsDecorator(mrt) - pdf, err := os.ReadFile("docs/assets/pdf/v2.pdf") + for i := 0; i < 50; i++ { + m.AddRows(text.NewRow(20, "content")) + } + + document, err := m.Generate() if err != nil { log.Fatal(err.Error()) } - m.AddPDFs(pdf) - - for i := 0; i < 50; i++ { - m.AddRows(text.NewRow(20, "content")) + savedPdf, err := os.ReadFile("docs/assets/pdf/v2.pdf") + if err != nil { + log.Fatal(err.Error()) } - document, err := m.Generate() + err = document.Merge(savedPdf) if err != nil { log.Fatal(err.Error()) } - err = document.Save("docs/assets/pdf/addpdfv2.pdf") + err = document.Save("docs/assets/pdf/mergepdfv2.pdf") if err != nil { log.Fatal(err.Error()) } - err = document.GetReport().Save("docs/assets/text/addpdfv2.txt") + err = document.GetReport().Save("docs/assets/text/mergepdfv2.txt") if err != nil { log.Fatal(err.Error()) } diff --git a/docs/assets/pdf/addpdfv2.pdf b/docs/assets/pdf/mergepdfv2.pdf similarity index 99% rename from docs/assets/pdf/addpdfv2.pdf rename to docs/assets/pdf/mergepdfv2.pdf index 90dcb0114f5df50cfcb1d92b7081f09d84a3d374..2508686fceed8ce76ee6720cc659671758669c1e 100644 GIT binary patch delta 856 zcma)4&1(}u6eqi5#Wb;tX-HxsPK0(>(`M&mcazu<{K%mN3zCx}9+GtHXA?{!B3`6H zS|~Zlh!6S)6hs6ihnzf!h}eUmS3R@`LA>@RrMR;c1wqV%c{6W*zxmC3Z)Rsp+u71y z#u8$-9ugN09!fJC6I?MbR$FePgPG+=6}R2I+p4>5OdWW&rzQe+|61a4NTH7SIq^WD z1#xe(u5c#4PLco-VVwjlQPNF?=0sB`5iVs)o(0{;LbG-==$-g6k`f>Fvto0F_sp8Bo8 zogozB3U{Q$ZpxPQzq89ndh tZo4h{>~rNS#YIxBS+1oJlsN`zf3`}_51$1fAi z_L2`|irBr`vWzYEbrwmK1vDh(Sy3}&YO+cZ7Y`7TBi_?Vn5e z&Ipp4A`G=7{paQD$3-0v_fdNtu;~;XCBkcqidR!j>Fr*()9Xs!kq5o5G8KDfhY}<+ zPUAAk3?2@Z?KuDNUV#!}^*|_rv*UbaKa&2z)1k5z=ju>Nu!V_Gf{r5^l}4KTaZ^mQ z=G>et6pTLuC)POPGO>R5y%7VDuWu+}z8wQo!GCRN5Q>AV(`^5-pWjb|KoXBSg_H_4 zNJd+R#QcRuTZR<#S81>&QzGsxzcmMF8s&*aD8-1(BdQ^!oivtem6F|ZQ>D`c5&D4RDyRi0mb=7=I+PcZB;UTwUfrrSKdAg`XX@^hf{z diff --git a/docs/assets/text/addpdfv2.txt b/docs/assets/text/addpdfv2.txt deleted file mode 100644 index 4853c1d6..00000000 --- a/docs/assets/text/addpdfv2.txt +++ /dev/null @@ -1,4 +0,0 @@ -generate -> avg: 10.26ms, executions: [10.26ms] -add_row -> avg: 113.80ns, executions: [0.12μs, 0.08μs, 0.05μs, 0.02μs, 0.08μs, 0.02μs, 0.02μs, 0.01μs, 0.09μs, 0.02μs, 0.01μs, 0.02μs, 0.01μs, 3.53μs, 0.06μs, 0.05μs, 0.01μs, 0.07μs, 0.02μs, 0.02μs, 0.01μs, 0.06μs, 0.02μs, 0.01μs, 0.03μs, 0.01μs, 0.29μs, 0.06μs, 0.05μs, 0.02μs, 0.06μs, 0.02μs, 0.01μs, 0.02μs, 0.05μs, 0.02μs, 0.02μs, 0.02μs, 0.01μs, 0.24μs, 0.05μs, 0.06μs, 0.01μs, 0.08μs, 0.01μs, 0.01μs, 0.02μs, 0.05μs, 0.02μs, 0.02μs] -add_pdf -> avg: 243.00ns, executions: [243.00ns] -file_size -> 274.55Kb diff --git a/docs/assets/text/mergepdfv2.txt b/docs/assets/text/mergepdfv2.txt new file mode 100644 index 00000000..6eec6af9 --- /dev/null +++ b/docs/assets/text/mergepdfv2.txt @@ -0,0 +1,4 @@ +generate -> avg: 8.58ms, executions: [8.58ms] +add_row -> avg: 86.64ns, executions: [0.24μs, 0.09μs, 0.07μs, 0.03μs, 0.08μs, 0.02μs, 0.02μs, 0.02μs, 0.08μs, 0.02μs, 0.02μs, 0.02μs, 0.03μs, 2.07μs, 0.07μs, 0.06μs, 0.01μs, 0.06μs, 0.02μs, 0.02μs, 0.02μs, 0.06μs, 0.02μs, 0.02μs, 0.02μs, 0.02μs, 0.29μs, 0.05μs, 0.05μs, 0.02μs, 0.06μs, 0.02μs, 0.02μs, 0.02μs, 0.06μs, 0.02μs, 0.02μs, 0.01μs, 0.01μs, 0.21μs, 0.04μs, 0.06μs, 0.02μs, 0.06μs, 0.02μs, 0.01μs, 0.02μs, 0.05μs, 0.02μs, 0.02μs] +merge_pdf -> avg: 1.21ms, executions: [1.21ms] +file_size -> 274.55Kb diff --git a/docs/v2/features/_sidebar.md b/docs/v2/features/_sidebar.md index 0fc3fe37..cd189218 100644 --- a/docs/v2/features/_sidebar.md +++ b/docs/v2/features/_sidebar.md @@ -1,7 +1,6 @@ * [← Back To Home](README.md?id=maroto-v2) * **Features** * [Add Page](v2/features/addpage.md?id=add-page) - * [Add PDF](v2/features/addpdf.md?id=add-pdf) * [Background](v2/features/background.md?id=add-background) * [Barcode](v2/features/barcode.md?id=barcode) * [Cell Style](v2/features/cellstyle.md?id=cell-style) @@ -17,6 +16,7 @@ * [List](v2/features/list.md?id=list) * [Margins](v2/features/margins.md?id=custom-margins) * [Max Grid Sum](v2/features/maxgridsum.md?id=max-grid-sum) + * [Merge PDF](v2/features/mergepdf.md?id=merge-pdf) * [Metadatas](v2/features/metadatas.md?id=metadatas) * [Orientation](v2/features/orientation.md?id=orientation) * [Page Number](v2/features/pagenumber.md?id=page-number) diff --git a/docs/v2/features/addpdf.md b/docs/v2/features/addpdf.md deleted file mode 100644 index b7aee6f8..00000000 --- a/docs/v2/features/addpdf.md +++ /dev/null @@ -1,13 +0,0 @@ -# Add PDF - -## Code Example -[filename](../../assets/examples/addpdf/v2/main.go ':include :type=code') - - -## PDF Generated -```pdf - assets/pdf/addpdfv2.pdf -``` - -## Time Execution -[filename](../../assets/text/addpdfv2.txt ':include :type=code') \ No newline at end of file diff --git a/docs/v2/features/mergepdf.md b/docs/v2/features/mergepdf.md new file mode 100644 index 00000000..e6a02cf4 --- /dev/null +++ b/docs/v2/features/mergepdf.md @@ -0,0 +1,13 @@ +# Merge PDF + +## Code Example +[filename](../../assets/examples/mergepdf/v2/main.go ':include :type=code') + + +## PDF Generated +```pdf + assets/pdf/mergepdfv2.pdf +``` + +## Time Execution +[filename](../../assets/text/mergepdfv2.txt ':include :type=code') \ No newline at end of file diff --git a/pkg/core/core.go b/pkg/core/core.go index f4639ba9..14ab2234 100644 --- a/pkg/core/core.go +++ b/pkg/core/core.go @@ -13,7 +13,6 @@ type Maroto interface { AddRows(rows ...Row) AddRow(rowHeight float64, cols ...Col) Row AddPages(pages ...Page) - AddPDFs(pdfs ...[]byte) GetStructure() *node.Node[Structure] Generate() (Document, error) } @@ -23,6 +22,7 @@ type Document interface { GetBase64() string Save(file string) error GetReport() *metrics.Report + Merge([]byte) error } type Node interface { diff --git a/pkg/core/pdf.go b/pkg/core/pdf.go index 08b042ba..6afd8df8 100644 --- a/pkg/core/pdf.go +++ b/pkg/core/pdf.go @@ -4,7 +4,9 @@ import ( "encoding/base64" "os" + "github.com/johnfercher/maroto/v2/pkg/merge" "github.com/johnfercher/maroto/v2/pkg/metrics" + "github.com/johnfercher/maroto/v2/pkg/time" ) type pdf struct { @@ -31,6 +33,38 @@ func (p *pdf) GetReport() *metrics.Report { return p.report } +func (p *pdf) Merge(bytes []byte) error { + var mergedBytes []byte + var err error + + timeSpent := time.GetTimeSpent(func() { + mergedBytes, err = merge.Bytes(p.bytes, bytes) + }) + if err != nil { + return err + } + + timeMetric := metrics.TimeMetric{ + Key: "merge_pdf", + Times: []*metrics.Time{timeSpent}, + Avg: timeSpent, + } + timeMetric.Normalize() + p.report.TimeMetrics = append(p.report.TimeMetrics, timeMetric) + + p.bytes = mergedBytes + p.report.SizeMetric = metrics.SizeMetric{ + Key: "file_size", + Size: metrics.Size{ + Value: float64(len(mergedBytes)), + Scale: metrics.Byte, + }, + } + p.report.Normalize() + + return nil +} + func (p *pdf) Save(file string) error { f, err := os.Create(file) if err != nil { diff --git a/pkg/maroto.go b/pkg/maroto.go index ccc1b7f9..2af9b633 100644 --- a/pkg/maroto.go +++ b/pkg/maroto.go @@ -1,11 +1,11 @@ package pkg import ( - "bytes" "errors" - "io" "log" + "github.com/johnfercher/maroto/v2/pkg/merge" + "github.com/johnfercher/maroto/v2/pkg/core/entity" "github.com/johnfercher/go-tree/node" @@ -23,7 +23,6 @@ import ( "github.com/f-amaral/go-async/pool" "github.com/johnfercher/maroto/v2/pkg/config" "github.com/johnfercher/maroto/v2/pkg/core" - "github.com/pdfcpu/pdfcpu/pkg/api" ) type maroto struct { @@ -37,7 +36,6 @@ type maroto struct { rows []core.Row header []core.Row footer []core.Row - pdfs [][]byte headerHeight float64 footerHeight float64 currentHeight float64 @@ -148,10 +146,6 @@ func (m *maroto) GetStructure() *node.Node[core.Structure] { return node } -func (m *maroto) AddPDFs(pdfs ...[]byte) { - m.pdfs = append(m.pdfs, pdfs...) -} - func (m *maroto) addRows(rows ...core.Row) { for _, row := range rows { m.addRow(row) @@ -234,24 +228,7 @@ func (m *maroto) generate() (core.Document, error) { return nil, err } - if len(m.pdfs) == 0 { - return core.NewPDF(documentBytes, nil), nil - } - - readers := []io.ReadSeeker{} - readers = append(readers, bytes.NewReader(documentBytes)) - for _, pdf := range m.pdfs { - readers = append(readers, bytes.NewReader(pdf)) - } - - var buf bytes.Buffer - writer := io.Writer(&buf) - err = mergePdfs(readers, writer) - if err != nil { - return nil, err - } - - return core.NewPDF(buf.Bytes(), nil), nil + return core.NewPDF(documentBytes, nil), nil } func (m *maroto) generateConcurrently() (core.Document, error) { @@ -275,24 +252,18 @@ func (m *maroto) generateConcurrently() (core.Document, error) { log.Fatal("error on generating pages") } - readers := make([]io.ReadSeeker, len(processed.Results)+len(m.pdfs)) + pdfs := make([][]byte, len(processed.Results)) for i, result := range processed.Results { - b := result.Output.([]byte) - readers[i] = bytes.NewReader(b) + bytes := result.Output.([]byte) + pdfs[i] = bytes } - for i, pdf := range m.pdfs { - readers[i+len(processed.Results)] = bytes.NewReader(pdf) - } - - var buf bytes.Buffer - writer := io.Writer(&buf) - err := mergePdfs(readers, writer) + mergedBytes, err := merge.Bytes(pdfs...) if err != nil { return nil, err } - return core.NewPDF(buf.Bytes(), nil), nil + return core.NewPDF(mergedBytes, nil), nil } func (m *maroto) processPage(pages []core.Page) ([]byte, error) { @@ -326,9 +297,3 @@ func getConfig(configs ...*entity.Config) *entity.Config { func getProvider(cache cache.Cache, cfg *entity.Config) core.Provider { return gofpdf.New(cfg, cache) } - -func mergePdfs(readers []io.ReadSeeker, writer io.Writer) error { - conf := api.LoadConfiguration() - conf.WriteXRefStream = false - return api.MergeRaw(readers, writer, conf) -} diff --git a/pkg/merge/merge.go b/pkg/merge/merge.go new file mode 100644 index 00000000..b29bf8c9 --- /dev/null +++ b/pkg/merge/merge.go @@ -0,0 +1,30 @@ +package merge + +import ( + "bytes" + "io" + + "github.com/pdfcpu/pdfcpu/pkg/api" +) + +func Bytes(pdfs ...[]byte) ([]byte, error) { + readers := make([]io.ReadSeeker, len(pdfs)) + for i, pdf := range pdfs { + readers[i] = bytes.NewReader(pdf) + } + + var buf bytes.Buffer + writer := io.Writer(&buf) + err := mergePdfs(readers, writer) + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func mergePdfs(readers []io.ReadSeeker, writer io.Writer) error { + conf := api.LoadConfiguration() + conf.WriteXRefStream = false + return api.MergeRaw(readers, writer, conf) +} diff --git a/pkg/metricsdecorator.go b/pkg/metricsdecorator.go index 28350e2b..0c4aa846 100644 --- a/pkg/metricsdecorator.go +++ b/pkg/metricsdecorator.go @@ -53,14 +53,6 @@ func (m *metricsDecorator) AddPages(pages ...core.Page) { m.addPageTime = append(m.addPageTime, timeSpent) } -func (m *metricsDecorator) AddPDFs(pdfs ...[]byte) { - timeSpent := time.GetTimeSpent(func() { - m.inner.AddPDFs(pdfs...) - }) - - m.addPDFTime = append(m.addPDFTime, timeSpent) -} - func (m *metricsDecorator) AddRows(rows ...core.Row) { timeSpent := time.GetTimeSpent(func() { m.inner.AddRows(rows...)