writer

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 7, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package writer implements PDF writing infrastructure.

Package writer provides infrastructure for writing PDF files.

This package implements the low-level PDF writing functionality, including object management, cross-reference tables, and file structure.

Package writer provides PDF writing infrastructure for generating PDF files.

Package writer implements PDF writing infrastructure.

Package writer implements PDF writing infrastructure.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func CompressStream

func CompressStream(data []byte, level CompressionLevel) ([]byte, error)

CompressStream compresses data using zlib (FlateDecode in PDF terminology).

PDF's FlateDecode filter uses zlib compression, which includes:

  • 2-byte zlib header
  • Deflate-compressed data
  • 4-byte Adler-32 checksum

This is different from raw deflate compression.

Parameters:

  • data: Uncompressed data to compress
  • level: Compression level (NoCompression, BestSpeed, DefaultCompression, BestCompression)

Returns:

  • compressed: Compressed data (zlib format)
  • error: Any error that occurred

Example:

content := []byte("BT /F1 12 Tf 100 700 Td (Hello) Tj ET")
compressed, err := CompressStream(content, DefaultCompression)

Reference: PDF 1.7 Specification, Section 7.4.4 (FlateDecode Filter).

func CreateAcroFormDict

func CreateAcroFormDict(fieldRefs []int, fontObjNum int) string

CreateAcroFormDict creates the AcroForm dictionary for the catalog.

The AcroForm dictionary is required when a document contains form fields. It includes:

  • /Fields: Array of all form field references
  • /NeedAppearances: true (let the PDF reader generate appearances)
  • /DR: Default resources (fonts)
  • /DA: Default appearance string

PDF structure:

<<
  /Fields [101 0 R 102 0 R ...]
  /NeedAppearances true
  /DR <<
    /Font <<
      /Helv 5 0 R
      /Cour 6 0 R
      /TiRo 7 0 R
    >>
  >>
  /DA (/Helv 12 Tf 0 g)
>>

Parameters:

  • fieldRefs: Array of form field object numbers
  • fontObjNum: Object number of Helvetica font (for default appearance)

Returns the AcroForm dictionary as a PDF object string.

func CreateFontObjects

func CreateFontObjects(textOps []TextOp) (map[string]*fonts.Standard14Font, error)

CreateFontObjects creates PDF font objects for the fonts used in text operations.

Returns a map of font name -> *Standard14Font.

This allows the writer to create font objects and assign them object numbers.

func DecompressStream

func DecompressStream(data []byte) ([]byte, error)

DecompressStream decompresses zlib data (FlateDecode filter).

This is the inverse of CompressStream, used for reading compressed streams.

Parameters:

  • data: Compressed data (zlib format)

Returns:

  • decompressed: Decompressed data
  • error: Any error that occurred (invalid format, checksum mismatch, etc.)

Example:

decompressed, err := DecompressStream(compressed)

Reference: PDF 1.7 Specification, Section 7.4.4 (FlateDecode Filter).

func EscapePDFString

func EscapePDFString(s string) string

EscapePDFString escapes a string for use in PDF literal strings.

PDF literal strings are enclosed in parentheses: (Hello World)

Escapes:

  • \ → \\
  • ( → \(
  • ) → \)
  • \n → \n (newline)
  • \r → \r (carriage return)
  • \t → \t (tab)
  • \b → \b (backspace)
  • \f → \f (form feed)

Unicode characters (including Cyrillic) are passed through as-is. The caller is responsible for encoding them appropriately (usually UTF-16BE for text strings in PDF).

Example:

EscapePDFString("Hello")              // "Hello"
EscapePDFString("Price: $50 (USD)")   // "Price: $50 \\(USD\\)"
EscapePDFString("Line1\nLine2")       // "Line1\\nLine2"
EscapePDFString("C:\\path")           // "C:\\\\path"
EscapePDFString("Привет")             // "Привет" (unchanged)

Reference: PDF 1.7 Spec, Table 3 (Escape sequences in literal strings).

func EstimateCompressionRatio

func EstimateCompressionRatio(data []byte) float64

EstimateCompressionRatio estimates the compression ratio for given data.

This is useful for deciding whether to compress a stream:

  • Ratio < 0.9: Good compression, use FlateDecode
  • Ratio >= 0.9: Poor compression, store uncompressed

Parameters:

  • data: Uncompressed data

Returns:

  • ratio: Estimated compression ratio (compressed size / original size)

Note: This actually compresses the data to get an accurate estimate. For a fast heuristic, check if data contains repeated patterns.

func ShouldCompress

func ShouldCompress(data []byte) bool

ShouldCompress determines if data should be compressed based on size and content.

Heuristic:

  • Data < 50 bytes: Don't compress (overhead not worth it)
  • Data >= 50 bytes: Compress (likely worth it for text content)

For more precise control, use EstimateCompressionRatio.

Parameters:

  • data: Uncompressed data

Returns:

  • bool: true if compression is recommended

Types

type BezierSegment

type BezierSegment struct {
	Start Point
	C1    Point
	C2    Point
	End   Point
}

