Code Monkey home page Code Monkey logo

fpdf's Introduction

GoFPDF document generator

GitHub release CI MIT licensed Report GoDoc

Package go-pdf/fpdf implements a PDF document generator with high level support for text, drawing and images.

Features

  • UTF-8 support
  • Choice of measurement unit, page format and margins
  • Page header and footer management
  • Automatic page breaks, line breaks, and text justification
  • Inclusion of JPEG, PNG, GIF, TIFF and basic path-only SVG images
  • Colors, gradients and alpha channel transparency
  • Outline bookmarks
  • Internal and external links
  • TrueType, Type1 and encoding support
  • Page compression
  • Lines, Bézier curves, arcs, and ellipses
  • Rotation, scaling, skewing, translation, and mirroring
  • Clipping
  • Document protection
  • Layers
  • Templates
  • Barcodes
  • Charting facility
  • Import PDFs as templates

gofpdf has no dependencies other than the Go standard library. All tests pass on Linux, Mac and Windows platforms.

gofpdf supports UTF-8 TrueType fonts and “right-to-left” languages. Note that Chinese, Japanese, and Korean characters may not be included in many general purpose fonts. For these languages, a specialized font (for example, NotoSansSC for simplified Chinese) can be used.

Also, support is provided to automatically translate UTF-8 runes to code page encodings for languages that have fewer than 256 glyphs.

Installation

To install the package on your system, run

go get github.com/go-pdf/fpdf

Later, to receive updates, run

go get -u -v github.com/go-pdf/fpdf/...

Quick Start

The following Go code generates a simple PDF file.

pdf := fpdf.New("P", "mm", "A4", "")
pdf.AddPage()
pdf.SetFont("Arial", "B", 16)
pdf.Cell(40, 10, "Hello, world")
err := pdf.OutputFileAndClose("hello.pdf")

See the functions in the fpdf_test.go file (shown as examples in this documentation) for more advanced PDF examples.

Errors

If an error occurs in an Fpdf method, an internal error field is set. After this occurs, Fpdf method calls typically return without performing any operations and the error state is retained. This error management scheme facilitates PDF generation since individual method calls do not need to be examined for failure; it is generally sufficient to wait until after Output() is called. For the same reason, if an error occurs in the calling application during PDF generation, it may be desirable for the application to transfer the error to the Fpdf instance by calling the SetError() method or the SetErrorf() method. At any time during the life cycle of the Fpdf instance, the error state can be determined with a call to Ok() or Err(). The error itself can be retrieved with a call to Error().

Conversion Notes

This package is a relatively straightforward translation from the original FPDF library written in PHP (despite the caveat in the introduction to Effective Go). The API names have been retained even though the Go idiom would suggest otherwise (for example, pdf.GetX() is used rather than simply pdf.X()). The similarity of the two libraries makes the original FPDF website a good source of information. It includes a forum and FAQ.

However, some internal changes have been made. Page content is built up using buffers (of type bytes.Buffer) rather than repeated string concatenation. Errors are handled as explained above rather than panicking. Output is generated through an interface of type io.Writer or io.WriteCloser. A number of the original PHP methods behave differently based on the type of the arguments that are passed to them; in these cases additional methods have been exported to provide similar functionality. Font definition files are produced in JSON rather than PHP.

Example PDFs

A side effect of running go test ./... is the production of a number of example PDFs. These can be found in the gofpdf/pdf directory after the tests complete.

Please note that these examples run in the context of a test. In order run an example as a standalone application, you’ll need to examine fpdf_test.go for some helper routines, for example exampleFilename() and summary().

Example PDFs can be compared with reference copies in order to verify that they have been generated as expected. This comparison will be performed if a PDF with the same name as the example PDF is placed in the fpdf/pdf/reference directory and if the third argument to ComparePDFFiles() in internal/example/example.go is true. (By default it is false.) The routine that summarizes an example will look for this file and, if found, will call ComparePDFFiles() to check the example PDF for equality with its reference PDF. If differences exist between the two files they will be printed to standard output and the test will fail. If the reference file is missing, the comparison is considered to succeed. In order to successfully compare two PDFs, the placement of internal resources must be consistent and the internal creation timestamps must be the same. To do this, the methods SetCatalogSort() and SetCreationDate() need to be called for both files. This is done automatically for all examples.

Nonstandard Fonts

Nothing special is required to use the standard PDF fonts (courier, helvetica, times, zapfdingbats) in your documents other than calling SetFont().

You should use AddUTF8Font() or AddUTF8FontFromBytes() to add a TrueType UTF-8 encoded font. Use RTL() and LTR() methods switch between “right-to-left” and “left-to-right” mode.

In order to use a different non-UTF-8 TrueType or Type1 font, you will need to generate a font definition file and, if the font will be embedded into PDFs, a compressed version of the font file. This is done by calling the MakeFont function or using the included makefont command line utility. To create the utility, cd into the makefont subdirectory and run “go build”. This will produce a standalone executable named makefont. Select the appropriate encoding file from the font subdirectory and run the command as in the following example.

./makefont --embed --enc=../font/cp1252.map --dst=../font ../font/calligra.ttf

In your PDF generation code, call AddFont() to load the font and, as with the standard fonts, SetFont() to begin using it. Most examples, including the package example, demonstrate this method. Good sources of free, open-source fonts include Google Fonts and DejaVu Fonts.

Related Packages

