/*
* Copyright (c) 2013 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 gofpdf_test
import (
"bufio"
"code.google.com/p/gofpdf"
"fmt"
"io/ioutil"
"os"
"regexp"
"strings"
)
// Absolute path needed for gocov tool; relative OK for test
const (
GOFPDF_DIR = "."
FONT_DIR = GOFPDF_DIR + "/font"
IMG_DIR = GOFPDF_DIR + "/image"
TEXT_DIR = GOFPDF_DIR + "/text"
)
type nullWriter struct {
}
func (nw *nullWriter) Write(p []byte) (n int, err error) {
n = len(p)
return
}
func (nw *nullWriter) Close() (err error) {
return
}
type pdfWriter struct {
pdf *gofpdf.Fpdf
fl *os.File
idx int
}
func (pw *pdfWriter) Write(p []byte) (n int, err error) {
if pw.pdf.Ok() {
return pw.fl.Write(p)
}
return
}
func (pw *pdfWriter) Close() (err error) {
if pw.fl != nil {
pw.fl.Close()
pw.fl = nil
}
if pw.pdf.Ok() {
fmt.Printf("Successfully generated pdf/tutorial%02d.pdf\n", pw.idx)
} else {
fmt.Printf("%s\n", pw.pdf.Error())
}
return
}
func docWriter(pdf *gofpdf.Fpdf, idx int) *pdfWriter {
pw := new(pdfWriter)
pw.pdf = pdf
pw.idx = idx
if pdf.Ok() {
var err error
fileStr := fmt.Sprintf("%s/pdf/tutorial%02d.pdf", GOFPDF_DIR, idx)
pw.fl, err = os.Create(fileStr)
if err != nil {
pdf.SetErrorf("Error opening output file %s", fileStr)
}
}
return pw
}
// Convert 'ABCDEFG' to, for example, 'A,BCD,EFG'
func strDelimit(str string, sepstr string, sepcount int) string {
pos := len(str) - sepcount
for pos > 0 {
str = str[:pos] + sepstr + str[pos:]
pos = pos - sepcount
}
return str
}
type htmlSegmentType struct {
cat byte // 'O' open tag, 'C' close tag, 'T' text
str string // Literal text unchanged, tags are lower case
attr map[string]string // Attribute keys are lower case
}
// Returns a list of HTML tags and literal elements. This is done with regular
// expressions, so the result is only marginally better than useless.
// Adapted from http://www.fpdf.org/
func htmlTokenize(htmlStr string) (list []htmlSegmentType) {
list = make([]htmlSegmentType, 0, 16)
htmlStr = strings.Replace(htmlStr, "\n", " ", -1)
htmlStr = strings.Replace(htmlStr, "\r", "", -1)
tagRe, _ := regexp.Compile(`(?U)<.*>`)
attrRe, _ := regexp.Compile(`([^=]+)=["']?([^"']+)`)
capList := tagRe.FindAllStringIndex(htmlStr, -1)
if capList != nil {
var seg htmlSegmentType
var parts []string
pos := 0
for _, cap := range capList {
if pos < cap[0] {
seg.cat = 'T'
seg.str = htmlStr[pos:cap[0]]
seg.attr = nil
list = append(list, seg)
}
if htmlStr[cap[0]+1] == '/' {
seg.cat = 'C'
seg.str = strings.ToLower(htmlStr[cap[0]+2 : cap[1]-1])
seg.attr = nil
list = append(list, seg)
} else {
// Extract attributes
parts = strings.Split(htmlStr[cap[0]+1:cap[1]-1], " ")
if len(parts) > 0 {
for j, part := range parts {
if j == 0 {
seg.cat = 'O'
seg.str = strings.ToLower(parts[0])
seg.attr = make(map[string]string)
} else {
attrList := attrRe.FindAllStringSubmatch(part, -1)
if attrList != nil {
for _, attr := range attrList {
seg.attr[strings.ToLower(attr[1])] = attr[2]
}
}
}
}
list = append(list, seg)
}
}
pos = cap[1]
}
if len(htmlStr) > pos {
seg.cat = 'T'
seg.str = htmlStr[pos:]
seg.attr = nil
list = append(list, seg)
}
}
return
}
func lorem() string {
return "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod " +
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis " +
"nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis " +
"aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat " +
"nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui " +
"officia deserunt mollit anim id est laborum."
}
// Hello, world
func ExampleFpdf_tutorial01() {
pdf := gofpdf.New("P", "mm", "A4", FONT_DIR)
pdf.AddPage()
pdf.SetFont("Arial", "B", 16)
pdf.Cell(40, 10, "Hello World!")
pdf.OutputAndClose(docWriter(pdf, 1))
// Output:
// Successfully generated pdf/tutorial01.pdf
}
// Header, footer and page-breaking
func ExampleFpdf_tutorial02() {
pdf := gofpdf.New("P", "mm", "A4", FONT_DIR)
pdf.SetHeaderFunc(func() {
pdf.Image(IMG_DIR+"/logo.png", 10, 6, 30, 0, false, "", 0, "")
pdf.SetY(5)
pdf.SetFont("Arial", "B", 15)
pdf.Cell(80, 0, "")
pdf.CellFormat(30, 10, "Title", "1", 0, "C", false, 0, "")
pdf.Ln(20)
})
pdf.SetFooterFunc(func() {
pdf.SetY(-15)
pdf.SetFont("Arial", "I", 8)
pdf.CellFormat(0, 10, fmt.Sprintf("Page %d/{nb}", pdf.PageNo()), "", 0, "C", false, 0, "")
})
pdf.AliasNbPages("")
pdf.AddPage()
pdf.SetFont("Times", "", 12)
for j := 1; j <= 40; j++ {
pdf.CellFormat(0, 10, fmt.Sprintf("Printing line number %d", j), "", 1, "", false, 0, "")
}
pdf.OutputAndClose(docWriter(pdf, 2))
// Output:
// Successfully generated pdf/tutorial02.pdf
}
// Word-wrapping, line justification and page-breaking
func ExampleFpdf_tutorial03() {
pdf := gofpdf.New("P", "mm", "A4", FONT_DIR)
titleStr := "20000 Leagues Under the Seas"
pdf.SetTitle(titleStr, false)
pdf.SetAuthor("Jules Verne", false)
pdf.SetHeaderFunc(func() {
// Arial bold 15
pdf.SetFont("Arial", "B", 15)
// Calculate width of title and position
wd := pdf.GetStringWidth(titleStr) + 6
pdf.SetX((210 - wd) / 2)
// Colors of frame, background and text
pdf.SetDrawColor(0, 80, 180)
pdf.SetFillColor(230, 230, 0)
pdf.SetTextColor(220, 50, 50)
// Thickness of frame (1 mm)
pdf.SetLineWidth(1)
// Title
pdf.CellFormat(wd, 9, titleStr, "1", 1, "C", true, 0, "")
// Line break
pdf.Ln(10)
})
pdf.SetFooterFunc(func() {
// Position at 1.5 cm from bottom
pdf.SetY(-15)
// Arial italic 8
pdf.SetFont("Arial", "I", 8)
// Text color in gray
pdf.SetTextColor(128, 128, 128)
// Page number
pdf.CellFormat(0, 10, fmt.Sprintf("Page %d", pdf.PageNo()), "", 0, "C", false, 0, "")
})
chapterTitle := func(chapNum int, titleStr string) {
// // Arial 12
pdf.SetFont("Arial", "", 12)
// Background color
pdf.SetFillColor(200, 220, 255)
// Title
pdf.CellFormat(0, 6, fmt.Sprintf("Chapter %d : %s", chapNum, titleStr), "", 1, "L", true, 0, "")
// Line break
pdf.Ln(4)
}
chapterBody := func(fileStr string) {
// Read text file
txtStr, err := ioutil.ReadFile(fileStr)
if err != nil {
pdf.SetError(err)
}
// Times 12
pdf.SetFont("Times", "", 12)
// Output justified text
pdf.MultiCell(0, 5, string(txtStr), "", "", false)
// Line break
pdf.Ln(-1)
// Mention in italics
pdf.SetFont("", "I", 0)
pdf.Cell(0, 5, "(end of excerpt)")
}
printChapter := func(chapNum int, titleStr, fileStr string) {
pdf.AddPage()
chapterTitle(chapNum, titleStr)
chapterBody(fileStr)
}
printChapter(1, "A RUNAWAY REEF", TEXT_DIR+"/20k_c1.txt")
printChapter(2, "THE PROS AND CONS", TEXT_DIR+"/20k_c2.txt")
pdf.OutputAndClose(docWriter(pdf, 3))
// Output:
// Successfully generated pdf/tutorial03.pdf
}
// Multiple column layout
func ExampleFpdf_tutorial04() {
var y0 float64
var crrntCol int
pdf := gofpdf.New("P", "mm", "A4", FONT_DIR)
titleStr := "20000 Leagues Under the Seas"
pdf.SetTitle(titleStr, false)
pdf.SetAuthor("Jules Verne", false)
setCol := func(col int) {
// Set position at a given column
crrntCol = col
x := 10.0 + float64(col)*65.0
pdf.SetLeftMargin(x)
pdf.SetX(x)
}
chapterTitle := func(chapNum int, titleStr string) {
// Arial 12
pdf.SetFont("Arial", "", 12)
// Background color
pdf.SetFillColor(200, 220, 255)
// Title
pdf.CellFormat(0, 6, fmt.Sprintf("Chapter %d : %s", chapNum, titleStr), "", 1, "L", true, 0, "")
// Line break
pdf.Ln(4)
y0 = pdf.GetY()
}
chapterBody := func(fileStr string) {
// Read text file
txtStr, err := ioutil.ReadFile(fileStr)
if err != nil {
pdf.SetError(err)
}
// Font
pdf.SetFont("Times", "", 12)
// Output text in a 6 cm width column
pdf.MultiCell(60, 5, string(txtStr), "", "", false)
pdf.Ln(-1)
// Mention
pdf.SetFont("", "I", 0)
pdf.Cell(0, 5, "(end of excerpt)")
// Go back to first column
setCol(0)
}
printChapter := func(num int, titleStr, fileStr string) {
// Add chapter
pdf.AddPage()
chapterTitle(num, titleStr)
chapterBody(fileStr)
}
pdf.SetAcceptPageBreakFunc(func() bool {
// Method accepting or not automatic page break
if crrntCol < 2 {
// Go to next column
setCol(crrntCol + 1)
// Set ordinate to top
pdf.SetY(y0)
// Keep on page
return false
} else {
// Go back to first column
setCol(0)
// Page break
return true
}
})
pdf.SetHeaderFunc(func() {
// Arial bold 15
pdf.SetFont("Arial", "B", 15)
// Calculate width of title and position
wd := pdf.GetStringWidth(titleStr) + 6
pdf.SetX((210 - wd) / 2)
// Colors of frame, background and text
pdf.SetDrawColor(0, 80, 180)
pdf.SetFillColor(230, 230, 0)
pdf.SetTextColor(220, 50, 50)
// Thickness of frame (1 mm)
pdf.SetLineWidth(1)
// Title
pdf.CellFormat(wd, 9, titleStr, "1", 1, "C", true, 0, "")
// Line break
pdf.Ln(10)
// Save ordinate
y0 = pdf.GetY()
})
pdf.SetFooterFunc(func() {
// Position at 1.5 cm from bottom
pdf.SetY(-15)
// Arial italic 8
pdf.SetFont("Arial", "I", 8)
// Text color in gray
pdf.SetTextColor(128, 128, 128)
// Page number
pdf.CellFormat(0, 10, fmt.Sprintf("Page %d", pdf.PageNo()), "", 0, "C", false, 0, "")
})
printChapter(1, "A RUNAWAY REEF", TEXT_DIR+"/20k_c1.txt")
printChapter(2, "THE PROS AND CONS", TEXT_DIR+"/20k_c2.txt")
pdf.OutputAndClose(docWriter(pdf, 4))
// Output:
// Successfully generated pdf/tutorial04.pdf
}
// Various table styles
func ExampleFpdf_tutorial05() {
pdf := gofpdf.New("P", "mm", "A4", FONT_DIR)
type countryType struct {
nameStr, capitalStr, areaStr, popStr string
}
countryList := make([]countryType, 0, 8)
header := []string{"Country", "Capital", "Area (sq km)", "Pop. (thousands)"}
loadData := func(fileStr string) {
fl, err := os.Open(fileStr)
if err == nil {
scanner := bufio.NewScanner(fl)
var c countryType
for scanner.Scan() {
// Austria;Vienna;83859;8075
lineStr := scanner.Text()
list := strings.Split(lineStr, ";")
if len(list) == 4 {
c.nameStr = list[0]
c.capitalStr = list[1]
c.areaStr = list[2]
c.popStr = list[3]
countryList = append(countryList, c)
} else {
err = fmt.Errorf("Error tokenizing %s", lineStr)
}
}
fl.Close()
if len(countryList) == 0 {
err = fmt.Errorf("Error loading data from %s", fileStr)
}
}
if err != nil {
pdf.SetError(err)
}
}
// Simple table
basicTable := func() {
for _, str := range header {
pdf.CellFormat(40, 7, str, "1", 0, "", false, 0, "")
}
pdf.Ln(-1)
for _, c := range countryList {
pdf.CellFormat(40, 6, c.nameStr, "1", 0, "", false, 0, "")
pdf.CellFormat(40, 6, c.capitalStr, "1", 0, "", false, 0, "")
pdf.CellFormat(40, 6, c.areaStr, "1", 0, "", false, 0, "")
pdf.CellFormat(40, 6, c.popStr, "1", 0, "", false, 0, "")
pdf.Ln(-1)
}
}
// Better table
improvedTable := func() {
// Column widths
w := []float64{40.0, 35.0, 40.0, 45.0}
wSum := 0.0
for _, v := range w {
wSum += v
}
// Header
for j, str := range header {
pdf.CellFormat(w[j], 7, str, "1", 0, "C", false, 0, "")
}
pdf.Ln(-1)
// Data
for _, c := range countryList {
pdf.CellFormat(w[0], 6, c.nameStr, "LR", 0, "", false, 0, "")
pdf.CellFormat(w[1], 6, c.capitalStr, "LR", 0, "", false, 0, "")
pdf.CellFormat(w[2], 6, strDelimit(c.areaStr, ",", 3), "LR", 0, "R", false, 0, "")
pdf.CellFormat(w[3], 6, strDelimit(c.popStr, ",", 3), "LR", 0, "R", false, 0, "")
pdf.Ln(-1)
}
pdf.CellFormat(wSum, 0, "", "T", 0, "", false, 0, "")
}
// Colored table
fancyTable := func() {
// Colors, line width and bold font
pdf.SetFillColor(255, 0, 0)
pdf.SetTextColor(255, 255, 255)
pdf.SetDrawColor(128, 0, 0)
pdf.SetLineWidth(.3)
pdf.SetFont("", "B", 0)
// Header
w := []float64{40, 35, 40, 45}
wSum := 0.0
for _, v := range w {
wSum += v
}
for j, str := range header {
pdf.CellFormat(w[j], 7, str, "1", 0, "C", true, 0, "")
}
pdf.Ln(-1)
// Color and font restoration
pdf.SetFillColor(224, 235, 255)
pdf.SetTextColor(0, 0, 0)
pdf.SetFont("", "", 0)
// Data
fill := false
for _, c := range countryList {
pdf.CellFormat(w[0], 6, c.nameStr, "LR", 0, "", fill, 0, "")
pdf.CellFormat(w[1], 6, c.capitalStr, "LR", 0, "", fill, 0, "")
pdf.CellFormat(w[2], 6, strDelimit(c.areaStr, ",", 3), "LR", 0, "R", fill, 0, "")
pdf.CellFormat(w[3], 6, strDelimit(c.popStr, ",", 3), "LR", 0, "R", fill, 0, "")
pdf.Ln(-1)
fill = !fill
}
pdf.CellFormat(wSum, 0, "", "T", 0, "", false, 0, "")
}
loadData(TEXT_DIR + "/countries.txt")
pdf.SetFont("Arial", "", 14)
pdf.AddPage()
basicTable()
pdf.AddPage()
improvedTable()
pdf.AddPage()
fancyTable()
pdf.OutputAndClose(docWriter(pdf, 5))
// Output:
// Successfully generated pdf/tutorial05.pdf
}
// Internal and external links
func ExampleFpdf_tutorial06() {
var boldLvl, italicLvl, underscoreLvl int
var hrefStr string
pdf := gofpdf.New("P", "mm", "A4", FONT_DIR)
setStyle := func(boldAdj, italicAdj, underscoreAdj int) {
styleStr := ""
boldLvl += boldAdj
if boldLvl > 0 {
styleStr += "B"
}
italicLvl += italicAdj
if italicLvl > 0 {
styleStr += "I"
}
underscoreLvl += underscoreAdj
if underscoreLvl > 0 {
styleStr += "U"
}
pdf.SetFont("", styleStr, 0)
}
putLink := func(urlStr, txtStr string) {
// Put a hyperlink
pdf.SetTextColor(0, 0, 255)
setStyle(0, 0, 1)
pdf.WriteLinkString(5, txtStr, urlStr)
setStyle(0, 0, -1)
pdf.SetTextColor(0, 0, 0)
}
writeHtml := func(htmlStr string) {
list := htmlTokenize(htmlStr)
var ok bool
for _, el := range list {
switch el.cat {
case 'T':
if len(hrefStr) > 0 {
putLink(hrefStr, el.str)
hrefStr = ""
} else {
pdf.Write(5, el.str)
}
case 'O':
switch el.str {
case "b":
setStyle(1, 0, 0)
case "i":
setStyle(0, 1, 0)
case "u":
setStyle(0, 0, 1)
case "br":
pdf.Ln(5)
case "a":
hrefStr, ok = el.attr["href"]
if !ok {
hrefStr = ""
}
}
case 'C':
switch el.str {
case "b":
setStyle(-1, 0, 0)
case "i":
setStyle(0, -1, 0)
case "u":
setStyle(0, 0, -1)
}
}
}
}
// First page
pdf.AddPage()
pdf.SetFont("Arial", "", 20)
pdf.Write(5, "To find out what's new in this tutorial, click ")
pdf.SetFont("", "U", 0)
link := pdf.AddLink()
pdf.WriteLinkId(5, "here", link)
pdf.SetFont("", "", 0)
// Second page
pdf.AddPage()
pdf.SetLink(link, 0, -1)
pdf.Image(IMG_DIR+"/logo.png", 10, 12, 30, 0, false, "", 0, "http://www.fpdf.org")
pdf.SetLeftMargin(45)
pdf.SetFontSize(14)
htmlStr := `You can now easily print text mixing different styles: bold, ` +
`italic, underlined, or all at once!
` +
`You can also insert links on text, such as ` +
`www.fpdf.org, or on an image: click on the logo.`
writeHtml(htmlStr)
pdf.OutputAndClose(docWriter(pdf, 6))
// Output:
// Successfully generated pdf/tutorial06.pdf
}
// Non-standard font
func ExampleFpdf_tutorial07() {
pdf := gofpdf.New("P", "mm", "A4", FONT_DIR)
pdf.AddFont("Calligrapher", "", "calligra.json")
pdf.AddPage()
pdf.SetFont("Calligrapher", "", 35)
pdf.Cell(0, 10, "Enjoy new fonts with FPDF!")
pdf.OutputAndClose(docWriter(pdf, 7))
// Output:
// Successfully generated pdf/tutorial07.pdf
}
// Various image types
func ExampleFpdf_tutorial08() {
pdf := gofpdf.New("P", "mm", "A4", FONT_DIR)
pdf.AddPage()
pdf.SetFont("Arial", "", 11)
pdf.Image(IMG_DIR+"/logo.png", 10, 10, 30, 0, false, "", 0, "")
pdf.Text(50, 20, "logo.png")
pdf.Image(IMG_DIR+"/logo.gif", 10, 40, 30, 0, false, "", 0, "")
pdf.Text(50, 50, "logo.gif")
pdf.Image(IMG_DIR+"/logo-gray.png", 10, 70, 30, 0, false, "", 0, "")
pdf.Text(50, 80, "logo-gray.png")
pdf.Image(IMG_DIR+"/logo-rgb.png", 10, 100, 30, 0, false, "", 0, "")
pdf.Text(50, 110, "logo-rgb.png")
pdf.Image(IMG_DIR+"/logo.jpg", 10, 130, 30, 0, false, "", 0, "")
pdf.Text(50, 140, "logo.jpg")
pdf.OutputAndClose(docWriter(pdf, 8))
// Output:
// Successfully generated pdf/tutorial08.pdf
}
// Landscape mode with logos
func ExampleFpdf_tutorial09() {
var y0 float64
var crrntCol int
loremStr := lorem()
pdf := gofpdf.New("L", "mm", "A4", FONT_DIR)
const (
pageWd = 297.0 // A4 210.0 x 297.0
margin = 10.0
gutter = 4
colNum = 3
colWd = (pageWd - 2*margin - (colNum-1)*gutter) / colNum
)
setCol := func(col int) {
crrntCol = col
x := margin + float64(col)*(colWd+gutter)
pdf.SetLeftMargin(x)
pdf.SetX(x)
}
pdf.SetHeaderFunc(func() {
titleStr := "gofpdf"
pdf.SetFont("Helvetica", "B", 48)
wd := pdf.GetStringWidth(titleStr) + 6
pdf.SetX((pageWd - wd) / 2)
pdf.SetTextColor(128, 128, 160)
pdf.Write(12, titleStr[:2])
pdf.SetTextColor(128, 128, 128)
pdf.Write(12, titleStr[2:])
pdf.Ln(20)
y0 = pdf.GetY()
})
pdf.SetAcceptPageBreakFunc(func() bool {
if crrntCol < colNum-1 {
setCol(crrntCol + 1)
pdf.SetY(y0)
// Start new column, not new page
return false
} else {
setCol(0)
return true
}
})
pdf.AddPage()
pdf.SetFont("Times", "", 12)
for j := 0; j < 20; j++ {
if j == 1 {
pdf.Image(IMG_DIR+"/fpdf.png", -1, 0, colWd, 0, true, "", 0, "")
} else if j == 5 {
pdf.Image(IMG_DIR+"/golang-gopher.png", -1, 0, colWd, 0, true, "", 0, "")
}
pdf.MultiCell(colWd, 5, loremStr, "", "", false)
pdf.Ln(-1)
}
pdf.OutputAndClose(docWriter(pdf, 9))
// Output:
// Successfully generated pdf/tutorial09.pdf
}
// Test the corner cases as reported by the gocov tool
func ExampleFpdf_tutorial10() {
gofpdf.MakeFont(FONT_DIR+"/calligra.ttf", FONT_DIR+"/cp1252.map", FONT_DIR, nil, true)
pdf := gofpdf.New("", "", "", "")
pdf.SetFontLocation(FONT_DIR)
pdf.SetTitle("世界", true)
pdf.SetAuthor("世界", true)
pdf.SetSubject("世界", true)
pdf.SetCreator("世界", true)
pdf.SetKeywords("世界", true)
pdf.AddFont("Calligrapher", "", "calligra.json")
pdf.AddPage()
pdf.SetFont("Calligrapher", "", 16)
pdf.Writef(5, "\x95 %s \x95", pdf)
pdf.OutputAndClose(docWriter(pdf, 10))
// Output:
// Successfully generated pdf/tutorial10.pdf
}
// Geometric figures
func ExampleFpdf_tutorial11() {
const (
thin = 0.2
thick = 3.0
)
pdf := gofpdf.New("", "", "", FONT_DIR)
pdf.SetFont("Helvetica", "", 12)
pdf.SetFillColor(200, 200, 220)
pdf.AddPage()
y := 15.0
pdf.Text(10, y, "Circles")
pdf.SetFillColor(200, 200, 220)
pdf.SetLineWidth(thin)
pdf.Circle(20, y+15, 10, "D")
pdf.Circle(45, y+15, 10, "F")
pdf.Circle(70, y+15, 10, "FD")
pdf.SetLineWidth(thick)
pdf.Circle(95, y+15, 10, "FD")
pdf.SetLineWidth(thin)
y += 40.0
pdf.Text(10, y, "Ellipses")
pdf.SetFillColor(220, 200, 200)
pdf.Ellipse(30, y+15, 20, 10, 0, "D")
pdf.Ellipse(75, y+15, 20, 10, 0, "F")
pdf.Ellipse(120, y+15, 20, 10, 0, "FD")
pdf.SetLineWidth(thick)
pdf.Ellipse(165, y+15, 20, 10, 0, "FD")
pdf.SetLineWidth(thin)
y += 40.0
pdf.Text(10, y, "Curves (quadratic)")
pdf.SetFillColor(220, 220, 200)
pdf.Curve(10, y+30, 15, y-20, 40, y+30, "D")
pdf.Curve(45, y+30, 50, y-20, 75, y+30, "F")
pdf.Curve(80, y+30, 85, y-20, 110, y+30, "FD")
pdf.SetLineWidth(thick)
pdf.Curve(115, y+30, 120, y-20, 145, y+30, "FD")
pdf.SetLineCapStyle("round")
pdf.Curve(150, y+30, 155, y-20, 180, y+30, "FD")
pdf.SetLineWidth(thin)
pdf.SetLineCapStyle("butt")
y += 40.0
pdf.Text(10, y, "Curves (cubic)")
pdf.SetFillColor(220, 200, 220)
pdf.CurveCubic(10, y+30, 15, y-20, 40, y+30, 10, y+30, "D")
pdf.CurveCubic(45, y+30, 50, y-20, 75, y+30, 45, y+30, "F")
pdf.CurveCubic(80, y+30, 85, y-20, 110, y+30, 80, y+30, "FD")
pdf.SetLineWidth(thick)
pdf.CurveCubic(115, y+30, 120, y-20, 145, y+30, 115, y+30, "FD")
pdf.SetLineCapStyle("round")
pdf.CurveCubic(150, y+30, 155, y-20, 180, y+30, 150, y+30, "FD")
pdf.SetLineWidth(thin)
pdf.SetLineCapStyle("butt")
y += 40.0
pdf.Text(10, y, "Arcs")
pdf.SetFillColor(200, 220, 220)
pdf.SetLineWidth(thick)
pdf.Arc(45, y+35, 20, 10, 0, 0, 180, "FD")
pdf.SetLineWidth(thin)
pdf.Arc(45, y+35, 25, 15, 0, 90, 270, "D")
pdf.SetLineWidth(thick)
pdf.Arc(45, y+35, 30, 20, 0, 0, 360, "D")
pdf.SetLineCapStyle("round")
pdf.Arc(135, y+35, 20, 10, 135, 0, 180, "FD")
pdf.SetLineWidth(thin)
pdf.Arc(135, y+35, 25, 15, 135, 90, 270, "D")
pdf.SetLineWidth(thick)
pdf.Arc(135, y+35, 30, 20, 135, 0, 360, "D")
pdf.SetLineWidth(thin)
pdf.SetLineCapStyle("butt")
pdf.OutputAndClose(docWriter(pdf, 11))
// Output:
// Successfully generated pdf/tutorial11.pdf
}
// Transparency
func ExampleFpdf_tutorial12() {
const (
gapX = 10.0
gapY = 9.0
rectW = 40.0
rectH = 58.0
pageW = 210
pageH = 297
)
modeList := []string{"Normal", "Multiply", "Screen", "Overlay",
"Darken", "Lighten", "ColorDodge", "ColorBurn", "HardLight", "SoftLight",
"Difference", "Exclusion", "Hue", "Saturation", "Color", "Luminosity"}
pdf := gofpdf.New("", "", "", FONT_DIR)
pdf.SetLineWidth(2)
pdf.SetAutoPageBreak(false, 0)
pdf.AddPage()
pdf.SetFont("Helvetica", "", 18)
pdf.SetXY(0, gapY)
pdf.SetTextColor(0, 0, 0)
pdf.CellFormat(pageW, gapY, "Alpha Blending Modes", "", 0, "C", false, 0, "")
j := 0
y := 3 * gapY
for col := 0; col < 4; col++ {
x := gapX
for row := 0; row < 4; row++ {
pdf.Rect(x, y, rectW, rectH, "D")
pdf.SetFont("Helvetica", "B", 12)
pdf.SetFillColor(0, 0, 0)
pdf.SetTextColor(250, 250, 230)
pdf.SetXY(x, y+rectH-4)
pdf.CellFormat(rectW, 5, modeList[j], "", 0, "C", true, 0, "")
pdf.SetFont("Helvetica", "I", 150)
pdf.SetTextColor(80, 80, 120)
pdf.SetXY(x, y+2)
pdf.CellFormat(rectW, rectH, "A", "", 0, "C", false, 0, "")
pdf.SetAlpha(0.5, modeList[j])
pdf.Image(IMG_DIR+"/golang-gopher.png", x-gapX, y, rectW+2*gapX, 0, false, "", 0, "")
pdf.SetAlpha(1.0, "Normal")
x += rectW + gapX
j++
}
y += rectH + gapY
}
pdf.OutputAndClose(docWriter(pdf, 12))
// Output:
// Successfully generated pdf/tutorial12.pdf
}
// Gradients
func ExampleFpdf_tutorial13() {
pdf := gofpdf.New("", "", "", FONT_DIR)
pdf.SetFont("Helvetica", "", 12)
pdf.AddPage()
pdf.LinearGradient(0, 0, 210, 100, 250, 250, 255, 220, 220, 225, 0, 0, 0, .5)
pdf.LinearGradient(20, 25, 75, 75, 220, 220, 250, 80, 80, 220, 0, .2, 0, .8)
pdf.Rect(20, 25, 75, 75, "D")
pdf.LinearGradient(115, 25, 75, 75, 220, 220, 250, 80, 80, 220, 0, 0, 1, 1)
pdf.Rect(115, 25, 75, 75, "D")
pdf.RadialGradient(20, 120, 75, 75, 220, 220, 250, 80, 80, 220, 0.25, 0.75, 0.25, 0.75, 1)
pdf.Rect(20, 120, 75, 75, "D")
pdf.RadialGradient(115, 120, 75, 75, 220, 220, 250, 80, 80, 220, 0.25, 0.75, 0.75, 0.75, 0.75)
pdf.Rect(115, 120, 75, 75, "D")
pdf.OutputAndClose(docWriter(pdf, 13))
// Output:
// Successfully generated pdf/tutorial13.pdf
}
// Clipping examples
func ExampleFpdf_tutorial14() {
pdf := gofpdf.New("", "", "", FONT_DIR)
y := 10.0
pdf.AddPage()
pdf.SetFont("Helvetica", "", 24)
pdf.SetXY(0, y)
pdf.ClipText(10, y+12, "Clipping examples", false)
pdf.RadialGradient(10, y, 100, 20, 128, 128, 160, 32, 32, 48, 0.25, 0.5, 0.25, 0.5, 0.2)
pdf.ClipEnd()
y += 12
pdf.SetFont("Helvetica", "B", 120)
pdf.SetDrawColor(64, 80, 80)
pdf.SetLineWidth(.5)
pdf.ClipText(10, y+40, pdf.String(), true)
pdf.RadialGradient(10, y, 200, 50, 220, 220, 250, 80, 80, 220, 0.25, 0.5, 0.25, 0.5, 1)
pdf.ClipEnd()
y += 55
pdf.ClipRect(10, y, 105, 20, true)
pdf.SetFillColor(255, 255, 255)
pdf.Rect(10, y, 105, 20, "F")
pdf.ClipCircle(40, y+10, 15, false)
pdf.RadialGradient(25, y, 30, 30, 220, 250, 220, 40, 60, 40, 0.3, 0.85, 0.3, 0.85, 0.5)
pdf.ClipEnd()
pdf.ClipEllipse(80, y+10, 20, 15, false)
pdf.RadialGradient(60, y, 40, 30, 250, 220, 220, 60, 40, 40, 0.3, 0.85, 0.3, 0.85, 0.5)
pdf.ClipEnd()
pdf.ClipEnd()
y += 28
pdf.ClipEllipse(26, y+10, 16, 10, true)
pdf.Image(IMG_DIR+"/logo.jpg", 10, y, 32, 0, false, "JPG", 0, "")
pdf.ClipEnd()
pdf.ClipCircle(60, y+10, 10, true)
pdf.RadialGradient(50, y, 20, 20, 220, 220, 250, 40, 40, 60, 0.3, 0.7, 0.3, 0.7, 0.5)
pdf.ClipEnd()
pdf.ClipPolygon([]gofpdf.PointType{{80, y + 20}, {90, y}, {100, y + 20}}, true)
pdf.LinearGradient(80, y, 20, 20, 250, 220, 250, 60, 40, 60, 0.5, 1, 0.5, 0.5)
pdf.ClipEnd()
y += 30
pdf.SetLineWidth(.1)
pdf.SetDrawColor(180, 180, 180)
pdf.ClipRoundedRect(10, y, 120, 20, 5, true)
pdf.RadialGradient(10, y, 120, 20, 255, 255, 255, 240, 240, 220, 0.25, 0.75, 0.25, 0.75, 0.5)
pdf.SetXY(5, y-5)
pdf.SetFont("Times", "", 12)
pdf.MultiCell(130, 5, lorem(), "", "", false)
pdf.ClipEnd()
pdf.OutputAndClose(docWriter(pdf, 14))
// Output:
// Successfully generated pdf/tutorial14.pdf
}
// Page size example
func ExampleFpdf_tutorial15() {
pdf := gofpdf.NewCustom(&gofpdf.InitType{
UnitStr: "in",
Size: gofpdf.SizeType{6, 6},
FontDirStr: FONT_DIR,
})
pdf.SetMargins(0.5, 1, 0.5)
pdf.SetFont("Times", "", 14)
pdf.AddPageFormat("L", gofpdf.SizeType{3, 12})
pdf.SetXY(0.5, 1.5)
pdf.CellFormat(11, 0.2, "12 in x 3 in", "", 0, "C", false, 0, "")
pdf.AddPage() // Default size established in NewCustom()
pdf.SetXY(0.5, 3)
pdf.CellFormat(5, 0.2, "6 in x 6 in", "", 0, "C", false, 0, "")
pdf.AddPageFormat("P", gofpdf.SizeType{3, 12})
pdf.SetXY(0.5, 6)
pdf.CellFormat(2, 0.2, "3 in x 12 in", "", 0, "C", false, 0, "")
for j := 0; j <= 3; j++ {
wd, ht, u := pdf.PageSize(j)
fmt.Printf("%d: %6.2f %s, %6.2f %s\n", j, wd, u, ht, u)
}
pdf.OutputAndClose(docWriter(pdf, 15))
// Output:
// 0: 6.00 in, 6.00 in
// 1: 12.00 in, 3.00 in
// 2: 6.00 in, 6.00 in
// 3: 3.00 in, 12.00 in
// Successfully generated pdf/tutorial15.pdf
}
// Bookmark test
func ExampleFpdf_tutorial16() {
pdf := gofpdf.New("P", "mm", "A4", FONT_DIR)
pdf.AddPage()
pdf.SetFont("Arial", "", 15)
pdf.Bookmark("Page 1", 0, 0)
pdf.Bookmark("Paragraph 1", 1, -1)
pdf.Cell(0, 6, "Paragraph 1")
pdf.Ln(50)
pdf.Bookmark("Paragraph 2", 1, -1)
pdf.Cell(0, 6, "Paragraph 2")
pdf.AddPage()
pdf.Bookmark("Page 2", 0, 0)
pdf.Bookmark("Paragraph 3", 1, -1)
pdf.Cell(0, 6, "Paragraph 3")
pdf.OutputAndClose(docWriter(pdf, 16))
// Output:
// Successfully generated pdf/tutorial16.pdf
}
// Transformation test adapted from an example script by Moritz Wagner and
// Andreas Würmser.
func ExampleFpdf_tutorial17() {
const (
light = 200
dark = 0
)
var refX, refY float64
var refStr string
pdf := gofpdf.New("P", "mm", "A4", FONT_DIR)
pdf.AddPage()
color := func(val int) {
pdf.SetDrawColor(val, val, val)
pdf.SetTextColor(val, val, val)
}
reference := func(str string, x, y float64, val int) {
color(val)
pdf.Rect(x, y, 40, 10, "D")
pdf.Text(x, y-1, str)
}
refDraw := func(str string, x, y float64) {
refStr = str
refX = x
refY = y
reference(str, x, y, light)
}
refDupe := func() {
reference(refStr, refX, refY, dark)
}
titleStr := "Transformations"
titlePt := 36.0
titleHt := titlePt * 25.4 / 72.0
pdf.SetFont("Helvetica", "", titlePt)
titleWd := pdf.GetStringWidth(titleStr)
titleX := (210 - titleWd) / 2
pdf.Text(titleX, 10+titleHt, titleStr)
pdf.TransformBegin()
pdf.TransformMirrorVertical(10 + titleHt + 0.5)
pdf.ClipText(titleX, 10+titleHt, titleStr, false)
// Remember that the transform will mirror the gradient box too
pdf.LinearGradient(titleX, 10, titleWd, titleHt+4, 120, 120, 120, 255, 255, 255, 0, 0, 0, 0.6)
pdf.ClipEnd()
pdf.TransformEnd()
pdf.SetFont("Helvetica", "", 12)
// Scale by 150% centered by lower left corner of the rectangle
refDraw("Scale", 50, 60)
pdf.TransformBegin()
pdf.TransformScaleXY(150, 50, 70)
refDupe()
pdf.TransformEnd()
// Translate 7 to the right, 5 to the bottom
refDraw("Translate", 125, 60)
pdf.TransformBegin()
pdf.TransformTranslate(7, 5)
refDupe()
pdf.TransformEnd()
// Rotate 20 degrees counter-clockwise centered by the lower left corner of
// the rectangle
refDraw("Rotate", 50, 110)
pdf.TransformBegin()
pdf.TransformRotate(20, 50, 120)
refDupe()
pdf.TransformEnd()
// Skew 30 degrees along the x-axis centered by the lower left corner of the
// rectangle
refDraw("Skew", 125, 110)
pdf.TransformBegin()
pdf.TransformSkewX(30, 125, 110)
refDupe()
pdf.TransformEnd()
// Mirror horizontally with axis of reflection at left side of the rectangle
refDraw("Mirror horizontal", 50, 160)
pdf.TransformBegin()
pdf.TransformMirrorHorizontal(50)
refDupe()
pdf.TransformEnd()
// Mirror vertically with axis of reflection at bottom side of the rectangle
refDraw("Mirror vertical", 125, 160)
pdf.TransformBegin()
pdf.TransformMirrorVertical(170)
refDupe()
pdf.TransformEnd()
// Reflect against a point at the lower left point of rectangle
refDraw("Mirror point", 50, 210)
pdf.TransformBegin()
pdf.TransformMirrorPoint(50, 220)
refDupe()
pdf.TransformEnd()
// Mirror against a straight line described by a point and an angle
angle := -20.0
px := 120.0
py := 220.0
refDraw("Mirror line", 125, 210)
pdf.TransformBegin()
pdf.TransformRotate(angle, px, py)
pdf.Line(px-1, py-1, px+1, py+1)
pdf.Line(px-1, py+1, px+1, py-1)
pdf.Line(px-5, py, px+60, py)
pdf.TransformEnd()
pdf.TransformBegin()
pdf.TransformMirrorLine(angle, px, py)
refDupe()
pdf.TransformEnd()
pdf.OutputAndClose(docWriter(pdf, 17))
// Output:
// Successfully generated pdf/tutorial17.pdf
}