BezierSegment represents a cubic Bézier curve segment.

type CMYK

type CMYK struct {
	C float64 // Cyan
	M float64 // Magenta
	Y float64 // Yellow
	K float64 // blacK
}

CMYK represents a CMYK color (0.0 to 1.0 range).

type ColorStopOp

type ColorStopOp struct {
	Position float64
	Color    RGB
}

ColorStopOp represents a color stop in a gradient.

type CompressionLevel

type CompressionLevel int

CompressionLevel defines compression level for streams.

PDF uses FlateDecode filter, which is based on zlib (deflate with header and checksum).

Levels:

  • NoCompression: Store data without compression (fastest, largest)
  • BestSpeed: Fast compression with lower compression ratio
  • DefaultCompression: Balanced speed and compression (recommended)
  • BestCompression: Maximum compression (slowest, smallest)

Reference: PDF 1.7 Specification, Table 3.4 (Standard Filters).

const (
	// NoCompression disables compression (level 0).
	NoCompression CompressionLevel = 0

	// BestSpeed uses fastest compression (level 1).
	BestSpeed CompressionLevel = 1

	// DefaultCompression uses default zlib compression (level -1).
	// This is the recommended setting for most use cases.
	DefaultCompression CompressionLevel = -1

	// BestCompression uses maximum compression (level 9).
	BestCompression CompressionLevel = 9
)

type ContentStreamWriter

type ContentStreamWriter struct {
	// contains filtered or unexported fields
}

ContentStreamWriter builds PDF content streams.

A content stream is a sequence of PDF operators and operands that describe page content (text, graphics, images).

Example:

csw := NewContentStreamWriter()
csw.BeginText()
csw.SetFont("F1", 12)
csw.MoveTextPosition(100, 700)
csw.ShowText("Hello World")
csw.EndText()
content := csw.Bytes()

Reference: PDF 1.7 Specification, Section 8.2 (Content Streams and Resources).

Example (Combined)

ExampleContentStreamWriter_combined demonstrates combining text and graphics.

package main

import (
	"fmt"

	"github.com/coregx/gxpdf/internal/writer"
)

func main() {
	csw := writer.NewContentStreamWriter()

	// Draw a filled rectangle.
	csw.SaveState()
	csw.SetFillColorRGB(0.9, 0.9, 1.0) // Light blue
	csw.Rectangle(40.0, 40.0, 220.0, 80.0)
	csw.Fill()
	csw.RestoreState()

	// Add text on top.
	csw.BeginText()
	csw.SetFont("Times-Roman", 14.0)
	csw.MoveTextPosition(50.0, 60.0)
	csw.ShowText("Inside Box")
	csw.EndText()

	// Verify content was created.
	if csw.Len() > 0 {
		fmt.Println("Content stream created successfully")
	}
}
Output:

Content stream created successfully
Example (Compression)

ExampleContentStreamWriter_compression demonstrates content stream compression.

package main

import (
	"fmt"

	"github.com/coregx/gxpdf/internal/writer"
)

func main() {
	csw := writer.NewContentStreamWriter()

	// Create some content.
	csw.BeginText()
	csw.SetFont("Courier", 10.0)
	csw.MoveTextPosition(50.0, 750.0)
	csw.ShowText("This text will be compressed")
	csw.EndText()

	// Compress the content.
	compressed, err := csw.Compress()
	if err != nil {
		fmt.Printf("Compression error: %v\n", err)
		return
	}

	// Show that compression worked.
	if len(compressed) > 0 && csw.Len() > 0 {
		fmt.Println("Content stream compressed successfully")
	}
}
Output:

Content stream compressed successfully
Example (Rectangle)

ExampleContentStreamWriter_rectangle demonstrates drawing a rectangle.

package main

import (
	"fmt"

	"github.com/coregx/gxpdf/internal/writer"
)

func main() {
	csw := writer.NewContentStreamWriter()

	// Save state, set stroke color, draw rectangle.
	csw.SaveState()
	csw.SetStrokeColorRGB(1.0, 0.0, 0.0) // Red
	csw.SetLineWidth(2.0)
	csw.Rectangle(50.0, 50.0, 200.0, 100.0)
	csw.Stroke()
	csw.RestoreState()

	fmt.Println(csw.String())
}
Output:

q
1.00 0.00 0.00 RG
2.00 w
50.00 50.00 200.00 100.00 re
S
Q
Example (SimpleText)

ExampleContentStreamWriter_simpleText demonstrates creating a simple text content stream.

package main

import (
	"fmt"

	"github.com/coregx/gxpdf/internal/writer"
)

func main() {
	csw := writer.NewContentStreamWriter()

	// Create text content.
	csw.BeginText()
	csw.SetFont("Helvetica", 12.0)
	csw.MoveTextPosition(100.0, 700.0)
	csw.ShowText("Hello World")
	csw.EndText()

	// Get the content stream.
	fmt.Println(csw.String())
}
Output:

BT
/Helvetica 12.00 Tf
100.00 700.00 Td
(Hello World) Tj
ET

