github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/core/utils/pdf/pdfutils.go (about)

     1  package pdf
     2  
     3  import (
     4  	"fmt"
     5  	"path/filepath"
     6  	"strings"
     7  	"time"
     8  
     9  	rd "github.com/benoitkugler/goACVE/server/core/rawdata"
    10  
    11  	"github.com/jung-kurt/gofpdf"
    12  )
    13  
    14  // ------------------------------------ Helpers ------------------------------------
    15  type rgb [3]int
    16  
    17  type CustomPdf struct {
    18  	*gofpdf.Fpdf
    19  	Tr func(string) string
    20  }
    21  
    22  // renvoie un pdf prêt à l'emploi (footer et page prête)
    23  func InitPdfDetails(addPage bool, footerOnlyLastPage bool) CustomPdf {
    24  	pdf := gofpdf.New("P", "mm", "A4", "")
    25  	pdf.SetFont("Arial", "", 12)
    26  	pdf.SetMargins(sideMargin, marginTop, -1)
    27  	mypdf := CustomPdf{Fpdf: pdf, Tr: pdf.UnicodeTranslatorFromDescriptor("")}
    28  	if footerOnlyLastPage {
    29  		mypdf.SetFooterFuncLpi(func(lastPage bool) {
    30  			if lastPage {
    31  				mypdf.drawFooter()
    32  			}
    33  		})
    34  	} else {
    35  		mypdf.SetFooterFunc(mypdf.drawFooter)
    36  	}
    37  	if addPage {
    38  		mypdf.AddPage()
    39  	}
    40  	return mypdf
    41  }
    42  
    43  func initPdf() CustomPdf {
    44  	return InitPdfDetails(true, true)
    45  }
    46  
    47  func (pdf CustomPdf) SetFillColor(c rgb) {
    48  	pdf.Fpdf.SetFillColor(c[0], c[1], c[2])
    49  }
    50  
    51  func (pdf CustomPdf) SetDrawColor(c rgb) {
    52  	pdf.Fpdf.SetDrawColor(c[0], c[1], c[2])
    53  }
    54  
    55  func (pdf CustomPdf) insertImage(name string, w, h float64) {
    56  	file := filepath.Join(IMAGES_PATH, name)
    57  	pdf.ImageOptions(file, -1, -1, w, h, true, gofpdf.ImageOptions{}, 0, "")
    58  }
    59  
    60  func (pdf CustomPdf) AreaWidth() float64 {
    61  	w, _ := pdf.GetPageSize()
    62  	mL, _, mR, _ := pdf.GetMargins()
    63  	return w - mL - mR
    64  }
    65  
    66  func (pdf CustomPdf) areaBottomLimit() float64 {
    67  	_, h := pdf.GetPageSize()
    68  	return h - heightFooter - 6
    69  }
    70  
    71  func (pdf CustomPdf) LineHeight() float64 {
    72  	_, lineHeight := pdf.GetFontSize()
    73  	return lineHeight + 1
    74  }
    75  
    76  func (pdf CustomPdf) CellFormat(w, h float64, txtStr, borderStr, alignStr string, fill bool) {
    77  	pdf.Fpdf.CellFormat(w, h, txtStr, borderStr, 0, alignStr, fill, 0, "")
    78  }
    79  
    80  func (pdf CustomPdf) widthNeeded(lines []string) float64 {
    81  	max, addPadding := 0., 5.
    82  	for _, s := range lines {
    83  		w := pdf.GetStringWidth(s)
    84  		if w > max {
    85  			max = w
    86  		}
    87  	}
    88  	return max + addPadding
    89  }
    90  
    91  // ------------------------------------------ Header / Footer ------------------------------------------
    92  
    93  // Attention, len(lignes) <= 5 sinon ca dépasse !
    94  func (pdf CustomPdf) drawHeaderRight(expediteur []string, h float64) {
    95  	lineHeight := pdf.LineHeight()
    96  	padding := (h - lineHeight*float64(len(expediteur))) / 2
    97  	pdf.SetY(pdf.GetY() + padding)
    98  	pdf.MultiCell(pdf.AreaWidth(), lineHeight, pdf.Tr(strings.Join(expediteur, "\n")), "", "RM", false)
    99  }
   100  
   101  // DrawHeader ajoute un header
   102  // `iconWidth` et `iconHeight` peuvent être non nul
   103  // pour forcer une taille d'icône.
   104  func (pdf CustomPdf) DrawHeader(rightHeaderContent []string, iconWidth, iconHeight float64) {
   105  	pdf.SetY(pdf.GetY() + paddingHeaderTop)
   106  	oldY := pdf.GetY()
   107  	pdf.insertImage("app.png", iconWidth, iconHeight)
   108  	y, h := pdf.GetY(), pdf.GetY()-oldY
   109  	pdf.SetY(oldY)
   110  	pdf.drawHeaderRight(rightHeaderContent, h)
   111  	pdf.SetY(y)
   112  }
   113  
   114  func (pdf CustomPdf) drawFooter() {
   115  	h := pdf.HTMLBasicNew()
   116  	pdf.SetFontSize(10)
   117  	_, _, mR, _ := pdf.GetMargins()
   118  	rondsWidth, rondsHeight := 70., 6.
   119  
   120  	pdf.SetY(-heightFooter)
   121  	pdf.SetFillColor(secondaryColor)
   122  	pdf.SetTextColor(0, 0, 0)
   123  	pdf.CellFormat(0, 17, "", "", "", true)
   124  	pdf.SetXY(-(rondsWidth + mR + 2), -heightFooter-(rondsHeight/2))
   125  	pdf.insertImage("ronds.png", rondsWidth, rondsHeight)
   126  	pdf.SetY(-15)
   127  	pdf.SetLeftMargin(sideMargin + paddingFooter)
   128  	pdf.SetRightMargin(sideMargin + paddingFooter)
   129  	h.Write(4, pdf.Tr(rd.Asso.Title))
   130  	pdf.Ln(-1)
   131  	pdf.SetFontSize(9)
   132  	h.Write(4, pdf.Tr(rd.Asso.Infos))
   133  	pdf.Ln(-1)
   134  	pdf.SetFontSize(7.5)
   135  	h.Write(3, pdf.Tr(rd.Asso.Details))
   136  }
   137  
   138  // ------------------------ Zone titre / destinataire ------------------------
   139  func formatAdresse(s string) []string {
   140  	var outs []string
   141  	for _, line := range strings.Split(s, "\n") {
   142  		trim := strings.TrimSpace(line)
   143  		if trim != "" {
   144  			outs = append(outs, trim)
   145  		}
   146  	}
   147  	return outs
   148  }
   149  
   150  func (pdf CustomPdf) drawBandeDestinataire(titre string, dest rd.Destinataire) {
   151  	titreWidth, titreHeight, spacingDate := 60., 10., 2.
   152  	y := pdf.GetY() + spacingHeader
   153  	pdf.SetY(y)
   154  	pdf.SetDrawColor(primaryColor)
   155  	pdf.SetLineWidth(0.8)
   156  	pdf.ClipRoundedRect(pdf.GetX(), y, titreWidth, titreHeight, 4, true)
   157  	pdf.CellFormat(titreWidth, titreHeight, pdf.Tr(titre), "", "CM", false)
   158  	pdf.ClipEnd()
   159  	pdf.SetY(y + titreHeight + spacingDate)
   160  	now := time.Now()
   161  	pdf.SetFont("Arial", "I", 10)
   162  	pdf.CellFormat(titreWidth, 5, fmt.Sprintf("Edition au %d/%d/%d", now.Day(), now.Month(), now.Year()), "", "CM", false)
   163  
   164  	pdf.SetFont("Arial", "", 13)
   165  	codePostalVille := strings.TrimSpace(dest.CodePostal.String()) + " " + strings.TrimSpace(dest.Ville.ToUpper())
   166  	adresseLines := formatAdresse(dest.Adresse.String())
   167  	lines := append(append([]string{dest.NomPrenom.String()}, adresseLines...), codePostalVille)
   168  	neededWidth, neededHeight := pdf.widthNeeded(lines), pdf.LineHeight()*float64(len(lines))
   169  	x, paddingTop, paddingRight := pdf.AreaWidth()-neededWidth, 2., 3.
   170  	pdf.SetDrawColor(secondaryColor)
   171  	pdf.ClipRoundedRect(x, y, neededWidth+paddingRight, neededHeight+3, 5, true)
   172  	pdf.SetXY(x, y+paddingTop)
   173  	pdf.MultiCell(neededWidth, pdf.LineHeight(), pdf.Tr(strings.Join(lines, "\n")), "", "R", false)
   174  	pdf.ClipEnd()
   175  	pdf.Ln(spacingBandeDestinataire)
   176  	pdf.SetDrawColor(rgb{0, 0, 0})
   177  	pdf.SetLineWidth(0.2)
   178  }