A simple library for generating PDF written in Go lang

gopdf

gopdf is a simple library for generating PDF document written in Go lang.

Features

  • Unicode subfont embedding. (Chinese, Japanese, Korean, etc.)
  • Draw line, oval, rect, curve
  • Draw image ( jpg, png )
  • Password protection
  • Font kerning

Installation

go get -u github.com/signintech/gopdf

Print text

  
package main
import (
	"log"
	"github.com/signintech/gopdf"
)

func main() {

	pdf := gopdf.GoPdf{}
	pdf.Start(gopdf.Config{ PageSize: *gopdf.PageSizeA4 })  
	pdf.AddPage()
	err := pdf.AddTTFFont("wts11", "../ttf/wts11.ttf")
	if err != nil {
		log.Print(err.Error())
		return
	}

	err = pdf.SetFont("wts11", "", 14)
	if err != nil {
		log.Print(err.Error())
		return
	}
	pdf.Cell(nil, "您ε₯½")
	pdf.WritePdf("hello.pdf")

}

Image

package main
import (
	"log"
	"github.com/signintech/gopdf"
)

func main() {
	pdf := gopdf.GoPdf{}
	pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4 })  
	pdf.AddPage()
	var err error
	err = pdf.AddTTFFont("loma", "../ttf/Loma.ttf")
	if err != nil {
		log.Print(err.Error())
		return
	}
	
	pdf.Image("../imgs/gopher.jpg", 200, 50, nil) //print image
	err = pdf.SetFont("loma", "", 14)
	if err != nil {
		log.Print(err.Error())
		return
	}
	pdf.SetX(250) //move current location
	pdf.SetY(200)
	pdf.Cell(nil, "gopher and gopher") //print text

	pdf.WritePdf("image.pdf")
}
  

Links

package main

import (
	"log"
	"github.com/signintech/gopdf"
)

func main()  {
	pdf := gopdf.GoPdf{}
	pdf.Start(gopdf.Config{ PageSize: *gopdf.PageSizeA4 }) //595.28, 841.89 = A4
	pdf.AddPage()
	err := pdf.AddTTFFont("times", "./test/res/times.ttf")
	if err != nil {
		log.Print(err.Error())
		return
	}

	err = pdf.SetFont("times", "", 14)
	if err != nil {
		log.Print(err.Error())
		return
	}

	pdf.SetX(30)
	pdf.SetY(40)
	pdf.Text("Link to example.com")
	pdf.AddExternalLink("http://example.com/", 27.5, 28, 125, 15)

	pdf.SetX(30)
	pdf.SetY(70)
	pdf.Text("Link to second page")
	pdf.AddInternalLink("anchor", 27.5, 58, 120, 15)

	pdf.AddPage()
	pdf.SetX(30)
	pdf.SetY(100)
	pdf.SetAnchor("anchor")
	pdf.Text("Anchor position")

	pdf.WritePdf("hello.tmp.pdf")

}

Draw line

pdf.SetLineWidth(2)
pdf.SetLineType("dashed")
pdf.Line(10, 30, 585, 30)

Draw oval

pdf.SetLineWidth(1)
pdf.Oval(100, 200, 500, 500)

Draw polygon

pdf.SetStrokeColor(255, 0, 0)
pdf.SetLineWidth(2)
pdf.SetFillColor(0, 255, 0)
pdf.Polygon([]gopdf.Point{{X: 10, Y: 30}, {X: 585, Y: 200}, {X: 585, Y: 250}}, "DF")

Rotation text or image

pdf.SetX(100)
pdf.SetY(100)
pdf.Rotate(270.0, 100.0, 100.0)
pdf.Text("Hello...")
pdf.RotateReset() //reset

Set transparency

Read about transparency in pdf (page 320, section 11)

// alpha - value of transparency, can be between `0` and `1`
// blendMode - default value is `/Normal` - read about [blendMode and kinds of its](https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf) `(page 325, section 11.3.5)`

transparency := Transparency{
	Alpha: 0.5,
	BlendModeType: "",
}
pdf.SetTransparency(transparency Transparency)

Password protection

package main

import (
	"log"

	"github.com/signintech/gopdf"
)


func main() {

	pdf := gopdf.GoPdf{}
	pdf.Start(gopdf.Config{
		PageSize: *gopdf.PageSizeA4, //595.28, 841.89 = A4
		Protection: gopdf.PDFProtectionConfig{
			UseProtection: true,
			Permissions: gopdf.PermissionsPrint | gopdf.PermissionsCopy | gopdf.PermissionsModify,
			OwnerPass:   []byte("123456"),
			UserPass:    []byte("123456789")},
	})

	pdf.AddPage()
	pdf.AddTTFFont("loma", "../ttf/loma.ttf")
	pdf.Cell(nil,"Hi")
	pdf.WritePdf("protect.pdf")
}

Import existing PDF

Import existing PDF power by package gofpdi created by @phpdave11 (thank you πŸ˜„ )

package main

import (
        "github.com/signintech/gopdf"
        "io"
        "net/http"
        "os"
)

func main() {
        var err error

        // Download a Font
        fontUrl := "https://github.com/google/fonts/raw/master/ofl/daysone/DaysOne-Regular.ttf"
        if err = DownloadFile("example-font.ttf", fontUrl); err != nil {
            panic(err)
        }

        // Download a PDF
        fileUrl := "https://tcpdf.org/files/examples/example_012.pdf"
        if err = DownloadFile("example-pdf.pdf", fileUrl); err != nil {
            panic(err)
        }

        pdf := gopdf.GoPdf{}
        pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4

        pdf.AddPage()

        err = pdf.AddTTFFont("daysone", "example-font.ttf")
        if err != nil {
            panic(err)
        }

        err = pdf.SetFont("daysone", "", 20)
        if err != nil {
            panic(err)
        }

        // Color the page
        pdf.SetLineWidth(0.1)
        pdf.SetFillColor(124, 252, 0) //setup fill color
        pdf.RectFromUpperLeftWithStyle(50, 100, 400, 600, "FD")
        pdf.SetFillColor(0, 0, 0)

        pdf.SetX(50)
        pdf.SetY(50)
        pdf.Cell(nil, "Import existing PDF into GoPDF Document")

        // Import page 1
        tpl1 := pdf.ImportPage("example-pdf.pdf", 1, "/MediaBox")

        // Draw pdf onto page
        pdf.UseImportedTemplate(tpl1, 50, 100, 400, 0)

        pdf.WritePdf("example.pdf")

}

// DownloadFile will download a url to a local file. It's efficient because it will
// write as it downloads and not load the whole file into memory.
func DownloadFile(filepath string, url string) error {
        // Get the data
        resp, err := http.Get(url)
        if err != nil {
            return err
        }
        defer resp.Body.Close()

        // Create the file
        out, err := os.Create(filepath)
        if err != nil {
            return err
        }
        defer out.Close()

        // Write the body to file
        _, err = io.Copy(out, resp.Body)
        return err
}

Possible to set Trim-box

package main

import (
	"log"

	"github.com/signintech/gopdf"
)

func main() {
	
    pdf := gopdf.GoPdf{}
    mm6ToPx := 22.68
    
    // Base trim-box
    pdf.Start(gopdf.Config{
        PageSize: *gopdf.PageSizeA4, //595.28, 841.89 = A4
        TrimBox: gopdf.Box{Left: mm6ToPx, Top: mm6ToPx, Right: 595 - mm6ToPx, Bottom: 842 - mm6ToPx},
    })

    // Page trim-box
    opt := gopdf.PageOption{
        PageSize: gopdf.PageSizeA4, //595.28, 841.89 = A4
        TrimBox: &gopdf.Box{Left: mm6ToPx, Top: mm6ToPx, Right: 595 - mm6ToPx, Bottom: 842 - mm6ToPx},
    }
    pdf.AddPageWithOption(opt)

    if err := pdf.AddTTFFont("wts11", "../ttf/wts11.ttf"); err != nil {
        log.Print(err.Error())
        return
    }
    
    if err := pdf.SetFont("wts11", "", 14); err != nil {
        log.Print(err.Error())
        return
    }

    pdf.Cell(nil,"Hi")
    pdf.WritePdf("hello.pdf")
}

visit https://github.com/oneplus1000/gopdfsample for more samples.

Owner
Comments
  • White/Transparent text error in output PDF

    White/Transparent text error in output PDF

    Currently I am generating reports in a table format. It has been working fine for months, but suddenly I have a report for June where all the text is invisible. The text is all there, I can extract it using a tool such as pdftotext, but it is invisble when I open the PDF with any pdf viewer or pdf tool such as Scribus. For instance, the report of May generates a 16 pages PDF with no problems. Same code, for the June report, generates a 11 pages PDF with invisible text.

    I cannot share the PDF as it contains sensible information, but here is an screenshot: image

    Any idea how to solve this? Thank you

  • Kerning support feature request

    Kerning support feature request

    Hi, gopdf developers, thanks for a nice native package. The only feature i miss is kerning support. Without kerning, generated pdf documents look non-professional. It's a weak point of almost all open source pdf libraries. Do you have plans to implement this at some point? Especially it would be great if one could add/override internal font kerning values for arbitrary character pairs because many fonts lack thorough kerning spacings.

  • An issue with precisely aligning characters over a baseline

    An issue with precisely aligning characters over a baseline

    Hi, oneplus1000, I've encountered a problem when aligning characters of different sizes/typefaces over a same baseline. Characters do not position accurately. Is there a way to precisely put arbitrary characters(of arbitrary sizes/typefaces) over a same baseline? Maybe I'm doing something wrong? Is TypoAscender() the right metric in this case?

    import (
        "github.com/signintech/gopdf"
        "github.com/signintech/gopdf/fontmaker/core"
    )
    
    func getSpecTypoAsc(fontPath string, fontSize float64) float64 {
        var parser core.TTFParser
        parser.Parse(fontPath)
        typoAsc := float64(parser.TypoAscender()) * 1000.00 / float64(parser.UnitsPerEm())
        return typoAsc * fontSize / 1000.0
    }
    
    func main() {
        arialPath := "./ttf/arial.ttf"
        dejavuPath := "./ttf/DejaVuSerif.ttf"
        pdf := gopdf.GoPdf{}
        pdf.Start(gopdf.Config{Unit: "pt", PageSize: gopdf.Rect{W: 595.28, H: 841.89}})
        pdf.AddPage()
        pdf.AddTTFFont("arial", arialPath)
        pdf.AddTTFFont("deja", dejavuPath)
        pdf.SetX(0) 
        pdf.SetY(0)
        pdf.SetFont("arial", "", 60)
        pdf.Cell(nil, "h")
        pdf.SetFont("arial", "", 30)
        pdf.SetY(getSpecTypoAsc(arialPath, 60) - getSpecTypoAsc(arialPath, 30))
        pdf.Cell(nil, "h")
        pdf.SetFont("deja", "", 20)
        pdf.SetY(getSpecTypoAsc(arialPath, 60) - getSpecTypoAsc(dejavuPath, 20))
        pdf.Cell(nil, "h")      
        pdf.WritePdf("baseline.pdf")
    }
    

    baseline-dif

  • optimize:added functions to implement add new page automatically.

    optimize:added functions to implement add new page automatically.

    Abstract

    1. Added function SetNewY() to implement add new page automatically (such as text content). 2.Added function SetNewYIfNoOffset() to implement add new page automatically (such as image content).
    2. Test case files are in /test/pagination/.
    3. In addition, the code added this time will not affect the original function. It just provides an extra option.

    Description

    1. When using pdf.SetY(),there may be cases where the content truncated because of beyond the page. image

    2. When using SetNewY(), it will paginate automatically. image

    3. Unfortunately, this method is only suitable for scenarios where gp.curr.Y changes after adding content, such as pdf.Text(). When calling the scene where gp.curr.Y does not change, such as pdf.Image(), you need to use pdf.SetNewYIfNoOffset().

    4. When using pdf.SetNewYIfNoOffset(), it will paginate automatically. image

  • Draw image over rectangle

    Draw image over rectangle

    I am trying to insert an image on top of a rectangle without much success.

    pdf.SetFillColor(37, 45, 66)
    pdf.RectFromLowerLeftWithStyle(X, Y+H, W, H, "F")
    
    bytesOfImg := GetImageBytesFromOutThere()
    imgH, _ := gopdf.ImageHolderByBytes(bytesOfImg)
    imgRect := gopdf.Rect{
    	W: 200,
    	H: 300,
    }
    pdf.ImageByHolder(imgH, x, y, &imgRect)
    

    No matter what I try the picture is drawn under the rectangle.

    layer

  • Question: Cell fill color

    Question: Cell fill color

    I am trying to figure out a way to set the fill color of a cell, much like the way you would draw a filled rectangle.

    pdf.RectFromUpperLeftWithStyle(x, y, 200.28, 150.89, "FD")

    Thus far, I have not seen a way to do this. I want to build a PDF with tabular data, and need to be able to fill the cell background with a certain color. As far as I can tell, I'm stuck with a white background for cells.

  • Add CMYK color model support for text

    Add CMYK color model support for text

    1. Added support of CMYK color model for text. In the future it can be easily extended to support more color models.
    2. Adjusted naming to be more consistent
  • Introduce SplitTextWithWordWrap based on text spaces.

    Introduce SplitTextWithWordWrap based on text spaces.

    Since SplitText unfortunately also splits words in case the maximum line width is exceeded the SplitTextWithWordWrap function is meant to be 'word-sensitive'. Words do not get split anymore except there is no space rune available in the current line.

    Additionally introduced: setupDefaultA4PDF() for test support to get rid of some boilerplate code.

  • Letter J missing when writing text

    Letter J missing when writing text

    When using the font EB Garamond from google, the lowercase letter j does not render properly. Only the dot is printed. This is super strange. Not sure if I am doing something wrong, or if there is a special trick for some fonts. Just asking here first incase there are any obvious known issues I need to look out for before I waste a few hours trying to debug it πŸ˜€

    package main
    
    import (
    	"github.com/signintech/gopdf"
    	"log"
    )
    
    func main() {
    	pdf := gopdf.GoPdf{}
    	pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4})
    	pdf.AddPage()
    
            // Downloaded from https://fonts.google.com/specimen/EB+Garamond
    	err := pdf.AddTTFFont("EBGaramond", "EBGaramond-Regular.ttf")
    	if err != nil {
    		log.Print(err.Error())
    		return
    	}
    
    	err = pdf.SetFont("EBGaramond", "", 14)
    	if err != nil {
    		log.Print(err.Error())
    		return
    	}
    
    	pdf.SetX(30)
    	pdf.SetY(40)
    	pdf.Text("hijk")
    
    	pdf.WritePdf("test.pdf")
    }
    
  • How to draw a black filled triangle?

    How to draw a black filled triangle?

    I need to draw a triangle filled with black color. I can draw a triangle using 3 calls of Line method. But I cannot find a way to fill the triangle with black color. How can I do it?

  • Printing png files

    Printing png files

    Good day!

    Having problems printing out png images:

    pdf := gopdf.GoPdf{}
    pdf.Start(gopdf.Config{ PageSize: gopdf.Rect{W: 505, H: 840}})
    pdf.AddPage()
    pdf.Image("img/logo.png", 0, 0, &gopdf.Rect{W: 500, H: 500});
    

    – doesn't print anything.

    bytesOfImg, err := ioutil.ReadFile("img/logo.png")
    if err != nil {
        log.Print("Can't read file")
        log.Print(err)
        return
    }
    
    imgH, err := gopdf.ImageHolderByBytes(bytesOfImg)
    if err != nil {
        log.Print("Couldn't create holder")
        log.Print(err)
        return
    }
    
    err = pdf.ImageByHolder(imgH, 0, 0, nil)
    if err != nil {
        log.Print("Couldn't print out image")
        log.Print(err)
        return
    }
    

    – and this code prints "Couldn't print out image", "EOF"

    Thank you!

  • Named Layers in PDF

    Named Layers in PDF

    Is it possible to assign elements to specific layers with specific names? For example could add a layer, name it "images" and then add the images to that layer?

  • MultiCellWithOption vs CellWithOption behavior is different

    MultiCellWithOption vs CellWithOption behavior is different

    CellWithOption and MultiCellWithOption behavior is different, when you continuous use them. the function "CellWithOption" makes "AAAA",which is 1*n, but the function "MultiCellWithOption" makes "A\nA\nA\nA",which is n*1.

    In my opinion, the two function should be similar


    my code like this (reproduce the bug)

    opt := gopdf.CellOption{
    	Align:  gopdf.Center | gopdf.Middle,
    	Border: gopdf.AllBorders,
    	Float:  gopdf.Right,
    }
    rect := &gopdf.Rect{
    	W: fontSize * 3,
    	H: fontSize,
    }
    text:=abc
    x := pdf.GetX()
    y := pdf.GetY()
    for i := 0; i < 5; i++ {
    	err = pdf.CellWithOption(rect, text, opt)   // answer A
    	if err != nil {
    		log.Println(err)
    	}
    }
    pdf.SetXY(x, y+fontSize)
    
    text = "123"
    for i := 0; i < 5; i++ {
    	err = pdf.MultiCellWithOption(rect, text, opt)  // answer B
    	if err != nil {
    		log.Println(err)
    	}
    }
    

    for answer A, the output likes

    abcabcabcabcabc
    

    for answer B, the output likes

    123
    123
    123
    123
    123
    

    I think both answer A and answer B are same, I mean the answer A and answer B look like:

    abcabcabcabcabc
    123123123123123
    

    How to fix it? In the file ./gopdf.go, find function "MultiCellWithOption", at about line 1145, add the code

    gp.SetX(x + rectangle.W)
    gp.SetY(gp.GetY() - rectangle.H + 1)
    

    befor the return nil

  • (Question) Total pages

    (Question) Total pages

    How to check how many pages has imported pdf. I was trying something like bellow but doesn't work.

    ` tpl1 := pdf.ImportPage("my.pdf", 1, "/MediaBox")

    pdf.UseImportedTemplate(tpl1, 50, 100, 400, 0)
    
    pages := pdf.GetNumberOfPages()
    

    `

  • AddPage now duplicating previous page.

    AddPage now duplicating previous page.

    I recently revived a project previously working perfect.

    Now after updates to this library, when I use the AddPage function, I am getting a cloned previous page, like the buffer isn't cleared.

  • Adobe 110 error after generation of document

    Adobe 110 error after generation of document

    Hi, i tried to generate a pdf document with the gopdf library using a template downloaded from a storage location. The method works fine and when i see the document generated in the browser, it will open fine. But once the the document is downloaded in a local folder and when i'll try to open it, adobe 110 error occurs. PS: Template doesn't contain errors. I'll try to show a simplified version of the method i wrote:

    pdf := gopdf.GoPdf{}
    pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 841.89, H: 595.28}})
    pdf.AddPageWithOption(gopdf.PageOption{PageSize: &gopdf.Rect{W: 841.89, H: 595.28}})
    fileUrl, errSt := storage.Get("private", <path>, 10*60*time.Second)
    if errSt != nil {
    	return errSt.Error() + "Errore 114", errSt
    }
    errFile := DownloadFile("template.pdf", fileUrl)
    if errFile != nil {
    	return errFile.Error() + "Errore 121", errFile
    }
    tpl1 := pdf.ImportPage("template.pdf", 1, "/MediaBox")
    pdf.UseImportedTemplate(tpl1, 0, 0, 841.89, 595.28)
    
    filePdf := pdf.GetBytesPdf()
    fileReader := bytes.NewReader(filePdf)
    
    storage.Upload("private", fileReader, <path>, fileReader.Size(), "application/pdf", nil)
    return "ok", nil
    
Related tags
goldmark-pdf is a renderer for goldmark that allows rendering to PDF.
goldmark-pdf is a renderer for goldmark that allows rendering to PDF.

A PDF renderer for the goldmark markdown parser.

Dec 27, 2022
A PDF processor written in Go.
A PDF processor written in Go.

pdfcpu: a Go PDF processor pdfcpu is a PDF processing library written in Go supporting encryption. It provides both an API and a CLI. Supported are al

Jan 8, 2023
Newser is a simple utility to generate a pdf with you favorite news articles
Newser is a simple utility to generate a pdf with you favorite news articles

Newser A simple utility to crawl some news sites or other resources and download content into a pdf Building Make sure you have config.yaml setup and

Nov 9, 2022
Golang wrapper for Exiftool : extract as much metadata as possible (EXIF, ...) from files (pictures, pdf, office documents, ...)

go-exiftool go-exiftool is a golang library that wraps ExifTool. ExifTool's purpose is to extract as much metadata as possible (EXIF, IPTC, XMP, GPS,

Dec 28, 2022
A PDF document generator with high level support for text, drawing and images

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

Jan 4, 2023
PDF tools for reMarkable tablets

rm-pdf-tools - PDF tools for reMarkable Disclaimer: rm-pdf-tools is currently in a very early version, bugs are to be expected. Furthermore, the inten

Oct 14, 2022
A command line tool for mainly exporting logbook records from Google Spreadsheet to PDF file in EASA format
A command line tool for mainly exporting logbook records from Google Spreadsheet to PDF file in EASA format

Logbook CLI This is a command line tool for mainly exporting logbook records from Google Spreadsheet to PDF file in EASA format. It also supports rend

Feb 6, 2022
A Docker-powered stateless API for PDF files.
A Docker-powered stateless API for PDF files.

Gotenberg provides a developer-friendly API to interact with powerful tools like Chromium and LibreOffice to convert many documents (HTML, Markdown, Word, Excel, etc.) to PDF, transform them, merge them, and more!

Dec 30, 2022
PDF file parser

#pdf A pdf document parsing and modifying library The libary provides functions to parse and show elements in PDF documents. It checks the validity

Nov 7, 2021
create PDF from ASCII File for Cable labels

CableLable create PDF from ASCII File for Cable labels file format is one label per line, a line containing up to 3 words, each word is a line on the

Nov 8, 2021
Convert document to pdf with golang

Convert document to pdf Build docker: docker build --pull --rm -f "Dockerfile" -t convertdocument:latest "." docker run -p 3000:3000 registry.gitlab.

Nov 29, 2021
Ghostinthepdf - This is a small tool that helps to embed a PostScript file into a PDF

