Kurt Jungs Auslieferungszustand

This commit is contained in:
2021-03-02 13:27:45 +01:00
commit 5afea81825
156 changed files with 30287 additions and 0 deletions

302
contrib/barcode/barcode.go Normal file
View File

@@ -0,0 +1,302 @@
// Copyright (c) 2015 Jelmer Snoeck (Gmail: jelmer.snoeck)
//
// Permission to use, copy, modify, and distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
// Package barcode provides helper methods for adding barcodes of different
// types to your pdf document. It relies on the github.com/boombuler/barcode
// package for the barcode creation.
package barcode
import (
"bytes"
"errors"
"image/jpeg"
"io"
"strconv"
"sync"
"github.com/boombuler/barcode"
"github.com/boombuler/barcode/aztec"
"github.com/boombuler/barcode/codabar"
"github.com/boombuler/barcode/code128"
"github.com/boombuler/barcode/code39"
"github.com/boombuler/barcode/datamatrix"
"github.com/boombuler/barcode/ean"
"github.com/boombuler/barcode/qr"
"github.com/boombuler/barcode/twooffive"
"github.com/jung-kurt/gofpdf"
"github.com/ruudk/golang-pdf417"
)
// barcodes represents the barcodes that have been registered through this
// package. They will later be used to be scaled and put on the page.
// RubenN: made this a struct with a mutex to prevent race condition
var barcodes struct {
sync.Mutex
cache map[string]barcode.Barcode
}
// barcodePdf is a partial PDF implementation that only implements a subset of
// functions that are required to add the barcode to the PDF.
type barcodePdf interface {
GetConversionRatio() float64
GetImageInfo(imageStr string) *gofpdf.ImageInfoType
Image(imageNameStr string, x, y, w, h float64, flow bool, tp string, link int, linkStr string)
RegisterImageReader(imgName, tp string, r io.Reader) *gofpdf.ImageInfoType
SetError(err error)
}
// printBarcode internally prints the scaled or unscaled barcode to the PDF. Used by both
// Barcode() and BarcodeUnscalable().
func printBarcode(pdf barcodePdf, code string, x, y float64, w, h *float64, flow bool) {
barcodes.Lock()
unscaled, ok := barcodes.cache[code]
barcodes.Unlock()
if !ok {
err := errors.New("Barcode not found")
pdf.SetError(err)
return
}
bname := uniqueBarcodeName(code, x, y)
info := pdf.GetImageInfo(bname)
scaleToWidth := unscaled.Bounds().Dx()
scaleToHeight := unscaled.Bounds().Dy()
if info == nil {
bcode, err := barcode.Scale(
unscaled,
scaleToWidth,
scaleToHeight,
)
if err != nil {
pdf.SetError(err)
return
}
err = registerScaledBarcode(pdf, bname, bcode)
if err != nil {
pdf.SetError(err)
return
}
}
scaleToWidthF := float64(scaleToWidth)
scaleToHeightF := float64(scaleToHeight)
if w != nil {
scaleToWidthF = *w
}
if h != nil {
scaleToHeightF = *h
}
pdf.Image(bname, x, y, scaleToWidthF, scaleToHeightF, flow, "jpg", 0, "")
}
// BarcodeUnscalable puts a registered barcode in the current page.
//
// Its arguments work in the same way as that of Barcode(). However, it allows for an unscaled
// barcode in the width and/or height dimensions. This can be useful if you want to prevent
// side effects of upscaling.
func BarcodeUnscalable(pdf barcodePdf, code string, x, y float64, w, h *float64, flow bool) {
printBarcode(pdf, code, x, y, w, h, flow)
}
// Barcode puts a registered barcode in the current page.
//
// The size should be specified in the units used to create the PDF document.
// If width or height are left unspecfied, the barcode is not scaled in the unspecified dimensions.
//
// Positioning with x, y and flow is inherited from Fpdf.Image().
func Barcode(pdf barcodePdf, code string, x, y, w, h float64, flow bool) {
printBarcode(pdf, code, x, y, &w, &h, flow)
}
// GetUnscaledBarcodeDimensions returns the width and height of the
// unscaled barcode associated with the given code.
func GetUnscaledBarcodeDimensions(pdf barcodePdf, code string) (w, h float64) {
barcodes.Lock()
unscaled, ok := barcodes.cache[code]
barcodes.Unlock()
if !ok {
err := errors.New("Barcode not found")
pdf.SetError(err)
return
}
return convertFrom96Dpi(pdf, float64(unscaled.Bounds().Dx())),
convertFrom96Dpi(pdf, float64(unscaled.Bounds().Dy()))
}
// Register registers a barcode but does not put it on the page. Use Barcode()
// with the same code to put the barcode on the PDF page.
func Register(bcode barcode.Barcode) string {
barcodes.Lock()
if len(barcodes.cache) == 0 {
barcodes.cache = make(map[string]barcode.Barcode)
}
key := barcodeKey(bcode)
barcodes.cache[key] = bcode
barcodes.Unlock()
return key
}
// RegisterAztec registers a barcode of type Aztec to the PDF, but not to
// the page. Use Barcode() with the return value to put the barcode on the page.
// code is the string to be encoded. minECCPercent is the error correction percentage. 33 is the default.
// userSpecifiedLayers can be a value between -4 and 32 inclusive.
func RegisterAztec(pdf barcodePdf, code string, minECCPercent int, userSpecifiedLayers int) string {
bcode, err := aztec.Encode([]byte(code), minECCPercent, userSpecifiedLayers)
return registerBarcode(pdf, bcode, err)
}
// RegisterCodabar registers a barcode of type Codabar to the PDF, but not to
// the page. Use Barcode() with the return value to put the barcode on the page.
func RegisterCodabar(pdf barcodePdf, code string) string {
bcode, err := codabar.Encode(code)
return registerBarcode(pdf, bcode, err)
}
// RegisterCode128 registers a barcode of type Code128 to the PDF, but not to
// the page. Use Barcode() with the return value to put the barcode on the page.
func RegisterCode128(pdf barcodePdf, code string) string {
bcode, err := code128.Encode(code)
return registerBarcode(pdf, bcode, err)
}
// RegisterCode39 registers a barcode of type Code39 to the PDF, but not to
// the page. Use Barcode() with the return value to put the barcode on the page.
//
// includeChecksum and fullASCIIMode are inherited from code39.Encode().
func RegisterCode39(pdf barcodePdf, code string, includeChecksum, fullASCIIMode bool) string {
bcode, err := code39.Encode(code, includeChecksum, fullASCIIMode)
return registerBarcode(pdf, bcode, err)
}
// RegisterDataMatrix registers a barcode of type DataMatrix to the PDF, but not
// to the page. Use Barcode() with the return value to put the barcode on the
// page.
func RegisterDataMatrix(pdf barcodePdf, code string) string {
bcode, err := datamatrix.Encode(code)
return registerBarcode(pdf, bcode, err)
}
// RegisterPdf417 registers a barcode of type Pdf417 to the PDF, but not to the
// page. code is the string to be encoded. columns specifies the number of
// barcode columns; this should be a value between 1 and 30 inclusive.
// securityLevel specifies an error correction level between zero and 8
// inclusive. Barcodes for use with FedEx must set columns to 10 and
// securityLevel to 5. Use Barcode() with the return value to put the barcode
// on the page.
func RegisterPdf417(pdf barcodePdf, code string, columns int, securityLevel int) string {
bcode := pdf417.Encode(code, columns, securityLevel)
return registerBarcode(pdf, bcode, nil)
}
// RegisterEAN registers a barcode of type EAN to the PDF, but not to the page.
// It will automatically detect if the barcode is EAN8 or EAN13. Use Barcode()
// with the return value to put the barcode on the page.
func RegisterEAN(pdf barcodePdf, code string) string {
bcode, err := ean.Encode(code)
return registerBarcode(pdf, bcode, err)
}
// RegisterQR registers a barcode of type QR to the PDF, but not to the page.
// Use Barcode() with the return value to put the barcode on the page.
//
// The ErrorCorrectionLevel and Encoding mode are inherited from qr.Encode().
func RegisterQR(pdf barcodePdf, code string, ecl qr.ErrorCorrectionLevel, mode qr.Encoding) string {
bcode, err := qr.Encode(code, ecl, mode)
return registerBarcode(pdf, bcode, err)
}
// RegisterTwoOfFive registers a barcode of type TwoOfFive to the PDF, but not
// to the page. Use Barcode() with the return value to put the barcode on the
// page.
//
// The interleaved bool is inherited from twooffive.Encode().
func RegisterTwoOfFive(pdf barcodePdf, code string, interleaved bool) string {
bcode, err := twooffive.Encode(code, interleaved)
return registerBarcode(pdf, bcode, err)
}
// registerBarcode registers a barcode internally using the Register() function.
// In case of an error generating the barcode it will not be registered and will
// set an error on the PDF. It will return a unique key for the barcode type and
// content that can be used to put the barcode on the page.
func registerBarcode(pdf barcodePdf, bcode barcode.Barcode, err error) string {
if err != nil {
pdf.SetError(err)
return ""
}
return Register(bcode)
}
// uniqueBarcodeName makes sure every barcode has a unique name for its
// dimensions. Scaling a barcode image results in quality loss, which could be
// a problem for barcode readers.
func uniqueBarcodeName(code string, x, y float64) string {
xStr := strconv.FormatFloat(x, 'E', -1, 64)
yStr := strconv.FormatFloat(y, 'E', -1, 64)
return "barcode-" + code + "-" + xStr + yStr
}
// barcodeKey combines the code type and code value into a unique identifier for
// a barcode type. This is so that we can store several barcodes with the same
// code but different type in the barcodes map.
func barcodeKey(bcode barcode.Barcode) string {
return bcode.Metadata().CodeKind + bcode.Content()
}
// registerScaledBarcode registers a barcode with its exact dimensions to the
// PDF but does not put it on the page. Use Fpdf.Image() with the same code to
// add the barcode to the page.
func registerScaledBarcode(pdf barcodePdf, code string, bcode barcode.Barcode) error {
buf := new(bytes.Buffer)
err := jpeg.Encode(buf, bcode, nil)
if err != nil {
return err
}
reader := bytes.NewReader(buf.Bytes())
pdf.RegisterImageReader(code, "jpg", reader)
return nil
}
// convertTo96DPI converts the given value, which is based on a 72 DPI value
// like the rest of the PDF document, to a 96 DPI value that is required for
// an Image.
//
// Doing this through the Fpdf.Image() function would mean that it uses a 72 DPI
// value and stretches it to a 96 DPI value. This results in quality loss which
// could be problematic for barcode scanners.
func convertTo96Dpi(pdf barcodePdf, value float64) float64 {
return value * pdf.GetConversionRatio() / 72 * 96
}
// convertFrom96Dpi converts the given value, which is based on a 96 DPI value
// required for an Image, to a 72 DPI value like the rest of the PDF document.
func convertFrom96Dpi(pdf barcodePdf, value float64) float64 {
return value / pdf.GetConversionRatio() * 72 / 96
}

