diff --git a/README.md b/README.md index b4506d1b..b546de9c 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,12 @@ You can write your PDFs like you are creating a site using Bootstrap. A Row may Besides that, pages will be added when content may extrapolate the useful area. You can define a header which will be added always when a new page appear, in this case, a header may have many rows, lines or tablelist. -#### Maroto `v2.0.6` is here! Try out: +#### Maroto `v2.0.7` is here! Try out: * Installation with`go get`: ```bash -go get github.com/johnfercher/maroto/v2@v2.0.6 +go get github.com/johnfercher/maroto/v2@v2.0.7 ``` * You can see the full `v2` documentation [here](https://maroto.io/). diff --git a/docs/README.md b/docs/README.md index 84b2ee9c..abfc3ae1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -19,12 +19,12 @@ * We are about to create a document processor to generate PDFs by interpreting serialized data as: yml, json or html. Please contribute with your ideas in [this discussion](https://github.com/johnfercher/maroto/discussions/390). -#### 3. Maroto`v2.0.6`is here! Try out: +#### 3. Maroto`v2.0.7`is here! Try out: * Installation with`go get`: ```bash -go get github.com/johnfercher/maroto/v2@v2.0.6 +go get github.com/johnfercher/maroto/v2@v2.0.7 ``` The public API was completely redesigned with the aim of enhancing the diff --git a/docs/_coverpage.md b/docs/_coverpage.md index c162212e..f40bfd00 100644 --- a/docs/_coverpage.md +++ b/docs/_coverpage.md @@ -1,6 +1,6 @@ ![logo](assets/images/logo.png) -# Maroto v2.0.6 +# Maroto v2.0.7 > An open-source golang lib to create PDFs. Fast and Simple. diff --git a/docs/assets/examples/background/v2/main.go b/docs/assets/examples/background/v2/main.go index 21030e70..3a97aa47 100644 --- a/docs/assets/examples/background/v2/main.go +++ b/docs/assets/examples/background/v2/main.go @@ -45,7 +45,9 @@ func GetMaroto(image string) core.Maroto { log.Fatal(err) } b := config.NewBuilder(). - WithMargins(0, 0, 0). + WithTopMargin(0). + WithLeftMargin(0). + WithRightMargin(0). WithOrientation(orientation.Horizontal). WithMaxGridSize(20). WithBackgroundImage(bytes, extension.Png) diff --git a/docs/assets/examples/billing/v2/main.go b/docs/assets/examples/billing/v2/main.go index 71b3eee3..87021042 100644 --- a/docs/assets/examples/billing/v2/main.go +++ b/docs/assets/examples/billing/v2/main.go @@ -39,7 +39,9 @@ func main() { func GetMaroto() core.Maroto { cfg := config.NewBuilder(). WithPageNumber(). - WithMargins(10, 15, 10). + WithLeftMargin(10). + WithTopMargin(15). + WithRightMargin(10). Build() darkGrayColor := getDarkGrayColor() diff --git a/docs/assets/examples/disablepagebreak/v2/main.go b/docs/assets/examples/disablepagebreak/v2/main.go index 7b1b8d42..9c7463e9 100644 --- a/docs/assets/examples/disablepagebreak/v2/main.go +++ b/docs/assets/examples/disablepagebreak/v2/main.go @@ -39,7 +39,9 @@ func GetMaroto(image string) core.Maroto { log.Fatal(err) } b := config.NewBuilder(). - WithMargins(0, 0, 0). + WithTopMargin(0). + WithRightMargin(0). + WithLeftMargin(0). WithDimensions(361.8, 203.2). WithDisableAutoPageBreak(true). WithOrientation(orientation.Horizontal). diff --git a/docs/assets/examples/margins/v2/main.go b/docs/assets/examples/margins/v2/main.go index 33a3c05f..ebcb4d34 100644 --- a/docs/assets/examples/margins/v2/main.go +++ b/docs/assets/examples/margins/v2/main.go @@ -3,6 +3,8 @@ package main import ( "log" + "github.com/johnfercher/maroto/v2/pkg/components/row" + "github.com/johnfercher/maroto/v2" "github.com/johnfercher/maroto/v2/pkg/components/col" "github.com/johnfercher/maroto/v2/pkg/components/image" @@ -32,24 +34,35 @@ func main() { func GetMaroto() core.Maroto { cfg := config.NewBuilder(). - WithMargins(20, 20, 20). + WithTopMargin(20). + WithLeftMargin(20). + WithRightMargin(20). WithDebug(true). Build() mrt := maroto.New(cfg) m := maroto.NewMetricsDecorator(mrt) - m.AddRow(40, - image.NewFromFileCol(4, "docs/assets/images/gopherbw.png", props.Rect{ - Center: true, - Percent: 50, - }), - text.NewCol(4, "Margins Test", props.Text{ - Top: 12, - Size: 12, - }), - col.New(4), + err := m.RegisterHeader( + row.New(40).Add( + image.NewFromFileCol(4, "docs/assets/images/gopherbw.png", props.Rect{ + Center: true, + Percent: 50, + }), + text.NewCol(4, "Margins Test", props.Text{ + Top: 12, + Size: 12, + }), + col.New(4), + ), ) + if err != nil { + log.Fatal(err) + } + + for i := 0; i < 10; i++ { + m.AddRows(text.NewRow(30, "any text")) + } return m } diff --git a/docs/assets/pdf/backgroundv2.pdf b/docs/assets/pdf/backgroundv2.pdf index c0ac92d6..4c4405bb 100644 Binary files a/docs/assets/pdf/backgroundv2.pdf and b/docs/assets/pdf/backgroundv2.pdf differ diff --git a/docs/assets/pdf/marginsv2.pdf b/docs/assets/pdf/marginsv2.pdf index 071bec0d..6db16fa7 100644 Binary files a/docs/assets/pdf/marginsv2.pdf and b/docs/assets/pdf/marginsv2.pdf differ diff --git a/docs/assets/text/backgroundv2.txt b/docs/assets/text/backgroundv2.txt index ce5728ad..c4ceaa31 100644 --- a/docs/assets/text/backgroundv2.txt +++ b/docs/assets/text/backgroundv2.txt @@ -1,3 +1,3 @@ -generate -> avg: 2169.54ms, executions: [2169.54ms] -add_page -> avg: 8596.00ns, executions: [8.60μs] +generate -> avg: 541.29ms, executions: [541.29ms] +add_page -> avg: 2216.00ns, executions: [2.22μs] file_size -> 897.39Kb diff --git a/docs/assets/text/marginsv2.txt b/docs/assets/text/marginsv2.txt index 0dd16139..50b27b11 100644 --- a/docs/assets/text/marginsv2.txt +++ b/docs/assets/text/marginsv2.txt @@ -1,3 +1,4 @@ -generate -> avg: 605.72ms, executions: [605.72ms] -add_row -> avg: 1543.00ns, executions: [1.54μs] -file_size -> 253.43Kb +generate -> avg: 356.27ms, executions: [356.27ms] +header -> avg: 549.00ns, executions: [549.00ns] +add_rows -> avg: 94.10ns, executions: [131.00ns, 54.00ns, 26.00ns, 83.00ns, 16.00ns, 16.00ns, 16.00ns, 76.00ns, 478.00ns, 45.00ns] +file_size -> 256.71Kb diff --git a/internal/providers/gofpdf/builder.go b/internal/providers/gofpdf/builder.go index 400df19d..6aa59f2e 100644 --- a/internal/providers/gofpdf/builder.go +++ b/internal/providers/gofpdf/builder.go @@ -55,6 +55,8 @@ func (b *builder) Build(cfg *entity.Config, cache cache.Cache) *Dependencies { if cfg.DisableAutoPageBreak { fpdf.SetAutoPageBreak(false, 0) + } else { + fpdf.SetAutoPageBreak(true, cfg.Margins.Bottom) } fpdf.SetMargins(cfg.Margins.Left, cfg.Margins.Top, cfg.Margins.Right) diff --git a/internal/providers/gofpdf/builder_test.go b/internal/providers/gofpdf/builder_test.go index ca5e6581..1308eaab 100644 --- a/internal/providers/gofpdf/builder_test.go +++ b/internal/providers/gofpdf/builder_test.go @@ -5,9 +5,10 @@ import ( "testing" "github.com/johnfercher/maroto/v2/internal/fixture" - "github.com/johnfercher/maroto/v2/internal/providers/gofpdf" "github.com/johnfercher/maroto/v2/pkg/consts/fontfamily" "github.com/johnfercher/maroto/v2/pkg/core/entity" + + "github.com/johnfercher/maroto/v2/internal/providers/gofpdf" "github.com/stretchr/testify/assert" ) @@ -21,32 +22,64 @@ func TestNewBuilder(t *testing.T) { } func TestBuilder_Build(t *testing.T) { - // Arrange - sut := gofpdf.NewBuilder() - font := fixture.FontProp() - cfg := &entity.Config{ - Dimensions: &entity.Dimensions{ - Width: 100, - Height: 200, - }, - Margins: &entity.Margins{ - Left: 10, - Top: 10, - Right: 10, - Bottom: 10, - }, - DefaultFont: &font, - CustomFonts: []*entity.CustomFont{ - { - Family: fontfamily.Arial, + t.Run("when DisableAutoPageBreak true, should build correctly", func(t *testing.T) { + // Arrange + sut := gofpdf.NewBuilder() + font := fixture.FontProp() + cfg := &entity.Config{ + Dimensions: &entity.Dimensions{ + Width: 100, + Height: 200, }, - }, - DisableAutoPageBreak: true, - } + Margins: &entity.Margins{ + Left: 10, + Top: 10, + Right: 10, + Bottom: 10, + }, + DefaultFont: &font, + CustomFonts: []*entity.CustomFont{ + { + Family: fontfamily.Arial, + }, + }, + DisableAutoPageBreak: true, + } - // Act - dep := sut.Build(cfg, nil) + // Act + dep := sut.Build(cfg, nil) - // Assert - assert.NotNil(t, dep) + // Assert + assert.NotNil(t, dep) + }) + t.Run("when DisableAutoPageBreak false, should build correctly", func(t *testing.T) { + // Arrange + sut := gofpdf.NewBuilder() + font := fixture.FontProp() + cfg := &entity.Config{ + Dimensions: &entity.Dimensions{ + Width: 100, + Height: 200, + }, + Margins: &entity.Margins{ + Left: 10, + Top: 10, + Right: 10, + Bottom: 10, + }, + DefaultFont: &font, + CustomFonts: []*entity.CustomFont{ + { + Family: fontfamily.Arial, + }, + }, + DisableAutoPageBreak: false, + } + + // Act + dep := sut.Build(cfg, nil) + + // Assert + assert.NotNil(t, dep) + }) } diff --git a/pkg/config/builder.go b/pkg/config/builder.go index 884678e0..536c1714 100644 --- a/pkg/config/builder.go +++ b/pkg/config/builder.go @@ -25,7 +25,10 @@ import ( type Builder interface { WithPageSize(size pagesize.Type) Builder WithDimensions(width float64, height float64) Builder - WithMargins(left float64, top float64, right float64) Builder + WithLeftMargin(left float64) Builder + WithTopMargin(top float64) Builder + WithRightMargin(right float64) Builder + WithBottomMargin(bottom float64) Builder WithConcurrentMode(chunkWorkers int) Builder WithSequentialMode() Builder WithSequentialLowMemoryMode(chunkWorkers int) Builder @@ -114,24 +117,43 @@ func (b *CfgBuilder) WithDimensions(width float64, height float64) Builder { return b } -// WithMargins defines custom margins, bottom margin is not customizable due to gofpdf limitations. -func (b *CfgBuilder) WithMargins(left float64, top float64, right float64) Builder { +// WithLeftMargin customize margin. +func (b *CfgBuilder) WithLeftMargin(left float64) Builder { if left < pagesize.MinLeftMargin { return b } - if top < pagesize.MinRightMargin { + b.margins.Left = left + return b +} + +// WithTopMargin customize margin. +func (b *CfgBuilder) WithTopMargin(top float64) Builder { + if top < pagesize.MinTopMargin { return b } - if right < pagesize.MinTopMargin { + b.margins.Top = top + return b +} + +// WithRightMargin customize margin. +func (b *CfgBuilder) WithRightMargin(right float64) Builder { + if right < pagesize.MinRightMargin { return b } - b.margins.Left = left - b.margins.Top = top b.margins.Right = right + return b +} + +// WithBottomMargin customize margin. +func (b *CfgBuilder) WithBottomMargin(bottom float64) Builder { + if bottom < pagesize.MinBottomMargin { + return b + } + b.margins.Bottom = bottom return b } diff --git a/pkg/config/builder_test.go b/pkg/config/builder_test.go index 88e0560f..b9b9cae4 100644 --- a/pkg/config/builder_test.go +++ b/pkg/config/builder_test.go @@ -135,54 +135,95 @@ func TestBuilder_WithDimensions(t *testing.T) { }) } -func TestBuilder_WithMargins(t *testing.T) { - t.Run("when margins has invalid left, should not change the default value", func(t *testing.T) { +func TestCfgBuilder_WithTopMargin(t *testing.T) { + t.Run("when top is invalid, should not change the default value", func(t *testing.T) { // Arrange sut := config.NewBuilder() // Act - cfg := sut.WithMargins(-1, 20, 20).Build() + cfg := sut.WithTopMargin(-1).Build() // Assert - assert.Equal(t, 10.0, cfg.Margins.Left) assert.Equal(t, 10.0, cfg.Margins.Top) - assert.Equal(t, 10.0, cfg.Margins.Right) }) - t.Run("when margins has invalid right, should not change the default value", func(t *testing.T) { + t.Run("when top is valid, should change the default value", func(t *testing.T) { // Arrange sut := config.NewBuilder() // Act - cfg := sut.WithMargins(20, 20, -1).Build() + cfg := sut.WithTopMargin(5).Build() // Assert - assert.Equal(t, 10.0, cfg.Margins.Left) - assert.Equal(t, 10.0, cfg.Margins.Top) - assert.Equal(t, 10.0, cfg.Margins.Right) + assert.Equal(t, 5.0, cfg.Margins.Top) }) - t.Run("when margins has invalid top, should not change the default value", func(t *testing.T) { +} + +func TestCfgBuilder_WithLeftMargin(t *testing.T) { + t.Run("when left is invalid, should not change the default value", func(t *testing.T) { // Arrange sut := config.NewBuilder() // Act - cfg := sut.WithMargins(20, -1, 20).Build() + cfg := sut.WithLeftMargin(-1).Build() // Assert assert.Equal(t, 10.0, cfg.Margins.Left) - assert.Equal(t, 10.0, cfg.Margins.Top) + }) + t.Run("when left is valid, should change the default value", func(t *testing.T) { + // Arrange + sut := config.NewBuilder() + + // Act + cfg := sut.WithLeftMargin(5).Build() + + // Assert + assert.Equal(t, 5.0, cfg.Margins.Left) + }) +} + +func TestCfgBuilder_WithRightMargin(t *testing.T) { + t.Run("when right is invalid, should not change the default value", func(t *testing.T) { + // Arrange + sut := config.NewBuilder() + + // Act + cfg := sut.WithRightMargin(-1).Build() + + // Assert assert.Equal(t, 10.0, cfg.Margins.Right) }) - t.Run("when dimensions has valid values, should change the default value", func(t *testing.T) { + t.Run("when right is valid, should change the default value", func(t *testing.T) { + // Arrange + sut := config.NewBuilder() + + // Act + cfg := sut.WithRightMargin(5).Build() + + // Assert + assert.Equal(t, 5.0, cfg.Margins.Right) + }) +} + +func TestCfgBuilder_WithBottomMargin(t *testing.T) { + t.Run("when bottom is invalid, should not change the default value", func(t *testing.T) { + // Arrange + sut := config.NewBuilder() + + // Act + cfg := sut.WithBottomMargin(-1).Build() + + // Assert + assert.Equal(t, 20.0025, cfg.Margins.Bottom) + }) + t.Run("when bottom is valid, should change the default value", func(t *testing.T) { // Arrange sut := config.NewBuilder() // Act - cfg := sut.WithMargins(20, 20, 20).Build() + cfg := sut.WithBottomMargin(5).Build() // Assert - assert.Equal(t, 20.0, cfg.Margins.Left) - assert.Equal(t, 20.0, cfg.Margins.Top) - assert.Equal(t, 20.0, cfg.Margins.Right) + assert.Equal(t, 5.0, cfg.Margins.Bottom) }) } diff --git a/pkg/config/example_test.go b/pkg/config/example_test.go index 8be56694..4e83dbee 100644 --- a/pkg/config/example_test.go +++ b/pkg/config/example_test.go @@ -36,11 +36,47 @@ func ExampleCfgBuilder_WithPageSize() { // generate document } -// ExampleCfgBuilder_WithMargins demonstrates how to customize margins -func ExampleCfgBuilder_WithMargins() { - // If any margins is smaller than zero, then ignore customization. +// ExampleCfgBuilder_WithTopMargin demonstrates how to customize margin. +func ExampleCfgBuilder_WithTopMargin() { + // If top less than minimum, ignore customization. cfg := config.NewBuilder(). - WithMargins(5, 5, 5). + WithTopMargin(15). + Build() + + _ = maroto.New(cfg) + + // generate document +} + +// ExampleCfgBuilder_WithRightMargin demonstrates how to customize margin. +func ExampleCfgBuilder_WithRightMargin() { + // If top less than minimum, ignore customization. + cfg := config.NewBuilder(). + WithRightMargin(15). + Build() + + _ = maroto.New(cfg) + + // generate document +} + +// ExampleCfgBuilder_WithLeftMargin demonstrates how to customize margin. +func ExampleCfgBuilder_WithLeftMargin() { + // If top less than minimum, ignore customization. + cfg := config.NewBuilder(). + WithLeftMargin(15). + Build() + + _ = maroto.New(cfg) + + // generate document +} + +// ExampleCfgBuilder_WithBottomMargin demonstrates how to customize margin. +func ExampleCfgBuilder_WithBottomMargin() { + // If top less than minimum, ignore customization. + cfg := config.NewBuilder(). + WithBottomMargin(15). Build() _ = maroto.New(cfg) diff --git a/pkg/consts/pagesize/size.go b/pkg/consts/pagesize/size.go index 87cabedb..5351512d 100644 --- a/pkg/consts/pagesize/size.go +++ b/pkg/consts/pagesize/size.go @@ -30,7 +30,7 @@ const ( // DefaultRightMargin represents the default right margin in page size. DefaultRightMargin = 10.0 // DefaultBottomMargin represents the default bottom margin in page size. - DefaultBottomMargin = MinBottomMargin + DefaultBottomMargin = 20.0025 // MinTopMargin represents the minimum top margin in page size. MinTopMargin = 0.0 // MinLeftMargin represents the minimum left margin in page size. @@ -38,7 +38,7 @@ const ( // MinRightMargin represents the minimum right margin in page size. MinRightMargin = 0.0 // MinBottomMargin represents the minimum bottom margin in page size. - MinBottomMargin = 20.0025 + MinBottomMargin = 0.0 // DefaultFontSize represents the default font size in page size. DefaultFontSize = 10.0 // DefaultMaxGridSum represents the default max grid sum in page size. diff --git a/test/maroto/examples/margins.json b/test/maroto/examples/margins.json index bd53a232..309a8368 100755 --- a/test/maroto/examples/margins.json +++ b/test/maroto/examples/margins.json @@ -59,7 +59,250 @@ ] }, { - "value": 216.9975, + "value": 30, + "type": "row", + "nodes": [ + { + "value": 0, + "type": "col", + "details": { + "is_max": true + }, + "nodes": [ + { + "value": "any text", + "type": "text" + } + ] + } + ] + }, + { + "value": 30, + "type": "row", + "nodes": [ + { + "value": 0, + "type": "col", + "details": { + "is_max": true + }, + "nodes": [ + { + "value": "any text", + "type": "text" + } + ] + } + ] + }, + { + "value": 30, + "type": "row", + "nodes": [ + { + "value": 0, + "type": "col", + "details": { + "is_max": true + }, + "nodes": [ + { + "value": "any text", + "type": "text" + } + ] + } + ] + }, + { + "value": 30, + "type": "row", + "nodes": [ + { + "value": 0, + "type": "col", + "details": { + "is_max": true + }, + "nodes": [ + { + "value": "any text", + "type": "text" + } + ] + } + ] + }, + { + "value": 30, + "type": "row", + "nodes": [ + { + "value": 0, + "type": "col", + "details": { + "is_max": true + }, + "nodes": [ + { + "value": "any text", + "type": "text" + } + ] + } + ] + }, + { + "value": 30, + "type": "row", + "nodes": [ + { + "value": 0, + "type": "col", + "details": { + "is_max": true + }, + "nodes": [ + { + "value": "any text", + "type": "text" + } + ] + } + ] + }, + { + "value": 30, + "type": "row", + "nodes": [ + { + "value": 0, + "type": "col", + "details": { + "is_max": true + }, + "nodes": [ + { + "value": "any text", + "type": "text" + } + ] + } + ] + }, + { + "value": 6.997500000000002, + "type": "row", + "nodes": [ + { + "value": 12, + "type": "col" + } + ] + } + ] + }, + { + "type": "page", + "nodes": [ + { + "value": 40, + "type": "row", + "nodes": [ + { + "value": 4, + "type": "col", + "nodes": [ + { + "value": "docs/assets/images/gopherbw.png", + "type": "fileImage", + "details": { + "prop_center": true, + "prop_percent": 50 + } + } + ] + }, + { + "value": 4, + "type": "col", + "nodes": [ + { + "value": "Margins Test", + "type": "text", + "details": { + "prop_font_size": 12, + "prop_top": 12 + } + } + ] + }, + { + "value": 4, + "type": "col" + } + ] + }, + { + "value": 30, + "type": "row", + "nodes": [ + { + "value": 0, + "type": "col", + "details": { + "is_max": true + }, + "nodes": [ + { + "value": "any text", + "type": "text" + } + ] + } + ] + }, + { + "value": 30, + "type": "row", + "nodes": [ + { + "value": 0, + "type": "col", + "details": { + "is_max": true + }, + "nodes": [ + { + "value": "any text", + "type": "text" + } + ] + } + ] + }, + { + "value": 30, + "type": "row", + "nodes": [ + { + "value": 0, + "type": "col", + "details": { + "is_max": true + }, + "nodes": [ + { + "value": "any text", + "type": "text" + } + ] + } + ] + }, + { + "value": 126.9975, "type": "row", "nodes": [ {