The draw2d package is a two dimensional vector graphics library that can generate output in different forms. It uses go-pdf/fpdf for its document production mode.

Contributing Changes

go-pdf/fpdf is a global community effort and you are invited to make it even better. If you have implemented a new feature or corrected a problem, please consider contributing your change to the project. A contribution that does not directly pertain to the core functionality of go-pdf/fpdf should be placed in its own directory directly beneath the contrib directory.

Here are guidelines for making submissions. Your change should

  • be compatible with the MIT License
  • be properly documented
  • be formatted with go fmt
  • include an example in fpdf_test.go if appropriate
  • conform to the standards of golint and go vet, that is, golint . and go vet . should not generate any warnings
  • not diminish test coverage

Pull requests are the preferred means of accepting your changes.

License

go-pdf/fpdf is released under the MIT License. It is copyrighted by Kurt Jung and the contributors acknowledged below.

Acknowledgments

Thank you to Kurt Jung who originally wrote gofpdf in 2013 - 2019. This package’s code and documentation are closely derived from the FPDF library created by Olivier Plathey, and a number of font and image resources are copied directly from it. Bruno Michel has provided valuable assistance with the code. Drawing support is adapted from the FPDF geometric figures script by David Hernández Sanz. Transparency support is adapted from the FPDF transparency script by Martin Hall-May. Support for gradients and clipping is adapted from FPDF scripts by Andreas Würmser. Support for outline bookmarks is adapted from Olivier Plathey by Manuel Cornes. Layer support is adapted from Olivier Plathey. Support for transformations is adapted from the FPDF transformation script by Moritz Wagner and Andreas Würmser. PDF protection is adapted from the work of Klemen Vodopivec for the FPDF product. Lawrence Kesteloot provided code to allow an image’s extent to be determined prior to placement. Support for vertical alignment within a cell was provided by Stefan Schroeder. Ivan Daniluk generalized the font and image loading code to use the Reader interface while maintaining backward compatibility. Anthony Starks provided code for the Polygon function. Robert Lillack provided the Beziergon function and corrected some naming issues with the internal curve function. Claudio Felber provided implementations for dashed line drawing and generalized font loading. Stani Michiels provided support for multi-segment path drawing with smooth line joins, line join styles, enhanced fill modes, and has helped greatly with package presentation and tests. Templating is adapted by Marcus Downing from the FPDF_Tpl library created by Jan Slabon and Setasign. Jelmer Snoeck contributed packages that generate a variety of barcodes and help with registering images on the web. Jelmer Snoek and Guillermo Pascual augmented the basic HTML functionality with aligned text. Kent Quirk implemented backwards-compatible support for reading DPI from images that support it, and for setting DPI manually and then having it properly taken into account when calculating image size. Paulo Coutinho provided support for static embedded fonts. Dan Meyers added support for embedded JavaScript. David Fish added a generic alias-replacement function to enable, among other things, table of contents functionality. Andy Bakun identified and corrected a problem in which the internal catalogs were not sorted stably. Paul Montag added encoding and decoding functionality for templates, including images that are embedded in templates; this allows templates to be stored independently of gofpdf. Paul also added support for page boxes used in printing PDF documents. Wojciech Matusiak added supported for word spacing. Artem Korotkiy added support of UTF-8 fonts. Dave Barnes added support for imported objects and templates. Brigham Thompson added support for rounded rectangles. Joe Westcott added underline functionality and optimized image storage. Benoit KUGLER contributed support for rectangles with corners of unequal radius, modification times, and for file attachments and annotations.

Roadmap

  • Remove all legacy code page font support; use UTF-8 exclusively
  • Improve test coverage as reported by the coverage tool.

fpdf's People

Contributors

benoitkugler avatar claudiofelber avatar d1ngd0 avatar danmeyers avatar darkfreedman avatar darrenmcc avatar divan avatar echa avatar eiskasten avatar flibustenet avatar hyzgh avatar jacobalberty avatar jelmersnoeck avatar joewestcott avatar jung-kurt avatar kveselkov avatar marcus-downing avatar moogle19 avatar mrtsbt avatar phpdave11 avatar rubenn avatar ruudk avatar sbinet avatar sbstjn avatar seletskiy avatar stanim avatar thierry-f-78 avatar tim-st avatar vinayaknagpal avatar wmatusiak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

fpdf's Issues

PDF Document Properties are garbled

After creating the FPDF object I set certain things like:

pdf.SetKeywords("one, two, three", false)
pdf.SetSubject("export of metadata", true)
pdf.SetTitle("Test document", false)
pdf.SetAuthor("John doe", false)

But as you can see from the image below, when viewing the document some of those properties are either garbled or empty. Even the title is garbled. It doesn't matter if I set the UTF8 flag to true or false.

IMG20240412133203.jpg

Generating PDF in Windows 10 vs Linux

This is a strange situation, but I am creating a cross-platform program which includes generating PDFs and I've noticed that PDFs generated in Windows contain a small horizontal line in the middle of the generated PDF, while in Linux there isn't. Furthermore, if I open the Windows-generated PDF in Linux the line is gone.

This only happens if I use CellFormat(), but not if I use Cell(). Help?

EDIT: I just noticed that if I open the PDFs generated in Linux on the Windows machine, there is a line. The line is not present if the PDF is opened in Linux.

Thank you for your time.

image methods in a deprecation loop