View File

@@ -0,0 +1,222 @@
package barcode_test
import (
"testing"
"github.com/boombuler/barcode/code128"
"github.com/boombuler/barcode/qr"
"github.com/jung-kurt/gofpdf"
"github.com/jung-kurt/gofpdf/contrib/barcode"
"github.com/jung-kurt/gofpdf/internal/example"
)
func createPdf() (pdf *gofpdf.Fpdf) {
pdf = gofpdf.New("L", "mm", "A4", "")
pdf.SetFont("Helvetica", "", 12)
pdf.SetFillColor(200, 200, 220)
pdf.AddPage()
return
}
func ExampleRegister() {
pdf := createPdf()
fileStr := example.Filename("contrib_barcode_Register")
bcode, err := code128.Encode("gofpdf")
if err == nil {
key := barcode.Register(bcode)
var width float64 = 100
var height float64 = 10.0
barcode.BarcodeUnscalable(pdf, key, 15, 15, &width, &height, false)
}
err = pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_barcode_Register.pdf
}
func ExampleRegisterCodabar() {
pdf := createPdf()
key := barcode.RegisterCode128(pdf, "codabar")
var width float64 = 100
var height float64 = 10
barcode.BarcodeUnscalable(pdf, key, 15, 15, &width, &height, false)
fileStr := example.Filename("contrib_barcode_RegisterCodabar")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_barcode_RegisterCodabar.pdf
}
func ExampleRegisterAztec() {
pdf := createPdf()
key := barcode.RegisterAztec(pdf, "aztec", 33, 0)
barcode.Barcode(pdf, key, 15, 15, 100, 100, false)
fileStr := example.Filename("contrib_barcode_RegisterAztec")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_barcode_RegisterAztec.pdf
}
func ExampleRegisterCode128() {
pdf := createPdf()
key := barcode.RegisterCode128(pdf, "code128")
barcode.Barcode(pdf, key, 15, 15, 100, 10, false)
fileStr := example.Filename("contrib_barcode_RegisterCode128")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_barcode_RegisterCode128.pdf
}
func ExampleRegisterCode39() {
pdf := createPdf()
key := barcode.RegisterCode39(pdf, "CODE39", false, true)
barcode.Barcode(pdf, key, 15, 15, 100, 10, false)
fileStr := example.Filename("contrib_barcode_RegisterCode39")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_barcode_RegisterCode39.pdf
}
func ExampleRegisterDataMatrix() {
pdf := createPdf()
key := barcode.RegisterDataMatrix(pdf, "datamatrix")
barcode.Barcode(pdf, key, 15, 15, 20, 20, false)
fileStr := example.Filename("contrib_barcode_RegisterDataMatrix")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_barcode_RegisterDataMatrix.pdf
}
func ExampleRegisterEAN() {
pdf := createPdf()
key := barcode.RegisterEAN(pdf, "96385074")
barcode.Barcode(pdf, key, 15, 15, 100, 10, false)
fileStr := example.Filename("contrib_barcode_RegisterEAN")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_barcode_RegisterEAN.pdf
}
func ExampleRegisterQR() {
pdf := createPdf()
key := barcode.RegisterQR(pdf, "qrcode", qr.H, qr.Unicode)
barcode.Barcode(pdf, key, 15, 15, 100, 10, false)
fileStr := example.Filename("contrib_barcode_RegisterQR")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_barcode_RegisterQR.pdf
}
func ExampleRegisterTwoOfFive() {
pdf := createPdf()
key := barcode.RegisterTwoOfFive(pdf, "1234567895", true)
barcode.Barcode(pdf, key, 15, 15, 100, 10, false)
fileStr := example.Filename("contrib_barcode_RegisterTwoOfFive")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_barcode_RegisterTwoOfFive.pdf
}
func ExampleRegisterPdf417() {
pdf := createPdf()
key := barcode.RegisterPdf417(pdf, "1234567895", 10, 5)
barcode.Barcode(pdf, key, 15, 15, 100, 10, false)
fileStr := example.Filename("contrib_barcode_RegisterPdf417")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_barcode_RegisterPdf417.pdf
}
// TestRegisterCode128 ensures that no panic arises when an invalid barcode is registered.
func TestRegisterCode128(t *testing.T) {
pdf := createPdf()
barcode.RegisterCode128(pdf, "Invalid character: é")
}
// TestBarcodeUnscalable shows that the barcode may be scaled or not by providing optional heights and widths.
func TestBarcodeUnscalable(t *testing.T) {
pdf := createPdf()
key := barcode.RegisterCode128(pdf, "code128")
var width float64 = 100
var height float64 = 10
barcode.BarcodeUnscalable(pdf, key, 15, 15, &width, &height, false)
barcode.BarcodeUnscalable(pdf, key, 15, 35, nil, &height, false)
barcode.BarcodeUnscalable(pdf, key, 15, 55, &width, nil, false)
barcode.BarcodeUnscalable(pdf, key, 15, 75, nil, nil, false)
fileStr := example.Filename("contrib_barcode_Barcode")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_barcode_Barcode.pdf
}
// TestGetUnscaledBarcodeDimensions shows that the width and height returned by the function match that of the barcode
func TestGetUnscaledBarcodeDimensions(t *testing.T) {
pdf := createPdf()
key := barcode.RegisterQR(pdf, "qrcode", qr.H, qr.Unicode)
barcode.BarcodeUnscalable(pdf, key, 15, 15, nil, nil, false)
w, h := barcode.GetUnscaledBarcodeDimensions(pdf, key)
pdf.SetDrawColor(255, 0, 0)
pdf.Line(15, 15, 15+w, 15+h)
fileStr := example.Filename("contrib_barcode_GetBarcodeDimensions")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_barcode_GetBarcodeDimensions.pdf
}
// TestBarcodeNonIntegerScalingFactors shows that the barcode may be scaled to non-integer sizes
func TestBarcodeNonIntegerScalingFactors(t *testing.T) {
pdf := gofpdf.New("L", "in", "A4", "")
pdf.SetFont("Helvetica", "", 12)
pdf.SetFillColor(200, 200, 220)
pdf.AddPage()
key := barcode.RegisterQR(pdf, "qrcode", qr.H, qr.Unicode)
var scale float64 = 1.5
barcode.BarcodeUnscalable(pdf, key, 0.5, 0.5, &scale, &scale, false)
pdf.SetDrawColor(255, 0, 0)
pdf.Line(0.5, 0.5, 0.5+scale, 0.5+scale)
fileStr := example.Filename("contrib_barcode_BarcodeScaling")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_barcode_BarcodeScaling.pdf
}