This is a small tool that helps to embed a PostScript file into a PDF in a way that GhostScript will run the PostScript code during the

Dec 20, 2022
Read data from rss, convert in pdf and send to kindle. Amazon automatically convert them in azw3.

Kindle-RSS-PDF-AZW3 The Kindle RSS PDF AZW3 is a personal project. The Kindle RSS PDF AZW3 is a personal project. I received a Kindle for Christmas, a

Jan 10, 2022
Go-wk - PDF Generation API with wkhtmltopdf

Simple PDF Generation API with wkhtmltopdf Quick start Clone the repo locally an

Jan 25, 2022
PDF Annotator of Nightmares πŸŽƒ
PDF Annotator of Nightmares πŸŽƒ

PDFrankenstein is a GUI tool that intends to fill the gap on Linux where a good capable PDF annotator like Adobe Acrobat does not exist. What can you

Dec 8, 2022
Dirmap is a tool for generating a directory map.

dirmap ?? dirmap is a tool for generating a directory map. It extracts a part of the document from markdown or source code of each directory and uses

Nov 21, 2022
Go-lang based sonos standup system

Overview This is an CLI tool that can handle timed standup playback on a sonos device. It allows you to add links to audio files that will be randomly

Nov 23, 2021
goelftools is library written in Go for parsing ELF file.

goelftools goelftools is library written in Go for parsing ELF file. This library is inspired by pyelftools and rbelftools. Motivation The motivation

Dec 5, 2022
GoCsv is a library written in pure Go to use csv data more comfortable

GoCsv GoCsv is a library written in pure Go to use csv data more comfortable Supported Go version golang >= 1.13 Installation go get github.com/shr004

Nov 1, 2022