func NewContentStreamWriter

func NewContentStreamWriter() *ContentStreamWriter

NewContentStreamWriter creates a new content stream writer.

By default, compression is enabled with DefaultCompression level. Use SetCompression to change the compression level.

func (*ContentStreamWriter) BeginText

func (csw *ContentStreamWriter) BeginText()

BeginText begins a text object (BT operator).

Reference: PDF 1.7 Spec, Section 9.4 (Text Objects).

func (*ContentStreamWriter) Bytes

func (csw *ContentStreamWriter) Bytes() []byte

Bytes returns the accumulated content stream data.

func (*ContentStreamWriter) CloseAndStroke

func (csw *ContentStreamWriter) CloseAndStroke()

CloseAndStroke closes and strokes the path (s operator).

Reference: PDF 1.7 Spec, Section 8.5.3 (Path-Painting Operators).

func (*ContentStreamWriter) ClosePath

func (csw *ContentStreamWriter) ClosePath()

ClosePath closes the current subpath (h operator).

Reference: PDF 1.7 Spec, Section 8.5.2 (Path Construction Operators).

func (*ContentStreamWriter) Compress deprecated

func (csw *ContentStreamWriter) Compress() ([]byte, error)

Compress compresses the content stream using Flate encoding.

Deprecated: Use CompressedBytes() instead, which uses the configured compression level.

Returns compressed bytes or error.

func (*ContentStreamWriter) CompressedBytes

func (csw *ContentStreamWriter) CompressedBytes() ([]byte, error)

CompressedBytes returns the content stream compressed using the configured compression level.

If compression is disabled (NoCompression), returns uncompressed bytes.

Returns:

  • compressed: Compressed bytes (or uncompressed if NoCompression)
  • error: Any compression error

Example:

csw := NewContentStreamWriter()
csw.BeginText()
csw.ShowText("Hello")
csw.EndText()
compressed, err := csw.CompressedBytes()

func (*ContentStreamWriter) ConcatMatrix

func (csw *ContentStreamWriter) ConcatMatrix(a, b, c, d, e, f float64)

ConcatMatrix modifies the current transformation matrix (cm operator).

Parameters:

  • a, b, c, d, e, f: Matrix coefficients

Reference: PDF 1.7 Spec, Section 8.4.4 (Coordinate Systems).

func (*ContentStreamWriter) CurveTo

func (csw *ContentStreamWriter) CurveTo(x1, y1, x2, y2, x3, y3 float64)

CurveTo appends a cubic Bezier curve (c operator).

Parameters:

  • x1, y1: First control point
  • x2, y2: Second control point
  • x3, y3: End point

Reference: PDF 1.7 Spec, Section 8.5.2 (Path Construction Operators).

func (*ContentStreamWriter) EndPath

func (csw *ContentStreamWriter) EndPath()

EndPath ends the path without filling or stroking (n operator).

Reference: PDF 1.7 Spec, Section 8.5.3 (Path-Painting Operators).

func (*ContentStreamWriter) EndText

func (csw *ContentStreamWriter) EndText()

EndText ends a text object (ET operator).

Reference: PDF 1.7 Spec, Section 9.4 (Text Objects).

func (*ContentStreamWriter) Fill

func (csw *ContentStreamWriter) Fill()

Fill fills the path (f operator).

Uses nonzero winding number rule.

Reference: PDF 1.7 Spec, Section 8.5.3 (Path-Painting Operators).

func (*ContentStreamWriter) FillAndStroke

func (csw *ContentStreamWriter) FillAndStroke()

FillAndStroke fills and strokes the path (B operator).

Uses nonzero winding number rule.

Reference: PDF 1.7 Spec, Section 8.5.3 (Path-Painting Operators).

func (*ContentStreamWriter) FillAndStrokeEvenOdd

func (csw *ContentStreamWriter) FillAndStrokeEvenOdd()

FillAndStrokeEvenOdd fills and strokes using even-odd rule (B* operator).

Reference: PDF 1.7 Spec, Section 8.5.3 (Path-Painting Operators).

func (*ContentStreamWriter) FillEvenOdd

func (csw *ContentStreamWriter) FillEvenOdd()

FillEvenOdd fills the path using even-odd rule (f* operator).

Reference: PDF 1.7 Spec, Section 8.5.3 (Path-Painting Operators).

func (*ContentStreamWriter) GetCompression

func (csw *ContentStreamWriter) GetCompression() CompressionLevel

GetCompression returns the current compression level.

func (*ContentStreamWriter) IsCompressed

func (csw *ContentStreamWriter) IsCompressed() bool

IsCompressed returns true if compression is enabled.

Compression is disabled when level is NoCompression.

func (*ContentStreamWriter) Len

func (csw *ContentStreamWriter) Len() int

Len returns the length of the accumulated content.

func (*ContentStreamWriter) LineTo

func (csw *ContentStreamWriter) LineTo(x, y float64)

LineTo appends a straight line segment (l operator).

Parameters:

  • x, y: End point coordinates

Reference: PDF 1.7 Spec, Section 8.5.2 (Path Construction Operators).

