From caed6a338466079a637af39db2836b5f4b1771a9 Mon Sep 17 00:00:00 2001 From: Kurt Jung Date: Fri, 2 Aug 2013 14:59:27 -0400 Subject: Initial commit into mercurial --- fpdf_test.go | 627 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 627 insertions(+) create mode 100644 fpdf_test.go (limited to 'fpdf_test.go') diff --git a/fpdf_test.go b/fpdf_test.go new file mode 100644 index 0000000..7440a3b --- /dev/null +++ b/fpdf_test.go @@ -0,0 +1,627 @@ +/* + * 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 + +import ( + "bufio" + "fmt" + "io/ioutil" + "os" + "strings" + "testing" +) + +// 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 *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 *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 +} + +func ExampleFpdf_tutorial01() { + pdf := New("P", "mm", "A4", FONT_DIR) + pdf.AddPage() + pdf.SetFont("Arial", "B", 16) + pdf.Cell(40, 10, "Hello World!") + pdf.Output(docWriter(pdf, 1)) + // Output: + // Successfully generated pdf/tutorial01.pdf +} + +func ExampleFpdf_tutorial02() { + pdf := 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.Output(docWriter(pdf, 2)) + // Output: + // Successfully generated pdf/tutorial02.pdf +} + +func ExampleFpdf_tutorial03() { + pdf := 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.Output(docWriter(pdf, 3)) + // Output: + // Successfully generated pdf/tutorial03.pdf +} + +func ExampleFpdf_tutorial04() { + var y0 float64 + var crrntCol int + pdf := 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.Output(docWriter(pdf, 4)) + // Output: + // Successfully generated pdf/tutorial04.pdf +} + +func ExampleFpdf_tutorial05() { + pdf := 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.Output(docWriter(pdf, 5)) + // Output: + // Successfully generated pdf/tutorial05.pdf +} + +func ExampleFpdf_tutorial06() { + var boldLvl, italicLvl, underscoreLvl int + var hrefStr string + pdf := 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.Output(docWriter(pdf, 6)) + // Output: + // Successfully generated pdf/tutorial06.pdf +} + +func ExampleFpdf_tutorial07() { + pdf := New("P", "mm", "A4", FONT_DIR) + pdf.AddFont("Calligrapher", "", "calligra.json") + // pdf.AddFont("Marcellus-Regular", "", "Marcellus-Regular.json") + // pdf.AddFont("URWPalladioL-Roma", "", "p052003l.json") + pdf.AddPage() + pdf.SetFont("Calligrapher", "", 35) + // pdf.SetFont("Marcellus-Regular", "", 35) + // pdf.SetFont("URWPalladioL-Roma", "", 35) + pdf.Cell(0, 10, "Enjoy new fonts with FPDF!") + pdf.Output(docWriter(pdf, 7)) + // Output: + // Successfully generated pdf/tutorial07.pdf +} + +func ExampleFpdf_tutorial08() { + pdf := 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.Output(docWriter(pdf, 8)) + // Output: + // Successfully generated pdf/tutorial08.pdf +} + +func ExampleFpdf_tutorial09() { + var y0 float64 + var crrntCol int + loremStr := "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." + pdf := 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.Output(docWriter(pdf, 9)) + // Output: + // Successfully generated pdf/tutorial09.pdf +} + +// Test the corner cases as reported by the gocov tool +func TestFpdf(t *testing.T) { + var nw nullWriter + tmpDirStr := os.TempDir() + MakeFont(FONT_DIR+"/calliga.ttf", FONT_DIR+"/cp1252.map", tmpDirStr, nil, true) + pdf := New("", "", "", "") + pdf.SetFontLocation(FONT_DIR) + pdf.SetTitle("世界", true) + pdf.SetAuthor("世界", true) + pdf.SetSubject("世界", true) + pdf.SetCreator("世界", true) + pdf.SetKeywords("世界", true) + pdf.Output(&nw) + if len(pdf.String()) < 1 { + t.Fatalf("Trouble with pdf.String()") + } + err := pdf.Error() + if err != nil { + t.Fatal(err) + } + if pdf.Err() { + t.Fatal(pdf.Error()) + } +} -- cgit v1.2.1-24-ge1ad