View File

@@ -0,0 +1,68 @@
package main
// This command demonstrates the use of ghotscript to reduce the size
// of generated PDFs. This is based on a comment made by farkerhaiku:
// https://github.com/jung-kurt/gofpdf/issues/57#issuecomment-185843315
import (
"fmt"
"os"
"os/exec"
"github.com/jung-kurt/gofpdf"
)
func report(fileStr string, err error) {
if err == nil {
var info os.FileInfo
info, err = os.Stat(fileStr)
if err == nil {
fmt.Printf("%s: OK, size %d\n", fileStr, info.Size())
} else {
fmt.Printf("%s: bad stat\n", fileStr)
}
} else {
fmt.Printf("%s: %s\n", fileStr, err)
}
}
func newPdf() (pdf *gofpdf.Fpdf) {
pdf = gofpdf.New("P", "mm", "A4", "../../font")
pdf.SetCompression(false)
pdf.AddFont("Calligrapher", "", "calligra.json")
pdf.AddPage()
pdf.SetFont("Calligrapher", "", 35)
pdf.Cell(0, 10, "Enjoy new fonts with FPDF!")
return
}
func full(name string) {
report(name, newPdf().OutputFileAndClose(name))
}
func min(name string) {
cmd := exec.Command("gs", "-sDEVICE=pdfwrite",
"-dCompatibilityLevel=1.4",
"-dPDFSETTINGS=/screen", "-dNOPAUSE", "-dQUIET",
"-dBATCH", "-sOutputFile="+name, "-")
inPipe, err := cmd.StdinPipe()
if err == nil {
errChan := make(chan error, 1)
go func() {
errChan <- cmd.Start()
}()
err = newPdf().Output(inPipe)
if err == nil {
report(name, <-errChan)
} else {
report(name, err)
}
} else {
report(name, err)
}
}
func main() {
full("full.pdf")
min("min.pdf")
}

143
contrib/gofpdi/gofpdi.go Normal file
View File

@@ -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()
}

View File

@@ -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
}

View File

@@ -0,0 +1,43 @@
package httpimg
import (
"io"
"net/http"
"github.com/jung-kurt/gofpdf"
)
// httpimgPdf is a partial interface that only implements the functions we need
// from the PDF generator to put the HTTP images on the PDF.
type httpimgPdf interface {
GetImageInfo(imageStr string) *gofpdf.ImageInfoType
ImageTypeFromMime(mimeStr string) string
RegisterImageReader(imgName, tp string, r io.Reader) *gofpdf.ImageInfoType
SetError(err error)
}
// Register registers a HTTP image. Downloading the image from the provided URL
// and adding it to the PDF but not adding it to the page. Use Image() with the
// same URL to add the image to the page.
func Register(f httpimgPdf, urlStr, tp string) (info *gofpdf.ImageInfoType) {
info = f.GetImageInfo(urlStr)
if info != nil {
return
}
resp, err := http.Get(urlStr)
if err != nil {
f.SetError(err)
return
}
defer resp.Body.Close()
if tp == "" {
tp = f.ImageTypeFromMime(resp.Header["Content-Type"][0])
}
return f.RegisterImageReader(urlStr, tp, resp.Body)
}