func (*ContentStreamWriter) MoveTextPosition

func (csw *ContentStreamWriter) MoveTextPosition(tx, ty float64)

MoveTextPosition moves to the start of the next line (Td operator).

Parameters:

  • tx: Horizontal translation
  • ty: Vertical translation

Reference: PDF 1.7 Spec, Section 9.4.2 (Text-Positioning Operators).

func (*ContentStreamWriter) MoveTextPositionSetLeading

func (csw *ContentStreamWriter) MoveTextPositionSetLeading(tx, ty float64)

MoveTextPositionSetLeading moves to next line and sets leading (TD operator).

Parameters:

  • tx: Horizontal translation
  • ty: Vertical translation (also sets leading to -ty)

Reference: PDF 1.7 Spec, Section 9.4.2 (Text-Positioning Operators).

func (*ContentStreamWriter) MoveTo

func (csw *ContentStreamWriter) MoveTo(x, y float64)

MoveTo begins a new subpath (m operator).

Parameters:

  • x, y: Starting point coordinates

Reference: PDF 1.7 Spec, Section 8.5.2 (Path Construction Operators).

func (*ContentStreamWriter) MoveToNextLine

func (csw *ContentStreamWriter) MoveToNextLine()

MoveToNextLine moves to the start of the next line (T* operator).

Reference: PDF 1.7 Spec, Section 9.4.2 (Text-Positioning Operators).

func (*ContentStreamWriter) Rectangle

func (csw *ContentStreamWriter) Rectangle(x, y, width, height float64)

Rectangle appends a rectangle (re operator).

Parameters:

  • x, y: Lower-left corner
  • width, height: Rectangle dimensions

Reference: PDF 1.7 Spec, Section 8.5.2 (Path Construction Operators).

func (*ContentStreamWriter) Reset

func (csw *ContentStreamWriter) Reset()

Reset clears the content stream buffer.

func (*ContentStreamWriter) RestoreState

func (csw *ContentStreamWriter) RestoreState()

RestoreState restores the graphics state (Q operator).

Reference: PDF 1.7 Spec, Section 8.4.2 (Graphics State Stack).

func (*ContentStreamWriter) SaveState

func (csw *ContentStreamWriter) SaveState()

SaveState saves the graphics state (q operator).

Reference: PDF 1.7 Spec, Section 8.4.2 (Graphics State Stack).

func (*ContentStreamWriter) SetCompression

func (csw *ContentStreamWriter) SetCompression(level CompressionLevel)

SetCompression sets the compression level for this content stream.

Parameters:

  • level: Compression level (NoCompression, BestSpeed, DefaultCompression, BestCompression)

This affects the output of CompressedBytes() method.

Example:

csw := NewContentStreamWriter()
csw.SetCompression(BestCompression)  // Maximum compression
// ... add content ...
compressed, _ := csw.CompressedBytes()

func (*ContentStreamWriter) SetDashPattern

func (csw *ContentStreamWriter) SetDashPattern(dashArray []float64, dashPhase float64)

SetDashPattern sets the line dash pattern (d operator).

Parameters:

  • dashArray: Array of dash and gap lengths
  • dashPhase: Starting offset into the pattern

Reference: PDF 1.7 Spec, Section 8.4.3 (Graphics State Parameters).

func (*ContentStreamWriter) SetFillColorCMYK

func (csw *ContentStreamWriter) SetFillColorCMYK(c, m, y, k float64)

SetFillColorCMYK sets the fill color in CMYK (k operator).

Parameters:

  • c, m, y, k: CMYK values (0.0 to 1.0)

Reference: PDF 1.7 Spec, Section 8.6.8 (Color Operators).

func (*ContentStreamWriter) SetFillColorGray

func (csw *ContentStreamWriter) SetFillColorGray(gray float64)

SetFillColorGray sets the fill color in grayscale (g operator).

Parameters:

  • gray: Grayscale value (0.0 = black, 1.0 = white)

Reference: PDF 1.7 Spec, Section 8.6.8 (Color Operators).

func (*ContentStreamWriter) SetFillColorRGB

func (csw *ContentStreamWriter) SetFillColorRGB(r, g, b float64)

SetFillColorRGB sets the fill color in RGB (rg operator).

Parameters:

  • r, g, b: RGB values (0.0 to 1.0)

Reference: PDF 1.7 Spec, Section 8.6.8 (Color Operators).

func (*ContentStreamWriter) SetFont

func (csw *ContentStreamWriter) SetFont(fontName string, size float64)

SetFont sets the text font and size (Tf operator).

Parameters:

  • fontName: Font resource name (e.g., "F1")
  • size: Font size in points

Reference: PDF 1.7 Spec, Section 9.3 (Text State Parameters and Operators).

func (*ContentStreamWriter) SetLeading

func (csw *ContentStreamWriter) SetLeading(leading float64)

SetLeading sets the text leading (TL operator).

Leading is the vertical distance between text lines.

Parameters:

  • leading: Leading value in text space units