RegisterImage and RegisterImageReader are deprecated in favor of RegisterImageOptions and RegisterImageOptionsReader, which say to use Image to add the image to the page; RegisterImageOptionsReader in particular says "tp should be specified." On the other hand, Image is deprecated in favor of ImageOptions and says to see the latter for the description of the parameters, but ImageOptions doesn't have tp, and it says to use RegisterImage or RegisterImageReader to register the image if it isn't a plain file. There is no indication of what happens with the actual image options if I use both RegisterImageOptionsReader and ImageOptions, nor any explanation of tp that I am supposed to need with the former.

Need assistance in understanding TransformRotate()

Hi,

I am currently trying to rotate a block of text vertically in my PDF document and I have a hard time to understand how TransformRoate() operates - especially how to position the rotated element on my page. It seems that the X and Y parameters work in a different way that I would expect it.

Here is some example code I wrote:

func main() {
	pdf := fpdf.New("P", "mm", "A4", "")
	pdf.AddUTF8Font("opensans", "", "OpenSans-Regular.ttf")
	pdf.AddUTF8Font("opensans", "B", "OpenSans-Bold.ttf")
	pdf.AddUTF8Font("opensans", "I", "OpenSans-Italic.ttf")
	pdf.AddUTF8Font("opensans", "BI", "OpenSans-BoldItalic.ttf")
	pdf.AddPage()
	pdf.SetFont("opensans", "", 10)

	for i := 0.0; i <= 90; i = i + 10 {
		pdf.AddLayer(fmt.Sprintf("%f", i), true)
		pdf.SetXY(210.0/2, 297.0/2)
		pdf.TransformBegin()
		pdf.TransformRotate(i, 0, 0)
		pdf.CellFormat(0, 5, fmt.Sprintf("Angel: %f", i), "", 0, "", false, 0, "")
		pdf.TransformEnd()
	}
	if err := pdf.OutputFileAndClose("hello.pdf"); err != nil {
		fmt.Printf("error generating PDF: %s\n", err)
		os.Exit(1)
	}
}

I would expect that I have a piece of text that is starting centered on the page and is rotated from there in 10° increments. But in reallity it seem that the text is skewed in some weird way, even though the X and Y parameters are always 0. The result looks like this:

image

Does anybody has some advice or pointer to what I am doing wrong? As final goal I'd like to position vertical text boxes and a QR code in the upper left corner of the document, but given that I am basically blindly guessing right now where the rotated element would end up, I am not getting reliable re-producable results.

Any assistance is highly appreciated.

Panic on Split text with Unicode

The source document (novel manuscript) I use has Unicode characters like:

  • Object Replacement Character
  • Guillemets/Chevrons «»
  • M Dash —

I am using the standard fonts, in particular ARIAL at the moment panic occurs. And during formatting I try to indent a block of text. For that I call:

pdf.SplitText(textBlock, workingWidth)

If the text is plain ASCII nothing bad happens. If the text has Unicode characters FPDF craps out at SplitText.go line #31 with the following PANIC:

panic: runtime error: index out of range [8212] with length 256.

8212 is the decimal value of the Unicode M-dash character (\u2014). This issue was originally happening when it encountered the **Object Replacement Character **(\ufffc) but I handled that gracefully by doing the necessary object substitutions.

However, in creative writing there are those other Unicodes I mentioned above that are crucial for proper manuscript formatting. Unfortunately the pdf.SplitText() method of the library is unable to process them.

For what I could see Arial & Times do have that Unicode character. And for what I see in Split text it gets that character width from the current font but it only has 256 items which is not realistic for Unicode.

Latin é output as é

Hi, when I write text to a pdf page with accents like "é" the writer outputs as "é"

I searched why this was happening, and I found that was a encoding problem.
https://www.i18nqa.com/debug/utf8-debug.html

I treid changin the font to "times" "courier" "helvetica" and the problem was persistent.

Can you help me with this problem please.

An image and the test pdf
2022-06-20_13-18
hello.pdf

Generating PDF through an html template

I have a html template in which I will render data on the runtime and want to generate a pdf out of it. Is there any way I can do that using go fpdf.

this is my code

func usingGoFPDF() {
	now := time.Now()

	tmpl, err := template.ParseFiles(templateFileName)
	if err != nil {
		log.Fatalf("could not parse template: %v", err)
	}

	fmt.Println("template parsed", time.Since(now))

	var result bytes.Buffer

	data := AadharDetails{
		PhotoSrc:      "photo.jpg",
		FormId:        "1234567890",
		AadhaarNumber: "1234 5678 9012",
		FirstName:     "John",
		FatherName:    "Doe",
		DOB:           "01-01-2000",
		ContactPerson: "John Doe",
		Gender:        "Male",
		MobileNumber:  "1234567890",
		EmailId:       "[email protected]",
		Address:       "123, XYZ Street, ABC City, DEF State, 123456",
		HouseNo:       "123",
		Landmark:      "Near ABC",
		City:          "ABC",
		Street:        "XYZ",
		PostOffice:    "DEF",
		District:      "GHI",
		SubDistrict:   "JKL",
		State:         "MNO",
		Pincode:       "123456",
		Country:       "India",
	}

	fmt.Println("data set", time.Since(now))

	err = tmpl.Execute(&result, data)
	if err != nil {
		log.Fatalf("could not execute template: %v", err)
	}

	fmt.Println("template executed", time.Since(now))

	htmlData := result.String()

	// Create a PDF document
	pdf := fpdf.New("P", "mm", "A4", "")

	// Add a new page
	pdf.AddPage()

	fmt.Println(htmlData)
	pdf.Write(1.2, htmlData)

	err = pdf.OutputFileAndClose("output.pdf")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Time taken:", time.Since(now))
	fmt.Println("PDF generated successfully:", "output.pdf")

}