View File

@@ -0,0 +1,23 @@
package httpimg_test
import (
"github.com/jung-kurt/gofpdf"
"github.com/jung-kurt/gofpdf/contrib/httpimg"
"github.com/jung-kurt/gofpdf/internal/example"
)
func ExampleRegister() {
pdf := gofpdf.New("L", "mm", "A4", "")
pdf.SetFont("Helvetica", "", 12)
pdf.SetFillColor(200, 200, 220)
pdf.AddPage()
url := "https://github.com/jung-kurt/gofpdf/raw/master/image/logo_gofpdf.jpg?raw=true"
httpimg.Register(pdf, url, "")
pdf.Image(url, 15, 15, 267, 0, false, "", 0, "")
fileStr := example.Filename("contrib_httpimg_Register")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/contrib_httpimg_Register.pdf
}

83
contrib/tiff/tiff.go Normal file
View File

@@ -0,0 +1,83 @@
/*
* Copyright (c) 2016 Kurt Jung (Gmail: kurt.w.jung)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Package tiff allows standard (LZW-compressed) TIFF images to be used in
// documents generated with gofpdf.
package tiff
import (
"bytes"
"fmt"
"image"
"image/png"
"io"
"os"
"github.com/jung-kurt/gofpdf"
"golang.org/x/image/tiff"
)
// RegisterReader registers a TIFF image, adding it to the PDF file but not
// adding it to the page. imgName specifies the name that will be used in the
// call to Image() that actually places the image in the document. options
// specifies various image properties; in this case, the ImageType property
// should be set to "tiff". The TIFF image is a reader from the reader
// specified by r.
func RegisterReader(fpdf *gofpdf.Fpdf, imgName string, options gofpdf.ImageOptions, r io.Reader) (info *gofpdf.ImageInfoType) {
var err error
var img image.Image
var buf bytes.Buffer
if fpdf.Ok() {
if options.ImageType == "tiff" || options.ImageType == "tif" {
img, err = tiff.Decode(r)
if err == nil {
err = png.Encode(&buf, img)
if err == nil {
options.ImageType = "png"
info = fpdf.RegisterImageOptionsReader(imgName, options, &buf)
}
}
} else {
err = fmt.Errorf("expecting \"tiff\" or \"tif\" as image type, got \"%s\"", options.ImageType)
}
if err != nil {
fpdf.SetError(err)
}
}
return
}
// RegisterFile registers a TIFF image, adding it to the PDF file but not
// adding it to the page. imgName specifies the name that will be used in the
// call to Image() that actually places the image in the document. options
// specifies various image properties; in this case, the ImageType property
// should be set to "tiff". The TIFF image is read from the file specified by
// tiffFileStr.
func RegisterFile(fpdf *gofpdf.Fpdf, imgName string, options gofpdf.ImageOptions, tiffFileStr string) (info *gofpdf.ImageInfoType) {
var f *os.File
var err error
if fpdf.Ok() {
f, err = os.Open(tiffFileStr)
if err == nil {
info = RegisterReader(fpdf, imgName, options, f)
f.Close()
} else {
fpdf.SetError(err)
}
}
return
}

23
contrib/tiff/tiff_test.go Normal file
View File

@@ -0,0 +1,23 @@
package tiff_test
import (
"github.com/jung-kurt/gofpdf"
"github.com/jung-kurt/gofpdf/contrib/tiff"
"github.com/jung-kurt/gofpdf/internal/example"
)
// ExampleRegisterFile demonstrates the loading and display of a TIFF image.
func ExampleRegisterFile() {
pdf := gofpdf.New("L", "mm", "A4", "")
pdf.SetFont("Helvetica", "", 12)
pdf.SetFillColor(200, 200, 220)
pdf.AddPageFormat("L", gofpdf.SizeType{Wd: 200, Ht: 200})
opt := gofpdf.ImageOptions{ImageType: "tiff", ReadDpi: false}
_ = tiff.RegisterFile(pdf, "sample", opt, "../../image/golang-gopher.tiff")
pdf.Image("sample", 0, 0, 200, 200, false, "", 0, "")
fileStr := example.Filename("Fpdf_Contrib_Tiff")
err := pdf.OutputFileAndClose(fileStr)
example.Summary(err, fileStr)
// Output:
// Successfully generated ../../pdf/Fpdf_Contrib_Tiff.pdf
}