diff options
| author | Jelmer Snoeck <jelmer.snoeck@gmail.com> | 2015-08-29 14:41:39 +0100 | 
|---|---|---|
| committer | Jelmer Snoeck <jelmer.snoeck@gmail.com> | 2015-08-31 16:55:08 +0100 | 
| commit | bb0b7372a6e097a5a0efcbb7ca6cf6177813989e (patch) | |
| tree | ce9b340f7c8d3ae63d96021d0d5631d3493c067d /contrib/barcode | |
| parent | 706d7cc75e1f533b761a62d22cb2fc06d09c2de9 (diff) | |
Add Barcode contribution package.
This package adds the ability to easily add a barcode to the PDF. This
barcode is generated with the github.com/boombuler/barcode package.
It adds wrappers for all the available barcode types through the
`Register()` and `Register<Type>()` methods. These register methods put
the barcode on the PDF, but not on the page. They will return a unique
key that should be used later on with the `Barcode()` method scale the
barcode and put it on the page.
Diffstat (limited to 'contrib/barcode')
| -rw-r--r-- | contrib/barcode/barcode.go | 204 | ||||
| -rw-r--r-- | contrib/barcode/barcode_test.go | 126 | 
2 files changed, 330 insertions, 0 deletions
| diff --git a/contrib/barcode/barcode.go b/contrib/barcode/barcode.go new file mode 100644 index 0000000..e49ac53 --- /dev/null +++ b/contrib/barcode/barcode.go @@ -0,0 +1,204 @@ +// 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" +	"github.com/boombuler/barcode" +	"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" +	"image/jpeg" +	"strconv" +) + +// barcodes represents the barcodes that have been registered through this +// package. They will later be used to be scaled and put on the page. +var barcodes map[string]barcode.Barcode + +// Barcode puts a registered barcode in the current page. +// +// The size should be specified in the units used to create the PDF document. +// +// Positioning with x, y and flow is inherited from Fpdf.Image(). +func Barcode(pdf *gofpdf.Fpdf, code string, x, y, w, h float64, flow bool) { +	unscaled, ok := barcodes[code] + +	if !ok { +		err := errors.New("Barcode not found") +		pdf.SetError(err) +		return +	} + +	bname := uniqueBarcodeName(code, x, y) +	info := pdf.GetImageInfo(bname) + +	if info == nil { +		bcode, err := barcode.Scale( +			unscaled, +			int(convertTo96Dpi(pdf, w)), +			int(convertTo96Dpi(pdf, h)), +		) + +		if err != nil { +			pdf.SetError(err) +			return +		} + +		err = registerScaledBarcode(pdf, bname, bcode) +		if err != nil { +			pdf.SetError(err) +			return +		} +	} + +	pdf.Image(bname, x, y, 0, 0, flow, "jpg", 0, "") +} + +// 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 { +	if len(barcodes) == 0 { +		barcodes = make(map[string]barcode.Barcode) +	} + +	key := barcodeKey(bcode) +	barcodes[key] = bcode +	return key +} + +// 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 *gofpdf.Fpdf, 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 *gofpdf.Fpdf, 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 *gofpdf.Fpdf, 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 *gofpdf.Fpdf, code string) string { +	bcode, err := datamatrix.Encode(code) +	return registerBarcode(pdf, bcode, err) +} + +// 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 *gofpdf.Fpdf, 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 *gofpdf.Fpdf, 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 *gofpdf.Fpdf, 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 *gofpdf.Fpdf, bcode barcode.Barcode, err error) string { +	if err != nil { +		pdf.SetError(err) +	} + +	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 *gofpdf.Fpdf, 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 *gofpdf.Fpdf, value float64) float64 { +	return value * pdf.GetConversionRatio() / 72 * 96 +} diff --git a/contrib/barcode/barcode_test.go b/contrib/barcode/barcode_test.go new file mode 100644 index 0000000..c12ff12 --- /dev/null +++ b/contrib/barcode/barcode_test.go @@ -0,0 +1,126 @@ +package barcode_test + +import ( +	"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) +		barcode.Barcode(pdf, key, 15, 15, 100, 10, 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") +	barcode.Barcode(pdf, key, 15, 15, 100, 10, false) + +	fileStr := example.Filename("contrib_barcode_RegisterCodabar") +	err := pdf.OutputFileAndClose(fileStr) +	example.Summary(err, fileStr) +	// Output: +	// Successfully generated ../../pdf/contrib_barcode_RegisterCodabar.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, 20, 20, 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, 20, false) + +	fileStr := example.Filename("contrib_barcode_RegisterTwoOfFive") +	err := pdf.OutputFileAndClose(fileStr) +	example.Summary(err, fileStr) +	// Output: +	// Successfully generated ../../pdf/contrib_barcode_RegisterTwoOfFive.pdf +} | 
