forked from jung-kurt/gofpdf
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'upstream/master'
Update to latest version
- Loading branch information
Showing
11 changed files
with
672 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
all : documentation | ||
|
||
documentation : doc/index.html doc.go README.md | ||
|
||
cov : all | ||
go test -v -coverprofile=coverage && go tool cover -html=coverage -o=coverage.html | ||
|
||
check : | ||
golint . | ||
go vet -all . | ||
gofmt -s -l . | ||
goreportcard-cli -v | grep -v cyclomatic | ||
|
||
README.md : doc/document.md | ||
pandoc --read=markdown --write=gfm < $< > $@ | ||
|
||
doc/index.html : doc/document.md doc/html.txt | ||
pandoc --read=markdown --write=html --template=doc/html.txt \ | ||
--metadata pagetitle="GoFPDF Document Generator" < $< > $@ | ||
|
||
doc.go : doc/document.md doc/go.awk | ||
pandoc --read=markdown --write=plain $< | awk --assign=package_name=gofpdf --file=doc/go.awk > $@ | ||
gofmt -s -w $@ | ||
|
||
build : | ||
go build -v | ||
|
||
clean : | ||
rm -f coverage.html coverage doc/index.html doc.go README.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
/* | ||
Package gofpdi wraps the gofpdi PDF library to import existing PDFs as templates. See github.com/phpdave11/gofpdi | ||
for further information and examples. | ||
Users should call NewImporter() to obtain their own Importer instance to work with. | ||
To retain backwards compatibility, the package offers a default Importer that may be used via global functions. Note | ||
however that use of the default Importer is not thread safe. | ||
*/ | ||
package gofpdi | ||
|
||
import ( | ||
realgofpdi "github.com/phpdave11/gofpdi" | ||
"io" | ||
) | ||
|
||
// 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) | ||
} | ||
|
||
// Importer wraps an Importer from the gofpdi library. | ||
type Importer struct { | ||
fpdi *realgofpdi.Importer | ||
} | ||
|
||
// NewImporter creates a new Importer wrapping functionality from the gofpdi library. | ||
func NewImporter() *Importer { | ||
return &Importer{ | ||
fpdi: realgofpdi.NewImporter(), | ||
} | ||
} | ||
|
||
// ImportPage 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 (i *Importer) ImportPage(f gofpdiPdf, sourceFile string, pageno int, box string) int { | ||
// Set source file for fpdi | ||
i.fpdi.SetSourceFile(sourceFile) | ||
// return template id | ||
return i.getTemplateID(f, pageno, box) | ||
} | ||
|
||
// ImportPageFromStream imports a page of a PDF 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 (i *Importer) ImportPageFromStream(f gofpdiPdf, rs *io.ReadSeeker, pageno int, box string) int { | ||
// Set source stream for fpdi | ||
i.fpdi.SetSourceStream(rs) | ||
// return template id | ||
return i.getTemplateID(f, pageno, box) | ||
} | ||
|
||
func (i *Importer) getTemplateID(f gofpdiPdf, pageno int, box string) int { | ||
// Import page | ||
tpl := i.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 := i.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 := i.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 := i.fpdi.GetImportedObjHashPos() | ||
|
||
// Import gofpdi object hashes and their positions into gopdf | ||
f.ImportObjPos(importedObjPos) | ||
|
||
return tpl | ||
} | ||
|
||
// UseImportedTemplate draws 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 (i *Importer) UseImportedTemplate(f gofpdiPdf, tplid int, x float64, y float64, w float64, h float64) { | ||
// Get values from fpdi | ||
tplName, scaleX, scaleY, tX, tY := i.fpdi.UseTemplate(tplid, x, y, w, h) | ||
|
||
f.UseImportedTemplate(tplName, scaleX, scaleY, tX, tY) | ||
} | ||
|
||
// GetPageSizes returns page dimensions for all pages of the imported pdf. | ||
// Result consists of map[<page number>]map[<box>]map[<dimension>]<value>. | ||
// <page number>: page number, note that page numbers start at 1 | ||
// <box>: box identifier, e.g. "/MediaBox" | ||
// <dimension>: dimension string, either "w" or "h" | ||
func (i *Importer) GetPageSizes() map[int]map[string]map[string]float64 { | ||
return i.fpdi.GetPageSizes() | ||
} | ||
|
||
// Default Importer used by global functions | ||
var fpdi = NewImporter() | ||
|
||
// ImportPage 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. | ||
// Note: This uses the default Importer. Call NewImporter() to obtain a custom Importer. | ||
func ImportPage(f gofpdiPdf, sourceFile string, pageno int, box string) int { | ||
return fpdi.ImportPage(f, sourceFile, pageno, box) | ||
} | ||
|
||
// ImportPageFromStream imports a page of a PDF 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. | ||
// Note: This uses the default Importer. Call NewImporter() to obtain a custom Importer. | ||
func ImportPageFromStream(f gofpdiPdf, rs *io.ReadSeeker, pageno int, box string) int { | ||
return fpdi.ImportPageFromStream(f, rs, pageno, box) | ||
} | ||
|
||
// UseImportedTemplate draws 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. | ||
// Note: This uses the default Importer. Call NewImporter() to obtain a custom Importer. | ||
func UseImportedTemplate(f gofpdiPdf, tplid int, x float64, y float64, w float64, h float64) { | ||
fpdi.UseImportedTemplate(f, tplid, x, y, w, h) | ||
} | ||
|
||
// GetPageSizes returns page dimensions for all pages of the imported pdf. | ||
// Result consists of map[<page number>]map[<box>]map[<dimension>]<value>. | ||
// <page number>: page number, note that page numbers start at 1 | ||
// <box>: box identifier, e.g. "/MediaBox" | ||
// <dimension>: dimension string, either "w" or "h" | ||
// Note: This uses the default Importer. Call NewImporter() to obtain a custom Importer. | ||
func GetPageSizes() map[int]map[string]map[string]float64 { | ||
return fpdi.GetPageSizes() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package gofpdi | ||
|
||
import ( | ||
"bytes" | ||
"github.com/jung-kurt/gofpdf" | ||
"github.com/jung-kurt/gofpdf/internal/example" | ||
"io" | ||
"sync" | ||
"testing" | ||
) | ||
|
||
func ExampleNewImporter() { | ||
// create new pdf | ||
pdf := gofpdf.New("P", "pt", "A4", "") | ||
|
||
// for testing purposes, get an arbitrary template pdf as stream | ||
rs, _ := getTemplatePdf() | ||
|
||
// create a new Importer instance | ||
imp := NewImporter() | ||
|
||
// import first page and determine page sizes | ||
tpl := imp.ImportPageFromStream(pdf, &rs, 1, "/MediaBox") | ||
pageSizes := imp.GetPageSizes() | ||
nrPages := len(imp.GetPageSizes()) | ||
|
||
// add all pages from template pdf | ||
for i := 1; i <= nrPages; i++ { | ||
pdf.AddPage() | ||
if i > 1 { | ||
tpl = imp.ImportPageFromStream(pdf, &rs, i, "/MediaBox") | ||
} | ||
imp.UseImportedTemplate(pdf, tpl, 0, 0, pageSizes[i]["/MediaBox"]["w"], pageSizes[i]["/MediaBox"]["h"]) | ||
} | ||
|
||
// output | ||
fileStr := example.Filename("contrib_gofpdi_Importer") | ||
err := pdf.OutputFileAndClose(fileStr) | ||
example.Summary(err, fileStr) | ||
// Output: | ||
// Successfully generated ../../pdf/contrib_gofpdi_Importer.pdf | ||
} | ||
|
||
func TestGofpdiConcurrent(t *testing.T) { | ||
wg := sync.WaitGroup{} | ||
for i := 0; i < 100; i++ { | ||
wg.Add(1) | ||
go func() { | ||
defer wg.Done() | ||
pdf := gofpdf.New("P", "mm", "A4", "") | ||
pdf.AddPage() | ||
rs, _ := getTemplatePdf() | ||
imp := NewImporter() | ||
tpl := imp.ImportPageFromStream(pdf, &rs, 1, "/MediaBox") | ||
imp.UseImportedTemplate(pdf, tpl, 0, 0, 210.0, 297.0) | ||
// write to bytes buffer | ||
buf := bytes.Buffer{} | ||
if err := pdf.Output(&buf); err != nil { | ||
t.Fail() | ||
} | ||
}() | ||
} | ||
wg.Wait() | ||
} | ||
|
||
func getTemplatePdf() (io.ReadSeeker, error) { | ||
tpdf := gofpdf.New("P", "pt", "A4", "") | ||
tpdf.AddPage() | ||
tpdf.SetFont("Arial", "", 12) | ||
tpdf.Text(20, 20, "Example Page 1") | ||
tpdf.AddPage() | ||
tpdf.Text(20, 20, "Example Page 2") | ||
tbuf := bytes.Buffer{} | ||
err := tpdf.Output(&tbuf) | ||
return bytes.NewReader(tbuf.Bytes()), err | ||
} |
Oops, something went wrong.