It's breaking with the error - panic: runtime error: index out of range [60] with length 0

List item prefixed with an icon

I am trying to create bulletted, numbered lists and the like. However, I would also like to render an item (a string) which is preceded (prefixed) with an icon:

[indentation][small icon][item text]

How can I do that? Some of the documentation is kind of cryptic. For example the Image options has x & y parameters but no mentioning of how they are used. Is the X an offset from the current position? An offset from the (left) margin? Offset from edge of page?

Makefont fails!

  • I downloaded the Amaranth TrueType fonts from Google Fonts
  • I compiled the makefont.go source and also downloaded both the cp1252 & iso-8859-1 map files

However, when running it as indicated in the utility help instructions:

makefont --dst embed/fonts --embed --enc embed/fonts/cp1252.map ~/.fonts/Amaranth-Regular.ttf

And I get this error:

Unexpected EOF

The same error occurs when I omit the --embed option.

Implementing page x of y

I tried to implement page x of y on 7 page pdf.
Instead of getting 1/7 . I am getting 1/1 upto 7/7.Please suggest what to implement
pdf.CellFormat(0, 10, fmt.Sprintf("Page %d/%d", pdf.PageNo(), pdf.PageCount()), "", 0, "C", false, 0, "")

Text that goes over multiple lines in a cell, has an annoying line render under each line of the text.

I have a cell (MultiCell) , which contains alot of text and it goes over multiple lines. Under each of the line, there is very small line, that is only visible when the background fill is not white. In the example the fill colour is #ed9063 and the offending line is #fd8928. Does anyone know how to get rid of it? is a bug or have I got some setting wrong?

I have pdf.SetLineWidth(0),

Screenshot 2023-10-04 at 00 00 16

To duplicate, Just create a cell with a fill background to non-white and put text that wraps in it.

Unable to set header and footer with template

Using this code:

func main() {
	pdf := fpdf.New(fpdf.OrientationPortrait, fpdf.UnitMillimeter, fpdf.PageSizeA4, "")
	pdf.SetFont("Arial", "", 13)

	contentPageTemplate := pdf.CreateTemplate(func(tpl *fpdf.Tpl) {
		tpl.SetHeaderFuncMode(func() {
			tpl.SetY(5)
			tpl.SetFont("Arial", "B", 15)
			tpl.Cell(80, 0, "")
			tpl.CellFormat(30, 10, "Title", "1", 0, "C", false, 0, "")
			tpl.Ln(20)
			tpl.CellFormat(30, 10, "Class Report", "", 0, fpdf.AlignCenter, false, 0, "")
		}, true)
		tpl.SetFooterFunc(func() {
			tpl.SetY(-15)
			tpl.SetFont("Arial", "I", 13)
			tpl.CellFormat(0, 10, fmt.Sprintf("Page %d/{nb}", tpl.PageNo()),
				"", 0, "C", false, 0, "")
		})
	})

	pdf.AliasNbPages("")
	pdf.AddPage()
	pdf.CellFormat(0, 10, "This is the front cover", "", 0, fpdf.AlignCenter, false, 0, "")
	pdf.AddPage()
	pdf.UseTemplate(contentPageTemplate)
	pdf.CellFormat(0, 10, "This is the a content page with header and footer", "", 0, fpdf.AlignCenter, false, 0, "")

	log.Println(pdf.PageCount())

	pdf.OutputFileAndClose("test.pdf")
}

I am not able to add a header and footer on the second page. Is this the wrong way to do it?

Also, I am not sure if the authors of fpdf are open to using the Discussions page for this repo. I was looking for it to ask the question but it seems it is only possible for me to do so via opening an issue.

Thanks!

Concurrent PDF creation with AddUTF8FontFromBytes has a data race

The following code demonstrates the problem:

func TestConcurrentAddUTF8FontFromBytes(t *testing.T) {
	fontBytes, _ := os.ReadFile(example.FontFile("DejaVuSansCondensed.ttf"))

	wg := new(sync.WaitGroup)
	createPDF := func() {
		pdf := fpdf.New(fpdf.OrientationPortrait, "mm", "A4", "")
		pdf.AddPage()
		pdf.AddUTF8FontFromBytes("dejavu", "", fontBytes)
		pdf.SetFont("dejavu", "", 16)
		pdf.Cell(40, 10, "Hello World!")
		err := pdf.Output(io.Discard)
		if err != nil {
			t.Error(err)
		}
		wg.Done()
	}

	for i := 0; i < 10; i++ {
		wg.Add(1)
		go createPDF()
	}
	wg.Wait()
}

Result:

WARNING: DATA RACE
Write at 0x00c00020beff by goroutine 15:
  github.com/go-pdf/fpdf.(*utf8FontFile).generateChecksum()
      /src/github.com/vdobler/fpdf/utf8fontfile.go:170 +0x2b8
  github.com/go-pdf/fpdf.(*utf8FontFile).assembleTables()
      /src/github.com/vdobler/fpdf/utf8fontfile.go:1006 +0x5e8
  github.com/go-pdf/fpdf.(*utf8FontFile).GenerateCutFont()
      /src/github.com/vdobler/fpdf/utf8fontfile.go:786 +0x37fc
  github.com/go-pdf/fpdf.(*Fpdf).putfonts()
      /src/github.com/vdobler/fpdf/fpdf.go:4354 +0xbf0
  github.com/go-pdf/fpdf.(*Fpdf).putresources()
      /src/github.com/vdobler/fpdf/fpdf.go:4834 +0x64
  github.com/go-pdf/fpdf.(*Fpdf).enddoc()
      /src/github.com/vdobler/fpdf/fpdf.go:5038 +0x370
  github.com/go-pdf/fpdf.(*Fpdf).Close()
      /src/github.com/vdobler/fpdf/fpdf.go:700 +0x2dc
  github.com/go-pdf/fpdf.(*Fpdf).Output()
      /src/github.com/vdo  github.com/go-pdf/fpdf_test.TestConcurrentAddUTF8FontFromBytes.func1()
      /src/github.com/vdobler/fpdf/fpdf_example_test.go:2638 +0x1a4

Previous read at 0x00c00020beff by goroutine 14:
  github.com/go-pdf/fpdf.(*utf8FontFile).generateChecksum()
      /src/github.com/vdobler/fpdf/utf8fontfile.go:176 +0x98
  github.com/go-pdf/fpdf.(*utf8FontFile).assembleTables()
      /src/github.com/vdobler/fpdf/utf8fontfile.go:1006 +0x5e8
  github.com/go-pdf/fpdf.(*utf8FontFile).GenerateCutFont()
      /src/github.com/vdobler/fpdf/utf8fontfile.go:786 +0x37fc
  github.com/go-pdf/fpdf.(*Fpdf).putfonts()
      /src/github.com/vdobler/fpdf/fpdf.go:4354 +0xbf0
  github.com/go-pdf/fpdf.(*Fpdf).putresources()
      /src/github.com/vdobler/fpdf/fpdf.go:4834 +0x64
  github.com/go-pdf/fpdf.(*Fpdf).enddoc()
      /src/github.com/vdobler/fpdf/fpdf.go:5038 +0x370
  github.com/go-pdf/fpdf.(*Fpdf).Close()
      /src  github.com/go-pdf/fpdf.(*Fpdf).Output()
      /src/github.com/vdobler/fpdf/fpdf.go:3717 +0x64
  github.com/go-pdf/fpdf_test.TestConcurrentAddUTF8FontFromBytes.func1()
      /src/github.com/vdobler/fpdf/fpdf_example_test.go:2638 +0x1a4

Background: We create PDF based on HTTP requests and concurrent request lead to concurrent PDF creation. The UTF-8 fonts are go:embed'ed into our executables and we'd like to reuse these bytes without having to make a copy for each and every request.

Creating Lists in PDF with go-pdf Library

Hi,

I'm using the go-pdf library to make PDF files, and I want to know if it can make lists like bullet points or numbered lists in a simple way. Currently, I'm using this code:

package main

import (
    "github.com/go-pdf/fpdf"
    "log"
)

func main() {
    pdf := fpdf.New("P", "mm", "A4", "")
    pdf.AddPage()
    pdf.SetFont("Arial", "B", 12)

    for _, i := range []string{"1","2","3"} {
        pdf.MultiCell(0, 10, "- "+i, "", "L", false)
    }

    err := pdf.OutputFileAndClose("list.pdf")
    if err != nil {
        log.Fatal(err)
    }
}

It generates a PDF that looks like this:

- 1
- 2
- 3

Is there an easier way to create lists in go-pdf? Since it's inspired by PHP fpdf, I referred to the official PHP example at http://www.fpdf.org/en/script/script56.php for list formatting. I aim to achieve a similar result where lists look standard, with proper spacing between items and aligned lines when they break.

Am I missing any information in go-pdf's documentation regarding list creation? Is there a specific function for this purpose?

Thanks.

Adding a `warnings` member to the `Fpdf` struct

Hi all,

First of all, excellent project.

The reason for raising this is that some issues encountered during processing are not fatal and generating the doc in spite of them may be worthwhile. For example, consider https://github.com/go-pdf/fpdf/blob/main/png.go#L57 (I bring it as an example because I've actually encountered it):

	if bpc > 8 {
		f.err = fmt.Errorf("16-bit depth not supported in PNG file")
	}

With my input, if I simply change the code to print the error rather than assign it to f.err, I get the image in the generated PDF doc. You can easily reproduce this with the below command but I'm also attaching the resulting PDF to this issue:

go install github.com/mandolyte/mdtopdf/cmd/md2pdf@latest
md2pdf -i https://github.com/fogleman/gg/raw/master/README.md -o gg.pdf --page-size A3

gg.pdf

But, because in mdtopdf we call OutputFileAndClose(), which returns immediately if if f.err != nil, no doc is generated.

My suggestion is to add a warnings string array to the Fpdf struct, populate it when encountering non-fatal errors (instead of assigning them to the err member) and print these in OutputFileAndClose(), rather than give up and return without generating the file.

If you find this acceptable, I'm happy to submit a pull request.

Cheers,

How to add a page count at the bottom of Page

Hi, I was trying to add a page count at the bottom of the page, as the other implementation of fpdf works, by using pdf.SetY(-15) and therefore adding a cell.

But a new page is added and the {nb} is not interpolated.

