Skip to content

Instantly share code, notes, and snippets.

@Lioncat2002
Created February 18, 2024 05:28
Show Gist options
  • Save Lioncat2002/f40306aba45ccafe39dcceca294f50dc to your computer and use it in GitHub Desktop.
Save Lioncat2002/f40306aba45ccafe39dcceca294f50dc to your computer and use it in GitHub Desktop.
pdf_utils
package utils
import (
"bytes"
"errors"
"io"
"log"
"time"
"github.com/LegalForceLawRAPC/notarysign/common/schemas"
"github.com/LegalForceLawRAPC/notarysign/config"
"github.com/LegalForceLawRAPC/notarysign/pkg/models"
"github.com/phpdave11/gofpdi"
"github.com/signintech/gopdf"
)
var pdf *gopdf.GoPdf
func InitGoPdf() *gopdf.GoPdf {
pdf := &gopdf.GoPdf{}
pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4})
fontData, err := config.Content.ReadFile("fonts/OpenSans-Regular.ttf")
if err != nil {
log.Panicln(err)
}
if err := pdf.AddTTFFontData("open-sans", fontData); err != nil {
log.Panicln(err)
}
fontData, err = config.Content.ReadFile("fonts/AmericanSignature.ttf")
if err != nil {
log.Panicln(err)
}
if err := pdf.AddTTFFontData("american-signature", fontData); err != nil {
log.Panicln(err)
}
fontData, err = config.Content.ReadFile("fonts/Angelina.ttf")
if err != nil {
log.Panicln(err)
}
if err := pdf.AddTTFFontData("angelina", fontData); err != nil {
log.Panicln(err)
}
fontData, err = config.Content.ReadFile("fonts/Autograf.ttf")
if err != nil {
log.Panicln(err)
}
if err := pdf.AddTTFFontData("autograf", fontData); err != nil {
log.Panicln(err)
}
fontData, err = config.Content.ReadFile("fonts/Autography.ttf")
if err != nil {
log.Panicln(err)
}
if err := pdf.AddTTFFontData("autography", fontData); err != nil {
log.Panicln(err)
}
fontData, err = config.Content.ReadFile("fonts/Mitchel.ttf")
if err != nil {
log.Panicln(err)
}
if err := pdf.AddTTFFontData("mitchel", fontData); err != nil {
log.Panicln(err)
}
fontData, err = config.Content.ReadFile("fonts/SevenDaySignature.ttf")
if err != nil {
log.Panicln(err)
}
if err := pdf.AddTTFFontData("sevenday-signature", fontData); err != nil {
log.Panicln(err)
}
return pdf
}
func GetTotalPdfPages(pdfBuf []byte) int {
pdf = InitGoPdf()
importer := gofpdi.NewImporter()
pdfReader := bytes.NewReader(pdfBuf)
r := io.ReadSeeker(pdfReader)
importer.SetSourceStream(&r)
totalPagesOfPdf := importer.GetNumPages()
return totalPagesOfPdf
}
func AddPageToPDF(pdfBuf []byte, pageNumber int) ([]byte, error) {
pdf = InitGoPdf()
importer := gofpdi.NewImporter()
pdfReader := bytes.NewReader(pdfBuf)
r := io.ReadSeeker(pdfReader)
importer.SetSourceStream(&r)
totalPagesOfPdf := importer.GetNumPages()
for i := 0; i < totalPagesOfPdf; i++ {
importedPage := pdf.ImportPageStream(&r, i+1, "/MediaBox")
data := importer.GetPageSizes()
pageWidth := data[i+1]["/MediaBox"]["w"]
pageHeight := data[i+1]["/MediaBox"]["h"]
pdf.AddPageWithOption(gopdf.PageOption{PageSize: &gopdf.Rect{W: pageWidth, H: pageHeight}})
pdf.UseImportedTemplate(importedPage, 0, 0, pageWidth, pageHeight)
if pageNumber == i+1 {
pdf.AddPage()
//pdf.AddPageWithOption(gopdf.PageOption{PageSize: &gopdf.Rect{W: pageWidth, H: pageHeight}})
}
}
var newPDFBuf bytes.Buffer
_, err := pdf.WriteTo(&newPDFBuf)
if err != nil {
return nil, err
}
return newPDFBuf.Bytes(), nil
}
func DuplicatePageFromPDF(pdfBuf []byte, pageNumber int) ([]byte, error) {
pdf = InitGoPdf()
importer := gofpdi.NewImporter()
pdfReader := bytes.NewReader(pdfBuf)
r := io.ReadSeeker(pdfReader)
importer.SetSourceStream(&r)
totalPagesOfPdf := importer.GetNumPages()
for i := 0; i < totalPagesOfPdf; i++ {
importedPage := pdf.ImportPageStream(&r, i+1, "/MediaBox")
data := importer.GetPageSizes()
pageWidth := data[i+1]["/MediaBox"]["w"]
pageHeight := data[i+1]["/MediaBox"]["h"]
pdf.AddPageWithOption(gopdf.PageOption{PageSize: &gopdf.Rect{W: pageWidth, H: pageHeight}})
pdf.UseImportedTemplate(importedPage, 0, 0, pageWidth, pageHeight)
if pageNumber == i+1 {
pdf.AddPageWithOption(gopdf.PageOption{PageSize: &gopdf.Rect{W: pageWidth, H: pageHeight}})
pdf.UseImportedTemplate(importedPage, 0, 0, pageWidth, pageHeight)
}
}
var newPDFBuf bytes.Buffer
_, err := pdf.WriteTo(&newPDFBuf)
if err != nil {
return nil, err
}
return newPDFBuf.Bytes(), nil
}
func DeletePageFromPDF(pdfBuf []byte, pageNumber int) ([]byte, error) {
pdf = InitGoPdf()
importer := gofpdi.NewImporter()
pdfReader := bytes.NewReader(pdfBuf)
r := io.ReadSeeker(pdfReader)
if r == nil {
return nil, errors.New("failed to read pdf")
}
importer.SetSourceStream(&r)
totalPagesOfPdf := importer.GetNumPages()
for i := 0; i < totalPagesOfPdf; i++ {
if pageNumber != i+1 {
importedPage := pdf.ImportPageStream(&r, i+1, "/MediaBox")
data := importer.GetPageSizes()
pageWidth := data[i+1]["/MediaBox"]["w"]
pageHeight := data[i+1]["/MediaBox"]["h"]
pdf.AddPageWithOption(gopdf.PageOption{PageSize: &gopdf.Rect{W: pageWidth, H: pageHeight}})
pdf.UseImportedTemplate(importedPage, 0, 0, pageWidth, pageHeight)
}
}
var newPDFBuf bytes.Buffer
_, err := pdf.WriteTo(&newPDFBuf)
if err != nil {
return nil, err
}
return newPDFBuf.Bytes(), nil
}
func MergePDFs(pdfBufs [][]byte) ([]byte, error) {
// Merge PDFs in memory
pdf = InitGoPdf()
importer := gofpdi.NewImporter()
for _, pdfBuf := range pdfBufs {
if pdfBuf == nil {
return nil, errors.New("failed to merge pdf")
}
pdfReader := bytes.NewReader(pdfBuf)
r := io.ReadSeeker(pdfReader)
importer.SetSourceStream(&r)
totalPagesOfPdf := importer.GetNumPages()
for i := 0; i < totalPagesOfPdf; i++ {
importedPage := pdf.ImportPageStream(&r, i+1, "/MediaBox")
data := importer.GetPageSizes()
pageWidth := data[i+1]["/MediaBox"]["w"]
pageHeight := data[i+1]["/MediaBox"]["h"]
pdf.AddPageWithOption(gopdf.PageOption{PageSize: &gopdf.Rect{W: pageWidth, H: pageHeight}})
pdf.UseImportedTemplate(importedPage, 0, 0, pageWidth, pageHeight)
}
}
var mergedPDFBuf bytes.Buffer
_, err := pdf.WriteTo(&mergedPDFBuf)
if err != nil {
return nil, err
}
return mergedPDFBuf.Bytes(), nil
}
func GenerateSignedPdf(pdfBuf []byte, documentFields []schemas.DocumentFieldFetchData) ([]byte, error) {
pdf = InitGoPdf()
importer := gofpdi.NewImporter()
pdfReader := bytes.NewReader(pdfBuf)
r := io.ReadSeeker(pdfReader)
importer.SetSourceStream(&r)
totalPagesOfPdf := importer.GetNumPages()
for i := 0; i < totalPagesOfPdf; i++ {
importedPage := pdf.ImportPageStream(&r, i+1, "/MediaBox")
data := importer.GetPageSizes()
pageWidth := data[i+1]["/MediaBox"]["w"]
pageHeight := data[i+1]["/MediaBox"]["h"]
pdf.AddPageWithOption(gopdf.PageOption{PageSize: &gopdf.Rect{W: pageWidth, H: pageHeight}})
pdf.UseImportedTemplate(importedPage, 0, 0, pageWidth, pageHeight)
for _, field := range documentFields {
if field.PageNumber == i+1 {
if field.Signature != "" {
img, err := GetObjectContentInS3(field.Signature)
if err != nil {
return nil, err
}
imgHolder, err := gopdf.ImageHolderByBytes(img)
if err != nil {
return nil, err
}
pdf.ImageByHolder(imgHolder, field.X, field.Y, &gopdf.Rect{W: field.Width, H: field.Height})
} else if field.StringSignature != "" {
pdf.SetXY(field.X, field.Y)
pdf.SetFont("open-sans", "", field.FontSize)
err := pdf.Text(field.StringSignature)
if err != nil {
return nil, err
}
}
}
}
}
var signedPDFBuf bytes.Buffer
_, err := pdf.WriteTo(&signedPDFBuf)
if err != nil {
return nil, err
}
return signedPDFBuf.Bytes(), nil
}
func GenerateSignerCertificate(documentFields []schemas.DocumentFieldFetchData) ([]byte, error) {
pdf = InitGoPdf()
y := 100.0
pdf.AddPage()
if err := pdf.SetFont("open-sans", "", 12); err != nil {
return nil, err
}
if err := drawCell(pdf, "Name\tTimestamp\tSignature", 20, y); err != nil {
return nil, err
}
for i, field := range documentFields {
if err := pdf.SetFont("open-sans", "", 12); err != nil {
return nil, err
}
if err := drawCell(pdf, field.AssigneeName, 20, y); err != nil {
return nil, err
}
if err := pdf.SetFont("open-sans", "", 8); err != nil {
return nil, err
}
time := time.Unix(int64(field.UpdatedAt), 0)
if err := drawCell(pdf, time.UTC().String(), 120, y); err != nil {
return nil, err
}
if field.StringSignature != "" {
if err := pdf.SetFont("open-sans", "", 12); err != nil {
return nil, err
}
if err := drawCell(pdf, field.StringSignature, 360, y); err != nil {
return nil, err
}
} else if field.Signature != "" {
if err := drawImage(pdf, field.Signature, 360, y, field.Width, field.Height); err != nil {
return nil, err
}
}
y += 30
if (i+1)%3 == 0 && i != len(documentFields)-1 {
pdf.AddPage()
y = 100.0 // Reset Y position for the next page
}
}
var signerCertificateBuf bytes.Buffer
_, err := pdf.WriteTo(&signerCertificateBuf)
if err != nil {
return nil, err
}
return signerCertificateBuf.Bytes(), nil
}
func GenerateAttachmentPdf(pdfBuf []byte, attachments []models.Attachment) ([]byte, error) {
pdf = InitGoPdf()
importer := gofpdi.NewImporter()
pdfReader := bytes.NewReader(pdfBuf)
r := io.ReadSeeker(pdfReader)
importer.SetSourceStream(&r)
totalPagesOfPdf := importer.GetNumPages()
for i := 0; i < totalPagesOfPdf; i++ {
importedPage := pdf.ImportPageStream(&r, i+1, "/MediaBox")
data := importer.GetPageSizes()
pageWidth := data[i+1]["/MediaBox"]["w"]
pageHeight := data[i+1]["/MediaBox"]["h"]
pdf.AddPageWithOption(gopdf.PageOption{PageSize: &gopdf.Rect{W: pageWidth, H: pageHeight}})
pdf.UseImportedTemplate(importedPage, 0, 0, pageWidth, pageHeight)
for _, attachment := range attachments {
if attachment.PageNumber == i+1 {
img, err := GetObjectContentInS3(attachment.AttachmentS3Key)
if err != nil {
return nil, err
}
imgHolder, err := gopdf.ImageHolderByBytes(img)
if err != nil {
return nil, err
}
pdf.ImageByHolder(imgHolder, attachment.X, attachment.Y, &gopdf.Rect{W: attachment.Width, H: attachment.Height})
}
}
}
var attachmentPDFBuf bytes.Buffer
_, err := pdf.WriteTo(&attachmentPDFBuf)
if err != nil {
return nil, err
}
return attachmentPDFBuf.Bytes(), nil
}
func drawCell(pdf *gopdf.GoPdf, text string, x, y float64) error {
pdf.SetXY(x, y)
err := pdf.Cell(nil, text)
if err != nil {
return err
}
return nil
}
func drawImage(pdf *gopdf.GoPdf, key string, x, y, w, h float64) error {
img, err := GetObjectContentInS3(key)
if err != nil {
return err
}
imgHolder, err := gopdf.ImageHolderByBytes(img)
if err != nil {
return err
}
pdf.ImageByHolder(imgHolder, x, y, &gopdf.Rect{W: w, H: h})
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment