summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Barnes <phpdave11@gmail.com>2019-05-15 10:45:22 -0500
committerDave Barnes <phpdave11@gmail.com>2019-05-15 10:45:22 -0500
commit0fb5126fefeb1a7be7ed1c4dac02539af931a237 (patch)
tree9dc1ccf5ee62e07661689720ad17773a1577d240
parent8f080922446313698730071fd92ca15900e6a941 (diff)
Add support for imported objects and templates to version 1 of gofpdf.
-rw-r--r--README.md3
-rw-r--r--contrib/gofpdi/gofpdi.go62
-rw-r--r--def.go4
-rw-r--r--doc.go3
-rw-r--r--doc/document.md2
-rw-r--r--fpdf.go91
6 files changed, 162 insertions, 3 deletions
diff --git a/README.md b/README.md
index 2d5d14e..fdd8980 100644
--- a/README.md
+++ b/README.md
@@ -246,7 +246,8 @@ encoding and decoding functionality for templates, including images that
are embedded in templates; this allows templates to be stored
independently of gofpdf. Paul also added support for page boxes used in
printing PDF documents. Wojciech Matusiak added supported for word
-spacing. Artem Korotkiy added support of UTF-8 fonts.
+spacing. Artem Korotkiy added support of UTF-8 fonts. Dave Barnes added
+support for imported objects and templates.
## Roadmap
diff --git a/contrib/gofpdi/gofpdi.go b/contrib/gofpdi/gofpdi.go
new file mode 100644
index 0000000..c1f3df8
--- /dev/null
+++ b/contrib/gofpdi/gofpdi.go
@@ -0,0 +1,62 @@
+package gofpdi
+
+import (
+ realgofpdi "github.com/phpdave11/gofpdi"
+)
+
+// Create new gofpdi instance
+var fpdi = realgofpdi.NewImporter()
+
+// gofpdiPdf is a partial interface that only implements the functions we need
+// from the PDF generator to put the imported PDF templates on the PDF.
+type gofpdiPdf interface {
+ ImportObjects(objs map[string][]byte)
+ ImportObjPos(objs map[string]map[int]string)
+ ImportTemplates(tpls map[string]string)
+ UseImportedTemplate(tplName string, x float64, y float64, w float64, h float64)
+ SetError(err error)
+}
+
+// Imports a page of a PDF file with the specified box (/MediaBox, /TrimBox, /ArtBox, /CropBox, or /BleedBox).
+// Returns a template id that can be used with UseImportedTemplate to draw the template onto the page.
+func ImportPage(f gofpdiPdf, sourceFile string, pageno int, box string) int {
+ // Set source file for fpdi
+ fpdi.SetSourceFile(sourceFile)
+
+ // Import page
+ tpl := fpdi.ImportPage(pageno, box)
+
+ // Import objects into current pdf document
+ // Unordered means that the objects will be returned with a sha1 hash instead of an integer
+ // The objects themselves may have references to other hashes which will be replaced in ImportObjects()
+ tplObjIds := fpdi.PutFormXobjectsUnordered()
+
+ // Set template names and ids (hashes) in gofpdf
+ f.ImportTemplates(tplObjIds)
+
+ // Get a map[string]string of the imported objects.
+ // The map keys will be the ID of each object.
+ imported := fpdi.GetImportedObjectsUnordered()
+
+ // Import gofpdi objects into gofpdf
+ f.ImportObjects(imported)
+
+ // Get a map[string]map[int]string of the object hashes and their positions within each object,
+ // to be replaced with object ids (integers).
+ importedObjPos := fpdi.GetImportedObjHashPos()
+
+ // Import gofpdi object hashes and their positions into gopdf
+ f.ImportObjPos(importedObjPos)
+
+ return tpl
+}
+
+// Draw the template onto the page at x,y
+// If w is 0, the template will be scaled to fit based on h
+// If h is 0, the template will be scaled to fit based on w
+func UseImportedTemplate(f gofpdiPdf, tplid int, x float64, y float64, w float64, h float64) {
+ // Get values from fpdi
+ tplName, scaleX, scaleY, tX, tY := fpdi.UseTemplate(tplid, x, y, w, h)
+
+ f.UseImportedTemplate(tplName, scaleX, scaleY, tX, tY)
+}
diff --git a/def.go b/def.go
index ab4e81d..f725f01 100644
--- a/def.go
+++ b/def.go
@@ -504,6 +504,10 @@ type Fpdf struct {
offsets []int // array of object offsets
templates map[string]Template // templates used in this document
templateObjects map[string]int // template object IDs within this document
+ importedObjs map[string][]byte // imported template objects (gofpdi)
+ importedObjPos map[string]map[int]string // imported template objects hashes and their positions (gofpdi)
+ importedTplObjs map[string]string // imported template names and IDs (hashed) (gofpdi)
+ importedTplIds map[string]int // imported template ids hash to object id int (gofpdi)
buffer fmtBuffer // buffer holding in-memory PDF
pages []*bytes.Buffer // slice[page] of page content; 1-based
state int // current document state
diff --git a/doc.go b/doc.go
index 2d6f49b..3295200 100644
--- a/doc.go
+++ b/doc.go
@@ -253,7 +253,8 @@ encoding and decoding functionality for templates, including images that
are embedded in templates; this allows templates to be stored
independently of gofpdf. Paul also added support for page boxes used in
printing PDF documents. Wojciech Matusiak added supported for word
-spacing. Artem Korotkiy added support of UTF-8 fonts.
+spacing. Artem Korotkiy added support of UTF-8 fonts. Dave Barnes added
+support for imported objects and templates.
Roadmap
diff --git a/doc/document.md b/doc/document.md
index 33f5dac..de39656 100644
--- a/doc/document.md
+++ b/doc/document.md
@@ -226,7 +226,7 @@ decoding functionality for templates, including images that are embedded in
templates; this allows templates to be stored independently of gofpdf. Paul
also added support for page boxes used in printing PDF documents. Wojciech
Matusiak added supported for word spacing. Artem Korotkiy added support of
-UTF-8 fonts.
+UTF-8 fonts. Dave Barnes added support for imported objects and templates.
## Roadmap
diff --git a/fpdf.go b/fpdf.go
index d3366ce..e381459 100644
--- a/fpdf.go
+++ b/fpdf.go
@@ -85,6 +85,10 @@ func fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr string, size SizeType)
f.diffs = make([]string, 0, 8)
f.templates = make(map[string]Template)
f.templateObjects = make(map[string]int)
+ f.importedObjs = make(map[string][]byte, 0)
+ f.importedObjPos = make(map[string]map[int]string, 0)
+ f.importedTplObjs = make(map[string]string)
+ f.importedTplIds = make(map[string]int, 0)
f.images = make(map[string]*ImageInfoType)
f.pageLinks = make([][]linkType, 0, 8)
f.pageLinks = append(f.pageLinks, make([]linkType, 0, 0)) // pageLinks[0] is unused (1-based)
@@ -3101,6 +3105,86 @@ func (f *Fpdf) GetImageInfo(imageStr string) (info *ImageInfoType) {
return f.images[imageStr]
}
+// Import objects from gofpdi into current document
+func (f *Fpdf) ImportObjects(objs map[string][]byte) {
+ for k, v := range objs {
+ f.importedObjs[k] = v
+ }
+}
+
+// Import object hash positions from gofpdi
+func (f *Fpdf) ImportObjPos(objPos map[string]map[int]string) {
+ for k, v := range objPos {
+ f.importedObjPos[k] = v
+ }
+}
+
+// putImportedTemplates writes the imported template objects to the PDF
+func (f *Fpdf) putImportedTemplates() {
+ nOffset := f.n + 1
+
+ // keep track of list of sha1 hashes (to be replaced with integers)
+ objsIdHash := make([]string, len(f.importedObjs))
+
+ // actual object data with new id
+ objsIdData := make([][]byte, len(f.importedObjs))
+
+ // Populate hash slice and data slice
+ i := 0
+ for k, v := range f.importedObjs {
+ objsIdHash[i] = k
+ objsIdData[i] = v
+
+ i++
+ }
+
+ // Populate a lookup table to get an object id from a hash
+ hashToObjId := make(map[string]int, len(f.importedObjs))
+ for i = 0; i < len(objsIdHash); i++ {
+ hashToObjId[objsIdHash[i]] = i + nOffset
+ }
+
+ // Now, replace hashes inside data with %040d object id
+ for i = 0; i < len(objsIdData); i++ {
+ // get hash
+ hash := objsIdHash[i]
+
+ for pos, h := range f.importedObjPos[hash] {
+ // Convert object id into a 40 character string padded with spaces
+ objIdPadded := fmt.Sprintf("%40s", fmt.Sprintf("%d", hashToObjId[h]))
+
+ // Convert objIdPadded into []byte
+ objIdBytes := []byte(objIdPadded)
+
+ // Replace sha1 hash with object id padded
+ for j := pos; j < pos+40; j++ {
+ objsIdData[i][j] = objIdBytes[j-pos]
+ }
+ }
+
+ // Save objsIdHash so that procset dictionary has the correct object ids
+ f.importedTplIds[hash] = i + nOffset
+ }
+
+ // Now, put objects
+ for i = 0; i < len(objsIdData); i++ {
+ f.newobj()
+ f.out(string(objsIdData[i]))
+ }
+}
+
+// Use imported template from gofpdi - draws imported PDF page onto page
+func (f *Fpdf) UseImportedTemplate(tplName string, scaleX float64, scaleY float64, tX float64, tY float64) {
+ f.outf("q 0 J 1 w 0 j 0 G 0 g q %.4F 0 0 %.4F %.4F %.4F cm %s Do Q Q\n", scaleX*f.k, scaleY*f.k, tX*f.k, (tY+f.h)*f.k, tplName)
+}
+
+// Import gofpdi template names into importedTplObjs - to be included in the procset dictionary
+func (f *Fpdf) ImportTemplates(tpls map[string]string) {
+ for tplName, tplId := range tpls {
+ f.importedTplObjs[tplName] = tplId
+ }
+}
+
// GetConversionRatio returns the conversion ratio based on the unit given when
// creating the PDF.
func (f *Fpdf) GetConversionRatio() float64 {
@@ -4173,6 +4257,12 @@ func (f *Fpdf) putxobjectdict() {
}
}
}
+ {
+ for tplName, objID := range f.importedTplObjs {
+ // here replace obj id hash with n
+ f.outf("%s %d 0 R", tplName, f.importedTplIds[objID])
+ }
+ }
}
func (f *Fpdf) putresourcedict() {
@@ -4288,6 +4378,7 @@ func (f *Fpdf) putresources() {
}
f.putimages()
f.putTemplates()
+ f.putImportedTemplates() // gofpdi
// Resource dictionary
f.offsets[2] = f.buffer.Len()
f.out("2 0 obj")