package main

import (
	"fmt"

	"github.com/go-pdf/fpdf"
)

func main() {
	pdf := fpdf.New("P", "mm", "A4", "")
	tr := pdf.UnicodeTranslatorFromDescriptor("")
	pdf.AddPage()
	pdf.SetFont("Arial", "B", 16)
	pdf.Cell(40, 10, tr("Olá, mundo"))
	pdf.SetY(-15)
	pdf.SetFont("Arial", "I", 8)
	pageNum := fmt.Sprintf("%d/{nb}", pdf.PageNo())
	pdf.CellFormat(0, 10, pageNum, "", 0, "C", false, 0, "")
	err := pdf.OutputFileAndClose("hello.pdf")
	if err != nil {
		panic(err.Error())
	}
}

To interpolate {nb} had to force by using pdf.AliasNbPages("{nb}"), but even though another page was added.

image

New help on automatic page break

From the README, it seems automatic page break is supported. In my local testing, when I keep writing texts, there's no new page generated and the additional text which cannot fit in a single page just disappears. Could you help me understand how auto page break can be enabled? Thanks!

Support for font kerning

Repost for sync.

jung-kurt/gofpdf#297

It seems gofpdf does not support font kerning at the moment. For example, when outputting "Tourist" with Arial font:

Result of gofpdf:
image

Expected:
image

Note the difference of the spacing between "T" and "o". Is there any way to apply font kerning?

emojis causing panic error

When I try to draw emojis in the PDF, it causes the library to panic with the error below:
panic: runtime error: index out of range with length 65536

Others are running into the same issue:
jung-kurt/gofpdf#255
jung-kurt/gofpdf#330

Is it possible to have the library support drawing of emojis in the PDF? Thanks!

How to Draw on Existing PDF

The examples in documentation shows adding new pdfs only. I would like to add lines and curves to existing pdf file. Could you please provide minimal working example of doing the same

How to generate tables?

Tables are a very common thing in pdf. Would to be great to have a higher level abstraction for creating the same

jung-kurt/gofpdf#129

I went through the above old issue on the parent repository which talks about different approaches. I feel a higher level abstraction for generating them would be much useful

SetKeyword() produces garbled property when document is encrypted

The following code:

pdf.SetKeywords("one two three", true)

Does not produce any error. However, when viewing the document and opening its properties, it shows a garbled string regardless of whether the last argument is true or false. In GO all strings are UTF8.

The same occurs with pdf.SetSubject() and pdf.SetTitle().

However, that only happens when pdf.SetProtection(fpdf.CnProtectPrint) is used. In that case even after the reader has entered the correct password, only the document content is decrypted but the document properties remain encrypted.

If on the other hand no protection is used during generation, the document properties are plain text and readable.

Fix:

  • After the correct password is entered, decrypt both content & properties.
  • Alternatively, don't encrypt document properties.

Euro Icon for CellFormat

Hello! I am trying to use the euro icon or \u20ac in CellFormat, however, I am not getting any success.

After passing pdf.CellFormat(w[4], 8, "€[1500,00]", "", 0, "R", false, 0, "") I am getting:
image

Same happens if I put instead of the , \u20ac. Can I get some guidance on this please?

Footnotes

It is clear how to create a footnote and how to write a clickable reference but there is no example of using footnotes. I am using FPDF with Auto Page to generate a document.

  • How many footnotes can you render at the bottom of the page, how? Is it in the footer area or just above?
  • Does WriteLinkID() need the page number to already be known, or is that resolved at the end on OutputAndClose()?

I would prefer to render the footnote on the same auto-page, but I couldn't find any example.

Alternatively, I don't know it it would work to first do AddLink() & WriteLinkID() on the current (auto) page, and then at the end of the document (last page), render all of them (any special format?).

Add newline support to CellFormat

When I add a \n in CellFormat text parameter it takes it away and does nothing with it. It would be cool to have newline support in fpdf for the CellFormat function

perf: improve perfs for pdfdeck

$ go get github.com/go-pdf/fpdf
go get: github.com/go-pdf/fpdf@none updating to
	github.com/go-pdf/[email protected]: parsing go.mod:
	module declares its path as: github.com/phpdave11/gofpdf
	        but was required as: github.com/go-pdf/fpdf

fpdf: dubious pdfVersion handling

in fpdf we can see multiple occurrences of:

if f.pdfVersion < "1.4" { ... }

it kind of works (as there are no "1.10" PDF version), but is brittle ("1.3" < "1.10" == false)

HIndi Rendering Problem

Incorrent rendering Hindi fonts https://hindi-fonts.com/fonts/mangal-regular

pdf := fpdf.New("P", "mm", "A4", "")
pdf.AddUTF8Font("mangal", "", "mangal.ttf")

pdf.AddPage()
pdf.SetFont("mangal", "", 16)
pdf.Cell(40, 10, "नमस्ते")

err := pdf.OutputFileAndClose("gopdf/hello_" + suffix + ".pdf")

if err != nil {
	panic(err)
}

Output

image

Expected

image

Load image from byte slice into PDF

My document source is a JSON file and, among other things, I extract images that are Base64 encoded.

However, I am trying to get that extracted image into PDF but there is no ImageOptions that takes a []byte instead of a filename.

makefont function that return bytes instead of writing to files.

