Skip to content

Commit

Permalink
Refactor image (#327)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnfercher authored Oct 1, 2023
1 parent fd3b1b0 commit 10de07b
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 61 deletions.
Binary file modified docs/assets/pdf/imagegridv2.pdf
Binary file not shown.
4 changes: 2 additions & 2 deletions docs/assets/text/imagegridv2.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
generate -> avg: 3.48ms, executions: [3.48ms]
add_cols -> avg: 153.00ns, executions: [361.00ns, 138.00ns, 120.00ns, 64.00ns, 159.00ns, 76.00ns]
generate -> avg: 3.35ms, executions: [3.35ms]
add_cols -> avg: 168.00ns, executions: [496.00ns, 137.00ns, 121.00ns, 69.00ns, 119.00ns, 66.00ns]
file_size -> 222.72Kb
29 changes: 20 additions & 9 deletions internal/code/code.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package code

import (
"bytes"
image2 "image"
"image"
"image/jpeg"

"github.com/johnfercher/maroto/v2/pkg/consts/extension"

"github.com/johnfercher/maroto/v2/pkg/core/entity"

"github.com/boombuler/barcode"
Expand All @@ -22,27 +24,27 @@ func New() *code {
}

// GenDataMatrix is responsible to generate a data matrix byte array.
func (c *code) GenDataMatrix(code string) ([]byte, error) {
func (c *code) GenDataMatrix(code string) (*entity.Image, error) {
dataMatrix, err := datamatrix.Encode(code)
if err != nil {
return nil, err
}

return c.getBytes(dataMatrix)
return c.getImage(dataMatrix)
}

// GenQr is responsible to generate a qr code byte array.
func (c *code) GenQr(code string) ([]byte, error) {
func (c *code) GenQr(code string) (*entity.Image, error) {
qrCode, err := qr.Encode(code, qr.M, qr.Auto)
if err != nil {
return nil, err
}

return c.getBytes(qrCode)
return c.getImage(qrCode)
}

// GenBar is responsible to generate a barcode byte array.
func (c *code) GenBar(code string, cell *entity.Cell, prop *props.Barcode) ([]byte, error) {
func (c *code) GenBar(code string, cell *entity.Cell, prop *props.Barcode) (*entity.Image, error) {
barCode, err := code128.Encode(code)
if err != nil {
return nil, err
Expand All @@ -63,15 +65,24 @@ func (c *code) GenBar(code string, cell *entity.Cell, prop *props.Barcode) ([]by
return nil, err
}

return c.getBytes(scaledBarCode)
return c.getImage(scaledBarCode)
}

func (c *code) getBytes(img image2.Image) ([]byte, error) {
func (c *code) getImage(img image.Image) (*entity.Image, error) {
var buf bytes.Buffer
err := jpeg.Encode(&buf, img, nil)
if err != nil {
return nil, err
}

return buf.Bytes(), nil
imgEntity := &entity.Image{
Bytes: buf.Bytes(),
Extension: extension.Jpg,
Dimensions: &entity.Dimensions{
Width: float64(img.Bounds().Dx()),
Height: float64(img.Bounds().Dy()),
},
}

return imgEntity, nil
}
6 changes: 3 additions & 3 deletions internal/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import (
"errors"

"github.com/johnfercher/maroto/v2/pkg/core/entity"
"github.com/jung-kurt/gofpdf"

"github.com/johnfercher/maroto/v2/pkg/core"

"github.com/google/uuid"
"github.com/johnfercher/maroto/v2/internal/fpdf"
"github.com/johnfercher/maroto/v2/pkg/consts/extension"
"github.com/johnfercher/maroto/v2/pkg/props"
"github.com/jung-kurt/gofpdf"
)

type image struct {
Expand All @@ -29,7 +29,7 @@ func NewImage(pdf fpdf.Fpdf, math core.Math) *image {
}

// Add use a byte array to add image to PDF.
func (s *image) Add(imgBytes []byte, cell *entity.Cell, margins *entity.Margins,
func (s *image) Add(img *entity.Image, cell *entity.Cell, margins *entity.Margins,
prop *props.Rect, extension extension.Type, flow bool,
) error {
imageID, _ := uuid.NewRandom()
Expand All @@ -40,7 +40,7 @@ func (s *image) Add(imgBytes []byte, cell *entity.Cell, margins *entity.Margins,
ReadDpi: false,
ImageType: string(extension),
},
bytes.NewReader(imgBytes),
bytes.NewReader(img.Bytes),
)

if info == nil {
Expand Down
20 changes: 5 additions & 15 deletions pkg/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import (
type Cache interface {
GetImage(value string, extension extension.Type) (*entity.Image, error)
LoadImage(value string, extension extension.Type) error
GetCode(code string, codeType string) ([]byte, error)
SaveCode(code string, codeType string, bytes []byte)
AddImage(value string, image *entity.Image)
}

type cache struct {
Expand All @@ -39,6 +38,10 @@ func (c *cache) LoadImage(file string, extension extension.Type) error {
return nil
}

func (c *cache) AddImage(value string, image *entity.Image) {
c.images[value+string(image.Extension)] = image
}

func (c *cache) GetImage(file string, extension extension.Type) (*entity.Image, error) {
image, ok := c.images[file+string(extension)]
if ok {
Expand All @@ -47,16 +50,3 @@ func (c *cache) GetImage(file string, extension extension.Type) (*entity.Image,

return nil, errors.New("image not found")
}

func (c *cache) GetCode(code string, codeType string) ([]byte, error) {
bytes, ok := c.codes[code+codeType]
if ok {
return bytes, nil
}

return nil, errors.New("code not found")
}

func (c *cache) SaveCode(code string, codeType string, bytes []byte) {
c.codes[code+codeType] = bytes
}
18 changes: 6 additions & 12 deletions pkg/cache/mutexcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@ import (
type mutexCache struct {
inner Cache
imageMutex sync.RWMutex
codeMutex sync.RWMutex
}

func NewMutexDecorator(cache Cache) Cache {
return &mutexCache{
inner: cache,
imageMutex: sync.RWMutex{},
codeMutex: sync.RWMutex{},
}
}

Expand All @@ -28,17 +26,13 @@ func (c *mutexCache) LoadImage(file string, extension extension.Type) error {
return c.inner.LoadImage(file, extension)
}

func (c *mutexCache) GetImage(file string, extension extension.Type) (*entity.Image, error) {
return c.inner.GetImage(file, extension)
}
func (c *mutexCache) AddImage(value string, image *entity.Image) {
c.imageMutex.Lock()
defer c.imageMutex.Unlock()

func (c *mutexCache) GetCode(code string, codeType string) ([]byte, error) {
return c.inner.GetCode(code, codeType)
c.inner.AddImage(value, image)
}

func (c *mutexCache) SaveCode(code string, codeType string, bytes []byte) {
c.codeMutex.Lock()
defer c.codeMutex.Unlock()

c.inner.SaveCode(code, codeType, bytes)
func (c *mutexCache) GetImage(file string, extension extension.Type) (*entity.Image, error) {
return c.inner.GetImage(file, extension)
}
19 changes: 19 additions & 0 deletions pkg/components/image/image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package image

import (
"errors"

"github.com/johnfercher/maroto/v2/pkg/consts/extension"
"github.com/johnfercher/maroto/v2/pkg/core/entity"
)

func FromBytes(bytes []byte, ext extension.Type) (*entity.Image, error) {
if !ext.IsValid() {
return nil, errors.New("invalid image format")
}

return &entity.Image{
Bytes: bytes,
Extension: ext,
}, nil
}
4 changes: 4 additions & 0 deletions pkg/consts/extension/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ const (
// Png represents a png extension.
Png Type = "png"
)

func (t Type) IsValid() bool {
return t == Jpg || t == Png
}
8 changes: 4 additions & 4 deletions pkg/core/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ type Math interface {

// Code is the abstraction which deals of how to add QrCodes or Barcode in a PDF.
type Code interface {
GenQr(code string) ([]byte, error)
GenDataMatrix(code string) ([]byte, error)
GenBar(code string, cell *entity.Cell, prop *props.Barcode) ([]byte, error)
GenQr(code string) (*entity.Image, error)
GenDataMatrix(code string) (*entity.Image, error)
GenBar(code string, cell *entity.Cell, prop *props.Barcode) (*entity.Image, error)
}

// Image is the abstraction which deals of how to add images in a PDF.
type Image interface {
Add(imgBytes []byte, cell *entity.Cell, margins *entity.Margins, prop *props.Rect, extension extension.Type, flow bool) error
Add(img *entity.Image, cell *entity.Cell, margins *entity.Margins, prop *props.Rect, extension extension.Type, flow bool) error
}

type Line interface {
Expand Down
5 changes: 3 additions & 2 deletions pkg/core/entity/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package entity
import "github.com/johnfercher/maroto/v2/pkg/consts/extension"

type Image struct {
Bytes []byte
Extension extension.Type
Bytes []byte
Extension extension.Type
Dimensions *Dimensions
}
42 changes: 28 additions & 14 deletions pkg/providers/gofpdf/gofpdf.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"bytes"
"strings"

"github.com/johnfercher/maroto/v2/pkg/components/image"

"github.com/johnfercher/maroto/v2/pkg/core/entity"

"github.com/johnfercher/maroto/v2/internal/code"
Expand Down Expand Up @@ -90,56 +92,56 @@ func (g *gofpdfProvider) AddSignature(text string, cell *entity.Cell, prop *prop
}

func (g *gofpdfProvider) AddMatrixCode(code string, cell *entity.Cell, prop *props.Rect) {
bytes, err := g.cache.GetCode(code, "matrixcode")
image, err := g.cache.GetImage(code, extension.Jpg)
if err != nil {
bytes, err = g.code.GenDataMatrix(code)
image, err = g.code.GenDataMatrix(code)
}

if err != nil {
g.text.Add("could not generate matrixcode", cell, merror.DefaultErrorText)
return
}

g.cache.SaveCode(code, "matrixcode", bytes)
err = g.image.Add(bytes, cell, g.cfg.Margins, prop, extension.Jpg, false)
g.cache.AddImage(code, image)
err = g.image.Add(image, cell, g.cfg.Margins, prop, extension.Jpg, false)
if err != nil {
g.fpdf.ClearError()
g.text.Add("could not add matrixcode to document", cell, merror.DefaultErrorText)
}
}

func (g *gofpdfProvider) AddQrCode(code string, cell *entity.Cell, prop *props.Rect) {
bytes, err := g.cache.GetCode(code, "qrcode")
image, err := g.cache.GetImage(code, extension.Jpg)
if err != nil {
bytes, err = g.code.GenQr(code)
image, err = g.code.GenQr(code)
}

if err != nil {
g.text.Add("could not generate qrcode", cell, merror.DefaultErrorText)
return
}

g.cache.SaveCode(code, "qrcode", bytes)
err = g.image.Add(bytes, cell, g.cfg.Margins, prop, extension.Jpg, false)
g.cache.AddImage(code, image)
err = g.image.Add(image, cell, g.cfg.Margins, prop, extension.Jpg, false)
if err != nil {
g.fpdf.ClearError()
g.text.Add("could not add qrcode to document", cell, merror.DefaultErrorText)
}
}

func (g *gofpdfProvider) AddBarCode(code string, cell *entity.Cell, prop *props.Barcode) {
bytes, err := g.cache.GetCode(code, "barcode")
image, err := g.cache.GetImage(code, extension.Jpg)
if err != nil {
bytes, err = g.code.GenBar(code, cell, prop)
image, err = g.code.GenBar(code, cell, prop)
}

if err != nil {
g.text.Add("could not generate barcode", cell, merror.DefaultErrorText)
return
}

g.cache.SaveCode(code, "barcode", bytes)
err = g.image.Add(bytes, cell, g.cfg.Margins, prop.ToRectProp(), extension.Jpg, false)
g.cache.AddImage(code, image)
err = g.image.Add(image, cell, g.cfg.Margins, prop.ToRectProp(), extension.Jpg, false)
if err != nil {
g.fpdf.ClearError()
g.text.Add("could not add barcode to document", cell, merror.DefaultErrorText)
Expand Down Expand Up @@ -171,15 +173,27 @@ func (g *gofpdfProvider) AddImageFromFile(file string, cell *entity.Cell, prop *
}

func (g *gofpdfProvider) AddImageFromBytes(bytes []byte, cell *entity.Cell, prop *props.Rect, extension extension.Type) {
err := g.image.Add(bytes, cell, g.cfg.Margins, prop, extension, false)
img, err := image.FromBytes(bytes, extension)
if err != nil {
g.fpdf.ClearError()
g.text.Add("could not parse image bytes", cell, merror.DefaultErrorText)
}

err = g.image.Add(img, cell, g.cfg.Margins, prop, extension, false)
if err != nil {
g.fpdf.ClearError()
g.text.Add("could not add image to document", cell, merror.DefaultErrorText)
}
}

func (g *gofpdfProvider) AddBackgroundImageFromBytes(bytes []byte, cell *entity.Cell, prop *props.Rect, extension extension.Type) {
err := g.image.Add(bytes, cell, g.cfg.Margins, prop, extension, true)
img, err := image.FromBytes(bytes, extension)
if err != nil {
g.fpdf.ClearError()
g.text.Add("could not parse image bytes", cell, merror.DefaultErrorText)
}

err = g.image.Add(img, cell, g.cfg.Margins, prop, extension, true)
if err != nil {
g.fpdf.ClearError()
g.text.Add("could not add image to document", cell, merror.DefaultErrorText)
Expand Down

0 comments on commit 10de07b

Please sign in to comment.