Reference: PDF 1.7 Spec, Section 9.3.5 (Text State Parameters).

func (*ContentStreamWriter) SetLineCap

func (csw *ContentStreamWriter) SetLineCap(style int)

SetLineCap sets the line cap style (J operator).

Parameters:

  • style: 0 = butt cap, 1 = round cap, 2 = projecting square cap

Reference: PDF 1.7 Spec, Section 8.4.3 (Graphics State Parameters).

func (*ContentStreamWriter) SetLineJoin

func (csw *ContentStreamWriter) SetLineJoin(style int)

SetLineJoin sets the line join style (j operator).

Parameters:

  • style: 0 = miter join, 1 = round join, 2 = bevel join

Reference: PDF 1.7 Spec, Section 8.4.3 (Graphics State Parameters).

func (*ContentStreamWriter) SetLineWidth

func (csw *ContentStreamWriter) SetLineWidth(width float64)

SetLineWidth sets the line width (w operator).

Parameters:

  • width: Line width in user space units

Reference: PDF 1.7 Spec, Section 8.4.3 (Graphics State Parameters).

func (*ContentStreamWriter) SetMiterLimit

func (csw *ContentStreamWriter) SetMiterLimit(limit float64)

SetMiterLimit sets the miter limit (M operator).

Parameters:

  • limit: Maximum ratio of miter length to line width

Reference: PDF 1.7 Spec, Section 8.4.3 (Graphics State Parameters).

func (*ContentStreamWriter) SetStrokeColorCMYK

func (csw *ContentStreamWriter) SetStrokeColorCMYK(c, m, y, k float64)

SetStrokeColorCMYK sets the stroke color in CMYK (K operator).

Parameters:

  • c, m, y, k: CMYK values (0.0 to 1.0)

Reference: PDF 1.7 Spec, Section 8.6.8 (Color Operators).

func (*ContentStreamWriter) SetStrokeColorGray

func (csw *ContentStreamWriter) SetStrokeColorGray(gray float64)

SetStrokeColorGray sets the stroke color in grayscale (G operator).

Parameters:

  • gray: Grayscale value (0.0 = black, 1.0 = white)

Reference: PDF 1.7 Spec, Section 8.6.8 (Color Operators).

func (*ContentStreamWriter) SetStrokeColorRGB

func (csw *ContentStreamWriter) SetStrokeColorRGB(r, g, b float64)

SetStrokeColorRGB sets the stroke color in RGB (RG operator).

Parameters:

  • r, g, b: RGB values (0.0 to 1.0)

Reference: PDF 1.7 Spec, Section 8.6.8 (Color Operators).

func (*ContentStreamWriter) SetTextMatrix

func (csw *ContentStreamWriter) SetTextMatrix(a, b, c, d, e, f float64)

SetTextMatrix sets the text matrix (Tm operator).

The text matrix determines text positioning and scaling.

Parameters:

  • a, b, c, d: Matrix coefficients for scaling/rotation
  • e, f: Translation (horizontal, vertical)

Reference: PDF 1.7 Spec, Section 9.4.2 (Text-Positioning Operators).

func (*ContentStreamWriter) ShowText

func (csw *ContentStreamWriter) ShowText(text string)

ShowText shows a text string (Tj operator).

Parameters:

  • text: Text to display (will be escaped)

Reference: PDF 1.7 Spec, Section 9.4.3 (Text-Showing Operators).

func (*ContentStreamWriter) ShowTextNextLine

func (csw *ContentStreamWriter) ShowTextNextLine(text string)