Currently if you design your program in such a way that you allow the user to specify a font, then you have to use the makefont function to convert fonts first and this writes to the disk and this could cause problems. It would be cool if there was a variant of the makefont function that return the bytes it would write to the file, especially considering that there is a AddUft8bytes function.

Optimizing parsepngstream

Based on profiling my application, image processing is the most CPU-intensive, with parsepngstream using a good bit of the time. Is there an opportunity to optimize this function? Perhaps using image/png from the standard library

Here is my profile:

File: ppdfdeck
Type: cpu
Time: May 23, 2024 at 3:11pm (EDT)
Duration: 4.11s, Total samples = 3.91s (95.24%)
Showing nodes accounting for 3.83s, 97.95% of 3.91s total
Dropped 36 nodes (cum <= 0.02s)
      flat  flat%   sum%        cum   cum%
     0.64s 16.37% 16.37%      0.64s 16.37%  github.com/go-pdf/fpdf.(*wbuffer).u8 (inline)
     0.36s  9.21% 25.58%      0.36s  9.21%  compress/flate.(*deflateFast).matchLen
     0.36s  9.21% 34.78%      0.36s  9.21%  hash/adler32.update
     0.27s  6.91% 41.69%      0.27s  6.91%  runtime.memmove
     0.26s  6.65% 48.34%      0.77s 19.69%  compress/flate.(*deflateFast).encode
     0.24s  6.14% 54.48%      0.29s  7.42%  compress/flate.(*decompressor).huffSym
     0.23s  5.88% 60.36%      0.76s 19.44%  compress/flate.(*decompressor).huffmanBlock
     0.21s  5.37% 65.73%      0.21s  5.37%  runtime.memclrNoHeapPointers
     0.19s  4.86% 70.59%      0.37s  9.46%  compress/flate.(*huffmanBitWriter).writeTokens
     0.18s  4.60% 75.19%      3.67s 93.86%  github.com/go-pdf/fpdf.(*Fpdf).parsepngstream
     0.10s  2.56% 77.75%      0.11s  2.81%  compress/flate.(*huffmanBitWriter).writeCode
     0.08s  2.05% 79.80%      0.33s  8.44%  compress/flate.(*huffmanBitWriter).indexTokens
     0.07s  1.79% 81.59%      0.09s  2.30%  compress/flate.(*huffmanEncoder).bitCounts
     0.06s  1.53% 83.12%      0.14s  3.58%  compress/flate.(*dictDecoder).tryWriteCopy (inline)
     0.06s  1.53% 84.65%      0.06s  1.53%  compress/flate.load32 (inline)
     0.05s  1.28% 85.93%      0.05s  1.28%  bytes.(*Reader).ReadByte
     0.04s  1.02% 86.96%      0.04s  1.02%  compress/flate.(*decompressor).moreBits
     0.04s  1.02% 87.98%      0.04s  1.02%  compress/flate.(*dictDecoder).writeByte (inline)
     0.04s  1.02% 89.00%      0.04s  1.02%  compress/flate.(*huffmanBitWriter).writeBits
     0.04s  1.02% 90.03%      0.04s  1.02%  compress/flate.load64 (inline)
     0.04s  1.02% 91.05%      0.04s  1.02%  compress/flate.token.length (inline)
     0.04s  1.02% 92.07%      0.04s  1.02%  runtime/internal/syscall.Syscall6
     0.04s  1.02% 93.09%      0.05s  1.28%  sort.insertionSort
     0.03s  0.77% 93.86%      0.03s  0.77%  crypto/sha1.blockAVX2
     0.03s  0.77% 94.63%      0.04s  1.02%  sort.partition
     0.02s  0.51% 95.14%      0.02s  0.51%  compress/flate.(*dictDecoder).histSize (inline)
     0.02s  0.51% 95.65%      0.02s  0.51%  compress/flate.(*huffmanBitWriter).writeDynamicHeader
     0.02s  0.51% 96.16%      0.02s  0.51%  compress/flate.byLiteral.Less
     0.02s  0.51% 96.68%      0.02s  0.51%  compress/flate.lengthCode (inline)
     0.02s  0.51% 97.19%      0.02s  0.51%  compress/flate.token.offset (inline)
     0.02s  0.51% 97.70%      0.02s  0.51%  runtime.procyield
     0.01s  0.26% 97.95%      0.20s  5.12%  compress/flate.(*huffmanEncoder).generate
         0     0% 97.95%      1.10s 28.13%  bytes.(*Buffer).ReadFrom
         0     0% 97.95%      0.06s  1.53%  bytes.(*Buffer).WriteString
         0     0% 97.95%      0.16s  4.09%  bytes.(*Buffer).grow
         0     0% 97.95%      0.16s  4.09%  bytes.growSlice
         0     0% 97.95%      1.53s 39.13%  compress/flate.(*Writer).Write (inline)
         0     0% 97.95%      0.07s  1.79%  compress/flate.(*byFreq).sort (inline)
         0     0% 97.95%      0.03s  0.77%  compress/flate.(*byLiteral).sort (inline)
         0     0% 97.95%      1.51s 38.62%  compress/flate.(*compressor).encSpeed
         0     0% 97.95%      0.02s  0.51%  compress/flate.(*compressor).fillStore
         0     0% 97.95%      0.02s  0.51%  compress/flate.(*compressor).init
         0     0% 97.95%      1.53s 39.13%  compress/flate.(*compressor).write
         0     0% 97.95%      0.83s 21.23%  compress/flate.(*decompressor).Read
         0     0% 97.95%      0.14s  3.58%  compress/flate.(*decompressor).nextBlock
         0     0% 97.95%      0.74s 18.93%  compress/flate.(*huffmanBitWriter).writeBlockDynamic
         0     0% 97.95%      0.03s  0.77%  compress/flate.(*huffmanEncoder).assignEncodingAndSize
         0     0% 97.95%      0.04s  1.02%  compress/flate.NewWriter (inline)
         0     0% 97.95%      0.04s  1.02%  compress/flate.NewWriterDict
         0     0% 97.95%      1.78s 45.52%  compress/zlib.(*Writer).Write
         0     0% 97.95%      0.04s  1.02%  compress/zlib.(*Writer).writeHeader
         0     0% 97.95%      0.98s 25.06%  compress/zlib.(*reader).Read
         0     0% 97.95%      0.03s  0.77%  crypto/sha1.(*digest).Write
         0     0% 97.95%      0.03s  0.77%  crypto/sha1.block
         0     0% 97.95%      0.09s  2.30%  github.com/go-pdf/fpdf.(*Fpdf).Close
         0     0% 97.95%      3.77s 96.42%  github.com/go-pdf/fpdf.(*Fpdf).ImageOptions
         0     0% 97.95%      0.10s  2.56%  github.com/go-pdf/fpdf.(*Fpdf).Output
         0     0% 97.95%      3.77s 96.42%  github.com/go-pdf/fpdf.(*Fpdf).RegisterImageOptions
         0     0% 97.95%      3.77s 96.42%  github.com/go-pdf/fpdf.(*Fpdf).RegisterImageOptionsReader
         0     0% 97.95%      0.09s  2.30%  github.com/go-pdf/fpdf.(*Fpdf).enddoc
         0     0% 97.95%      0.06s  1.53%  github.com/go-pdf/fpdf.(*Fpdf).out
         0     0% 97.95%      3.73s 95.40%  github.com/go-pdf/fpdf.(*Fpdf).parsepng
         0     0% 97.95%      0.08s  2.05%  github.com/go-pdf/fpdf.(*Fpdf).putimage
         0     0% 97.95%      0.08s  2.05%  github.com/go-pdf/fpdf.(*Fpdf).putimages
         0     0% 97.95%      0.08s  2.05%  github.com/go-pdf/fpdf.(*Fpdf).putresources
         0     0% 97.95%      0.07s  1.79%  github.com/go-pdf/fpdf.(*Fpdf).putstream
         0     0% 97.95%      0.03s  0.77%  github.com/go-pdf/fpdf.(*idEncoder).bytes (inline)
         0     0% 97.95%      1.79s 45.78%  github.com/go-pdf/fpdf.(*xmempool).compress
         0     0% 97.95%      1.03s 26.34%  github.com/go-pdf/fpdf.(*xmempool).uncompress
         0     0% 97.95%      0.03s  0.77%  github.com/go-pdf/fpdf.generateImageID
         0     0% 97.95%      0.06s  1.53%  github.com/go-pdf/fpdf.newRBuffer
         0     0% 97.95%      0.36s  9.21%  hash/adler32.(*digest).Write
         0     0% 97.95%      0.03s  0.77%  internal/poll.(*FD).Read
         0     0% 97.95%      0.04s  1.02%  internal/poll.ignoringEINTRIO (inline)
         0     0% 97.95%      3.87s 98.98%  main.dodeck
         0     0% 97.95%      3.77s 96.42%  main.doslides
         0     0% 97.95%      3.87s 98.98%  main.main
         0     0% 97.95%      3.77s 96.42%  main.pdfslide
         0     0% 97.95%      0.03s  0.77%  os.(*File).Read
         0     0% 97.95%      0.03s  0.77%  os.(*File).read (inline)
         0     0% 97.95%      0.03s  0.77%  runtime.gcBgMarkWorker
         0     0% 97.95%      0.03s  0.77%  runtime.gcBgMarkWorker.func2
         0     0% 97.95%      0.03s  0.77%  runtime.gcDrain
         0     0% 97.95%      0.03s  0.77%  runtime.gcDrainMarkWorkerDedicated (inline)
         0     0% 97.95%      0.02s  0.51%  runtime.growslice
         0     0% 97.95%      3.87s 98.98%  runtime.main
         0     0% 97.95%      0.04s  1.02%  runtime.makeslice
         0     0% 97.95%      0.06s  1.53%  runtime.mallocgc
         0     0% 97.95%      0.03s  0.77%  runtime.markroot
         0     0% 97.95%      0.03s  0.77%  runtime.markroot.func1
         0     0% 97.95%      0.03s  0.77%  runtime.memclrNoHeapPointersChunked
         0     0% 97.95%      0.02s  0.51%  runtime.newobject
         0     0% 97.95%      0.03s  0.77%  runtime.suspendG
         0     0% 97.95%      0.04s  1.02%  runtime.systemstack
         0     0% 97.95%      0.10s  2.56%  sort.Sort
         0     0% 97.95%      0.10s  2.56%  sort.pdqsort
         0     0% 97.95%      0.04s  1.02%  syscall.RawSyscall6
         0     0% 97.95%      0.03s  0.77%  syscall.Read (inline)
         0     0% 97.95%      0.04s  1.02%  syscall.Syscall
         0     0% 97.95%      0.03s  0.77%  syscall.read

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.