diff options
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | contrib/gofpdi/gofpdi.go | 62 | ||||
-rw-r--r-- | def.go | 4 | ||||
-rw-r--r-- | doc.go | 3 | ||||
-rw-r--r-- | doc/document.md | 2 | ||||
-rw-r--r-- | fpdf.go | 91 |
6 files changed, 162 insertions, 3 deletions
@@ -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) +} @@ -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 @@ -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 @@ -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") |