ShowTextNextLine moves to next line and shows text (' operator).

Equivalent to: T* followed by Tj.

Parameters:

  • text: Text to display (will be escaped)

Reference: PDF 1.7 Spec, Section 9.4.3 (Text-Showing Operators).

func (*ContentStreamWriter) String

func (csw *ContentStreamWriter) String() string

String returns the content stream as a string (for debugging).

func (*ContentStreamWriter) Stroke

func (csw *ContentStreamWriter) Stroke()

Stroke strokes the path (S operator).

Reference: PDF 1.7 Spec, Section 8.5.3 (Path-Painting Operators).

type GradientOp

type GradientOp struct {
	Type GradientType

	// ColorStops define the color transitions (minimum 2).
	ColorStops []ColorStopOp

	// Linear gradient coordinates
	X1, Y1, X2, Y2 float64

	// Radial gradient coordinates
	X0, Y0, R0, R1 float64

	// Extend flags
	ExtendStart bool
	ExtendEnd   bool
}

GradientOp represents a gradient fill operation.

type GradientType

type GradientType int

GradientType represents the type of gradient.

const (
	// GradientTypeLinear is an axial gradient (ShadingType 2).
	GradientTypeLinear GradientType = 2
	// GradientTypeRadial is a radial gradient (ShadingType 3).
	GradientTypeRadial GradientType = 3
)

type GraphicsOp

type GraphicsOp struct {
	Type int // 0=line, 1=rect, 2=circle, 5=polygon, 6=polyline, 7=ellipse, 8=bezier

	// Common fields
	X float64
	Y float64

	// Line fields
	X2 float64
	Y2 float64

	// Rectangle fields
	Width  float64
	Height float64

	// Circle fields
	Radius float64

	// Ellipse fields
	RX float64 // Horizontal radius
	RY float64 // Vertical radius

	// Polygon/Polyline fields
	Vertices []Point

	// Bezier fields
	BezierSegs []BezierSegment
	Closed     bool // For Bezier curves

	// Appearance
	StrokeColor     *RGB
	StrokeColorCMYK *CMYK // If set, takes precedence over StrokeColor
	FillColor       *RGB
	FillColorCMYK   *CMYK       // If set, takes precedence over FillColor
	FillGradient    *GradientOp // Gradient fill
	StrokeWidth     float64
	Dashed          bool
	DashArray       []float64
	DashPhase       float64
}

GraphicsOp represents a graphics drawing operation.

This is an infrastructure-level representation of graphics operations from the creator package.

type IndirectObject

type IndirectObject struct {
	// Number is the object number (must be positive).
	Number int

	// Generation is the generation number (usually 0).
	Generation int

	// Data contains the serialized object data (dictionary, array, etc.).
	Data []byte
}

IndirectObject represents a PDF indirect object.

In PDF format, indirect objects are uniquely identified by: - Object number (positive integer) - Generation number (usually 0 for new objects)

Format in PDF file:

N G obj
... object data ...
endobj

Example:

1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj

func CreateContentStreamObject

func CreateContentStreamObject(objNum int, content []byte, compress bool) *IndirectObject

CreateContentStreamObject creates a PDF stream object for content.

Format (uncompressed):

N 0 obj
<< /Length M >>
stream
... content ...
endstream
endobj

Format (compressed):

N 0 obj
<< /Length M /Filter /FlateDecode >>
stream
... compressed content ...
endstream
endobj

Parameters:

  • objNum: Object number for this stream
  • content: Stream content (uncompressed)
  • compress: If true, compress the content using FlateDecode

Returns the IndirectObject ready to write.

func NewIndirectObject

func NewIndirectObject(number, generation int, data []byte) *IndirectObject

NewIndirectObject creates a new indirect object.

Parameters:

  • number: Object number (must be positive)
  • generation: Generation number (usually 0)
  • data: Serialized object data

Example:

catalogData := []byte("<< /Type /Catalog /Pages 2 0 R >>")
obj := NewIndirectObject(1, 0, catalogData)

func (*IndirectObject) String

func (o *IndirectObject) String() string

String returns a string representation of the object (for debugging).

func (*IndirectObject) WriteTo

func (o *IndirectObject) WriteTo(w io.Writer) (int64, error)

WriteTo writes the indirect object to the writer.

Format:

N G obj
<data>
endobj

Returns the number of bytes written and any error.

type PageContent

type PageContent struct {
	// TextOperations are the text drawing operations for this page.
	TextOperations []TextOp

	// GraphicsOperations are the graphics drawing operations for this page.
	GraphicsOperations []GraphicsOp

	// Resources tracks fonts and other resources used on this page.
	Resources *ResourceDictionary
}

PageContent represents the content and resources for a single page.

This structure bridges the Creator API (which tracks text operations) with the Writer infrastructure (which generates PDF bytes).

type PdfWriter

type PdfWriter struct {
	// contains filtered or unexported fields
}

PdfWriter writes PDF documents to files.

This is the main infrastructure component for PDF file generation. It manages object numbering, cross-reference tables, and file structure.

Example:

doc := document.NewDocument()
doc.AddPage(document.A4)

writer, err := NewPdfWriter("output.pdf")
if err != nil {
    return err
}
defer writer.Close()

err = writer.Write(doc)

func NewPdfWriter

func NewPdfWriter(path string) (*PdfWriter, error)

NewPdfWriter creates a new PDF writer for the specified file path.

The file will be created or truncated if it already exists.

Returns an error if the file cannot be created.

func (*PdfWriter) Close

func (w *PdfWriter) Close() error

Close closes the writer and the underlying file.

It's safe to call Close multiple times.

func (*PdfWriter) Write

func (w *PdfWriter) Write(doc *document.Document) error

Write writes a document to the PDF file.

This performs the following steps: 1. Write PDF header with version 2. Write catalog object 3. Write pages object tree 4. Write cross-reference table 5. Write trailer

Returns an error if: - Document validation fails. - Document has no pages. - Any write operation fails.

func (*PdfWriter) WriteAllAnnotations

func (w *PdfWriter) WriteAllAnnotations(
	page *document.Page,
) ([]*IndirectObject, []int, error)

WriteAllAnnotations writes all annotations from a page and returns annotation objects.

This handles link, text, markup, and stamp annotations.

Returns:

  • annotObjs: Array of annotation indirect objects
  • annotRefs: Array of annotation object numbers (for /Annots array)
  • error: Any error that occurred

func (*PdfWriter) WriteAnnotations

func (w *PdfWriter) WriteAnnotations(
	annotations []*document.LinkAnnotation,
) ([]*IndirectObject, []int, error)

WriteAnnotations writes link annotations and returns annotation objects.

DEPRECATED: Use WriteAllAnnotations instead for pages, or writeLinkAnnotations for specific link annotations. This method is kept for backward compatibility.

For each annotation, creates an indirect object with the annotation dictionary.

Returns:

  • annotObjs: Array of annotation indirect objects
  • annotRefs: Array of annotation object numbers (for /Annots array)
  • error: Any error that occurred

func (*PdfWriter) WriteWithAllContent

func (w *PdfWriter) WriteWithAllContent(
	doc *document.Document,
	textContents map[int][]TextOp,
	graphicsContents map[int][]GraphicsOp,
) error

WriteWithAllContent writes a document with text and graphics content operations.

This is similar to WriteWithPageContent() but accepts both text and graphics operations.

Parameters:

  • doc: The document to write
  • textContents: Text operations for each page (indexed by page number)
  • graphicsContents: Graphics operations for each page (indexed by page number)

Returns an error if validation or writing fails.

func (*PdfWriter) WriteWithPageContent

func (w *PdfWriter) WriteWithPageContent(doc *document.Document, pageContents map[int][]TextOp) error

WriteWithPageContent writes a document with page content operations to the PDF file.

This is similar to Write() but accepts page-level content operations (text, graphics, etc.) that will be rendered as PDF content streams.

Parameters:

  • doc: The document to write
  • pageContents: Content operations for each page (indexed by page number)

Returns an error if validation or writing fails.

type Point

type Point struct {
	X float64
	Y float64
}

Point represents a 2D point.

type RGB

type RGB struct {
	R float64
	G float64
	B float64
}

RGB represents an RGB color (0.0 to 1.0 range).

type ResourceDictionary

type ResourceDictionary struct {
	// contains filtered or unexported fields
}

ResourceDictionary manages PDF page resources (fonts, images, graphics states, etc.).

Resources are referenced in content streams by name (e.g., /F1 for fonts, /Im1 for images). This struct tracks resource names and their corresponding PDF object numbers.

PDF Dictionary Format:

/Resources <<
  /Font << /F1 5 0 R /F2 6 0 R >>
  /XObject << /Im1 7 0 R >>
  /ExtGState << /GS1 8 0 R >>
  /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
>>

Thread Safety: Not thread-safe. Caller must synchronize if needed.

Example

ExampleResourceDictionary demonstrates basic usage of ResourceDictionary.

package main

import (
	"fmt"

	"github.com/coregx/gxpdf/internal/writer"
)

func main() {
	// Create a new resource dictionary.
	rd := writer.NewResourceDictionary()

	// Add a font resource.
	fontName := rd.AddFont(5) // Font object is at 5 0 R
	fmt.Printf("Font name: %s\n", fontName)

	// Add another font.
	fontName2 := rd.AddFont(6) // Font object is at 6 0 R
	fmt.Printf("Second font name: %s\n", fontName2)

	// Add an image.
	imageName := rd.AddImage(10) // Image object is at 10 0 R
	fmt.Printf("Image name: %s\n", imageName)

	// Get the PDF dictionary.
	fmt.Println(rd.String())

}
Output:

Font name: F1
Second font name: F2
Image name: Im1
<< /Font << /F1 5 0 R /F2 6 0 R >> /XObject << /Im1 10 0 R >> /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >>
Example (Empty)

ExampleResourceDictionary_empty demonstrates an empty resource dictionary.

package main

import (
	"fmt"

	"github.com/coregx/gxpdf/internal/writer"
)

func main() {
	rd := writer.NewResourceDictionary()

	// Check if dictionary has resources.
	fmt.Printf("Has resources: %v\n", rd.HasResources())

	// Empty dictionary outputs minimal syntax.
	fmt.Println(rd.String())

}
Output:

Has resources: false
<< >>
Example (Fonts)

ExampleResourceDictionary_fonts demonstrates managing font resources.

package main

import (
	"fmt"

	"github.com/coregx/gxpdf/internal/writer"
)

func main() {
	rd := writer.NewResourceDictionary()

	// Add fonts for a multi-font document.
	helvetica := rd.AddFont(5) // Object 5: Helvetica
	times := rd.AddFont(6)     // Object 6: Times-Roman
	courier := rd.AddFont(7)   // Object 7: Courier

	fmt.Printf("Helvetica: %s, Times: %s, Courier: %s\n", helvetica, times, courier)
	fmt.Println(rd.String())

}
Output:

Helvetica: F1, Times: F2, Courier: F3
<< /Font << /F1 5 0 R /F2 6 0 R /F3 7 0 R >> /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >>
Example (Images)

ExampleResourceDictionary_images demonstrates managing image resources.

package main

import (
	"fmt"

	"github.com/coregx/gxpdf/internal/writer"
)

func main() {
	rd := writer.NewResourceDictionary()

	// Add images for a document with graphics.
	logo := rd.AddImage(10)    // Object 10: Company logo
	photo := rd.AddImage(11)   // Object 11: Product photo
	diagram := rd.AddImage(12) // Object 12: Technical diagram

	fmt.Printf("Logo: %s, Photo: %s, Diagram: %s\n", logo, photo, diagram)
	fmt.Println(rd.String())

}
Output:

Logo: Im1, Photo: Im2, Diagram: Im3
<< /XObject << /Im1 10 0 R /Im2 11 0 R /Im3 12 0 R >> /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >>
Example (Mixed)

ExampleResourceDictionary_mixed demonstrates combining different resource types.

package main

import (
	"fmt"

	"github.com/coregx/gxpdf/internal/writer"
)

func main() {
	rd := writer.NewResourceDictionary()

	// Real-world document with fonts, images, and graphics states.
	rd.AddFont(5)       // Helvetica
	rd.AddFont(6)       // Times-Roman
	rd.AddImage(10)     // Logo
	rd.AddExtGState(15) // Transparency state

	fmt.Printf("Has resources: %v\n", rd.HasResources())
	fmt.Println(rd.String())

}
Output:

Has resources: true
<< /Font << /F1 5 0 R /F2 6 0 R >> /XObject << /Im1 10 0 R >> /ExtGState << /GS1 15 0 R >> /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >>

func GenerateContentStream

func GenerateContentStream(textOps []TextOp) (content []byte, resources *ResourceDictionary, err error)

GenerateContentStream generates a PDF content stream from text and graphics operations.

Graphics are drawn BEFORE text (so text appears on top).

Returns:

  • content: The content stream bytes
  • resources: The resource dictionary for fonts used
  • error: Any error that occurred

Example content stream:

BT
0 0 0 rg
/F1 24 Tf
100 700 Td
(Hello World) Tj
ET

func GenerateContentStreamWithGraphics

func GenerateContentStreamWithGraphics(textOps []TextOp, graphicsOps []GraphicsOp) (content []byte, resources *ResourceDictionary, err error)

GenerateContentStreamWithGraphics generates a PDF content stream from text and graphics operations.

Graphics are drawn BEFORE text (so text appears on top).

Returns:

  • content: The content stream bytes
  • resources: The resource dictionary for fonts used
  • error: Any error that occurred

func NewResourceDictionary

func NewResourceDictionary() *ResourceDictionary

NewResourceDictionary creates a new empty resource dictionary.

func (*ResourceDictionary) AddExtGState

func (rd *ResourceDictionary) AddExtGState(objNum int) string

AddExtGState adds a graphics state resource and returns its resource name.

Graphics states are named sequentially: GS1, GS2, GS3, etc.

Parameters:

  • objNum: PDF object number of the ExtGState dictionary

Returns:

  • Resource name (e.g., "GS1")

Example:

rd := NewResourceDictionary()
name := rd.AddExtGState(15)  // Returns "GS1"
// In content stream: /GS1 gs (apply graphics state GS1)

func (*ResourceDictionary) AddFont

func (rd *ResourceDictionary) AddFont(objNum int) string

AddFont adds a font resource and returns its resource name.

Fonts are named sequentially: F1, F2, F3, etc.

Parameters:

  • objNum: PDF object number of the font dictionary

Returns:

  • Resource name (e.g., "F1")

Example:

rd := NewResourceDictionary()
name := rd.AddFont(5)  // Returns "F1"
// In content stream: /F1 12 Tf (set font F1 at 12pt)

func (*ResourceDictionary) AddImage

func (rd *ResourceDictionary) AddImage(objNum int) string

AddImage adds an image XObject resource and returns its resource name.

Images are named sequentially: Im1, Im2, Im3, etc.

Parameters:

  • objNum: PDF object number of the image XObject

Returns:

  • Resource name (e.g., "Im1")

Example:

rd := NewResourceDictionary()
name := rd.AddImage(10)  // Returns "Im1"
// In content stream: /Im1 Do (draw image Im1)

func (*ResourceDictionary) Bytes

func (rd *ResourceDictionary) Bytes() []byte

Bytes returns the resource dictionary as PDF bytes.

Format:

<< /Font << /F1 5 0 R >> /XObject << /Im1 10 0 R >> /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >>

Returns empty dictionary if no resources are registered:

<< >>

Note: Resource names are sorted alphabetically for consistent output.

func (*ResourceDictionary) HasResources

func (rd *ResourceDictionary) HasResources() bool

HasResources returns true if any resources are registered.

Use this to check if the resource dictionary is empty before writing.

func (*ResourceDictionary) String

func (rd *ResourceDictionary) String() string

String returns the resource dictionary as a PDF string.

Convenience method for debugging and testing.

type TextOp

type TextOp struct {
	Text      string  // Text to display
	X         float64 // Horizontal position (points from left)
	Y         float64 // Vertical position (points from bottom)
	Font      string  // Font name (e.g., "Helvetica")
	Size      float64 // Font size in points
	Color     RGB     // Text color (RGB)
	ColorCMYK *CMYK   // Text color (CMYK, optional - takes precedence over RGB)
}

TextOp represents a text drawing operation.

This is an infrastructure-level representation of text operations from the creator package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL