pdf

  1. pdf
    1. Description
    2. Author
    3. Maintainer
    4. Repository
    5. Requirements
    6. Documentation
      1. Building documents
        1. build-doc
        2. with-document
        3. with-document-to-file
        4. write-document
        5. doc-compress-streams?
        6. doc-pdf-version
      2. Building pages
        1. build-page-context
        2. with-page
        3. page-context-port
        4. page-width
        5. in-text-mode
        6. with-graphics-state
        7. with-clip
      3. Object model
        1. build-font
        2. register-font
        3. font-name
        4. build-ext-gstate
        5. ext-gstate-name
        6. build-indirect-obj
        7. build-dictionary
        8. build-pdf-stream
        9. add-dictionary-item
        10. get-obj-ref
        11. doc-catalog
        12. indirect-obj-content
        13. unit-size
      4. Text operators
      5. Graphics state operators
      6. Path construction operators
      7. Painting operators
      8. Color operators
      9. Geometry helpers
    7. Examples

Description

A library for PDF generation.

Author

Marc Battyani and Bruce Butterfield

Maintainer

Ivan Raikov

Repository

This egg is hosted on the CHICKEN Subversion repository:

https://anonymous@code.call-cc.org/svn/chicken-eggs/release/6/pdf

If you want to check out the source code repository of this egg and you are not familiar with Subversion, see this page.

Requirements

srfi-1, regex, format

Documentation

A PDF document under construction is a record of type doc, created by build-doc. The content of a page content is a record of type page-context, created by build-page-context. Both are passed as arguments to the PDF operators described below, so independent documents can be built in the same program without interfering with each other.

Each document is created for a specific PDF version, "1.3" or "1.4". A "1.3" document (the default) only allows core PDF functionality. A "1.4" document additionally allows PDF 1.4 features, such as alpha transparency. See build-doc.

Building documents

build-doc
[procedure] (build-doc [COMPRESS-STREAMS? [PDF-VERSION]])

Creates and returns a new, empty document. COMPRESS-STREAMS? (default #t) sets whether streams are compressed when the document is written. PDF-VERSION (default "1.3") must be "1.3" or "1.4"; it sets the document's PDF version, and determines whether PDF 1.4 features such as alpha transparency (see build-ext-gstate) can be used. Signals an error if PDF-VERSION is neither.

with-document
[syntax] (with-document (DOC [COMPRESS-STREAMS? [PDF-VERSION]]) BODY ...)

Binds DOC to a new document (as build-doc) for BODY, and evaluates to the finished document.

with-document-to-file
[syntax] (with-document-to-file (DOC [COMPRESS-STREAMS? [PDF-VERSION]]) FILENAME BODY ...)

Like with-document, but writes the finished document to FILENAME (as write-document) instead of returning it.

write-document
[procedure] (write-document DOC FILE [VERSION] [TRAILER-EXTRA])

Writes DOC to FILE. VERSION (default: DOC's own PDF version, set by build-doc) is the PDF version string written to the file header; it can be overridden here independently of DOC's version. TRAILER-EXTRA (default "") is raw text appended to the trailer dictionary, after /Root.

doc-compress-streams?
[procedure] (doc-compress-streams? DOC)
[procedure] (doc-compress-streams?-set! DOC BOOLEAN)

Reads or sets whether DOC's streams are compressed.

doc-pdf-version
[procedure] (doc-pdf-version DOC)
[procedure] (doc-pdf-version-set! DOC VERSION)

Reads or sets DOC's PDF version ("1.3" or "1.4"), as set by build-doc.

Building pages

build-page-context
[procedure] (build-page-context PORT [WIDTH] [HEIGHT])

Creates and returns a new page context wrapping the output port PORT, for a page of WIDTH by HEIGHT points (defaulting to 612 by 792, i.e. US Letter).

with-page
[syntax] (with-page DOC (PAGE [WIDTH HEIGHT]) BODY ...)

Binds PAGE to a new page context for BODY to draw into, then adds the finished page to DOC. WIDTH and HEIGHT default to the standard page size.

page-context-port
[procedure] (page-context-port PAGE)

Returns the output port PAGE draws into.

page-width
[procedure] (page-width PAGE)
[procedure] (page-height PAGE)

Return PAGE's width or height, in points.

in-text-mode
[syntax] (in-text-mode PAGE BODY ...)

Wraps BODY in a PDF text object (BT/ET) on PAGE. Text must be drawn inside in-text-mode.

with-graphics-state
[syntax] (with-graphics-state PAGE BODY ...)

Saves PAGE's graphics state, runs BODY, then restores it (q/Q). Any change BODY makes -- to color, line width, the clip region, the coordinate system, alpha, and so on -- is undone once BODY finishes.

with-clip
[syntax] (with-clip PAGE (CLIP-FORM ...) BODY ...)
[syntax] (with-clip PAGE even-odd (CLIP-FORM ...) BODY ...)

Restricts drawing in BODY to the region enclosed by the path built by CLIP-FORM ... (a sequence of path construction operators, such as basic-rect or move-to/line-to). The region is determined by the nonzero-winding rule, or by the even-odd rule if the literal symbol even-odd is given as the second argument. Since with-clip is built on with-graphics-state, the clip region -- and any other state BODY changes -- is undone once BODY finishes.

Object model

Lower-level procedures for constructing PDF objects directly, e.g. from a library building on top of pdf.

build-font
[procedure] (build-font DOC BASE-FONT)

Adds a font named BASE-FONT (e.g. "Helvetica") to DOC and returns it.

register-font
[procedure] (register-font DOC FONT-OBJ [PREFIX])

Registers an already-built font dictionary object FONT-OBJ (see build-indirect-obj and build-dictionary) in DOC: assigns it a resource name starting with PREFIX (default "/CLF", the same prefix build-font uses) and records it so every page's /Font resource includes it. Returns FONT-OBJ.

build-font is written in terms of register-font. Call register-font directly when building a font dictionary by hand, e.g. for a font type build-font does not support.

font-name
[procedure] (font-name FONT)

Returns the resource name FONT was assigned (for use with set-font), as a string, e.g. "/CLF1".

build-ext-gstate
[procedure] (build-ext-gstate DOC [FILL-ALPHA [STROKE-ALPHA [BLEND-MODE]]])

Adds a PDF 1.4 ExtGState resource to DOC and returns it, for controlling alpha transparency and blend mode in later drawing (see set-ext-gstate). FILL-ALPHA and STROKE-ALPHA, if given, are constant alpha values from 0.0 (fully transparent) to 1.0 (fully opaque), applied to fill and stroke operations respectively. BLEND-MODE, if given, is a blend mode name, e.g. "Multiply". Signals an error unless DOC was created with PDF version "1.4" (see build-doc), since ExtGState is a PDF 1.4 feature, not part of core PDF 1.3.

ext-gstate-name
[procedure] (ext-gstate-name EXT-GSTATE)

Returns the resource name EXT-GSTATE was assigned (for use with set-ext-gstate), as a string, e.g. "/GS1".

build-indirect-obj
[procedure] (build-indirect-obj DOC CONTENT [REGISTER?])

Wraps CONTENT (a dictionary or stream) as an indirect object with a freshly assigned object number, and, unless REGISTER? is #f, registers it in DOC to be written out. Returns the indirect object.

build-dictionary
[procedure] (build-dictionary VALUES)

Returns a PDF dictionary object from VALUES, an alist of ("/Key" . value) pairs.

build-pdf-stream
[procedure] (build-pdf-stream CONTENT [EXTRA] [FORCE-UNCOMPRESSED?])

Returns a PDF stream object holding CONTENT (a string of raw bytes). EXTRA is an alist of additional dictionary entries for the stream. If FORCE-UNCOMPRESSED? is true, the stream is never compressed, regardless of DOC's compression setting.

add-dictionary-item
[procedure] (add-dictionary-item DICT NAME VALUE)

Adds NAME/VALUE to dictionary DICT.

get-obj-ref
[procedure] (get-obj-ref OBJ)

Returns the PDF indirect reference (e.g. "3 0 R") for indirect object OBJ.

doc-catalog
[procedure] (doc-catalog DOC)

Returns DOC's /Catalog indirect object.

indirect-obj-content
[procedure] (indirect-obj-content OBJ)

Returns the dictionary or stream wrapped by indirect object OBJ.

unit-size
[procedure] (unit-size)

Returns the number of points per inch (72).

Text operators

Each operator below writes to PAGE's content stream and must be called inside in-text-mode (except set-font, which may be called anywhere on the page).

(set-font PAGE FONT-NAME SIZE)
selects a font and size (Tf)
(move-to-next-line PAGE)
moves to the start of the next line (T*)
(draw-text PAGE STR)
draws STR at the current position (Tj)
(move-text PAGE DX DY)
moves the text position by (DX, DY) (Td)
(draw-text-on-next-line PAGE STR)
moves to the next line and draws STR (')
(set-text-rendering-mode PAGE MODE)
sets the text rendering mode (Tr)
(set-char-spacing PAGE SPACE)
sets extra character spacing (Tc)
(set-text-x-scale PAGE SCALE)
sets horizontal text scaling (Tz)
(set-text-leading PAGE SPACE)
sets line leading (TL)
(set-text-rise PAGE RISE)
sets text rise (baseline offset) (Ts)
(set-text-matrix PAGE A B C D E F)
sets the text matrix (Tm)
(draw-and-adjust-string PAGE STRINGS)
draws STRINGS, a list mixing substrings and numeric kerning adjustments (TJ)
(escape STR)
escapes (, ), and \ in STR for use in a PDF literal string

Graphics state operators

(rotate PAGE DEGREES)
rotates the coordinate system
(translate PAGE DX DY)
translates the coordinate system
(scale PAGE SX SY)
scales the coordinate system
(set-line-width PAGE WIDTH)
sets the stroke line width
(set-line-cap PAGE MODE)
sets the line cap style
(set-line-join PAGE MODE)
sets the line join style
(set-dash-pattern PAGE DASH-ARRAY PHASE)
sets the dash pattern
(set-mitter-limit PAGE LIMIT)
sets the miter limit
(save-graphics-state PAGE)
pushes the current graphics state onto a stack (q)
(restore-graphics-state PAGE)
pops the graphics state stack, undoing changes made since the matching save-graphics-state (Q)
(set-ext-gstate PAGE NAME)
applies a PDF 1.4 ExtGState resource built by build-ext-gstate, e.g. for alpha transparency (gs)

save-graphics-state and restore-graphics-state must be correctly paired; with-graphics-state (see Building pages, above) does this automatically.

Path construction operators

(move-to PAGE X Y)
starts a new subpath at (X, Y)
(line-to PAGE X Y)
adds a straight line segment to (X, Y)
(bezier-to PAGE X1 Y1 X2 Y2 X3 Y3)
adds a cubic Bezier curve with two control points
(bezier2-to PAGE X2 Y2 X3 Y3)
adds a cubic Bezier curve using the current point as its first control point
(bezier3-to PAGE X1 Y1 X3 Y3)
adds a cubic Bezier curve using the end point as its second control point
(close-path PAGE)
closes the current subpath
(basic-rect PAGE X Y DX DY)
adds a rectangle subpath

Painting operators

(stroke PAGE)
strokes the current path
(close-and-stroke PAGE)
closes and strokes the current path
(fill-path PAGE)
fills the current path (nonzero winding rule)
(close-and-fill PAGE)
closes and fills the current path
(even-odd-fill PAGE)
fills the current path (even-odd rule)
(fill-and-stroke PAGE)
fills then strokes the current path
(even-odd-fill-and-stroke PAGE)
fills (even-odd rule) then strokes the current path
(close-fill-and-stroke PAGE)
closes, fills, then strokes the current path
(close-even-odd-fill-and-stroke PAGE)
closes, fills (even-odd rule), then strokes the current path
(end-path-no-op PAGE)
ends the current path without painting it
(clip-path PAGE)
intersects the clip region with the current path (nonzero winding rule)
(even-odd-clip-path PAGE)
intersects the clip region with the current path (even-odd rule)

Clipping only takes effect at the next path-painting operator (commonly end-path-no-op, if the path itself should not also be painted), and stays in effect until the graphics state is restored (see with-graphics-state). with-clip (see Building pages, above) combines all of this into one step.

Color operators

(set-gray-stroke PAGE GRAY)
sets the stroke color, gray scale
(set-gray-fill PAGE GRAY)
sets the fill color, gray scale
(set-rgb-stroke PAGE R G B)
sets the stroke color, RGB
(set-rgb-fill PAGE R G B)
sets the fill color, RGB
(set-cymk-stroke PAGE C Y M K)
sets the stroke color, CMYK
(set-cymk-fill PAGE C Y M K)
sets the fill color, CMYK

Geometry helpers

Higher-level shapes built from the path construction operators above.

+2pi+
the constant 2pi
+pi/2+
the constant pi/2
(arc PAGE CX CY RADIUS START EXTENT)
adds an arc subpath, closed with a chord back to the center
(pie PAGE CX CY RADIUS START EXTENT)
adds a pie-slice subpath
(circle PAGE CX CY RADIUS)
adds a circular subpath
(ellipse PAGE CX CY RADIUS-A RADIUS-B)
adds an elliptical subpath
(rectangle PAGE X Y DX DY RADIUS)
adds a rectangle subpath, with rounded corners if RADIUS is nonzero
(polyline PAGE POINTS RADIUS CLOSED?)
adds a subpath through POINTS (a list of (X Y) pairs), with corners rounded by RADIUS
(regular-polygon PAGE CX CY RADIUS SIDES [FILLET-RADIUS])
adds a regular polygon subpath
(star PAGE CX CY EXT-RADIUS INT-RADIUS SIDES [FILLET-RADIUS])
adds a star subpath

Examples


(import scheme (chicken base) (chicken random) (prefix pdf pdf:))
(define random pseudo-random-integer)

(define-constant pi 3.14159)

(define-syntax dotimes
  (syntax-rules ()
    ((_ (index maxval) body ...)
     (do ((index 0 (+ index 1)))
       ((= index maxval))
       body ...))))

(define (ex1)
  (pdf:with-document-to-file (doc) "ex1.pdf"
   (let ((helvetica (pdf:build-font doc "Helvetica"))
         (courier (pdf:build-font doc "Courier")))
     (pdf:with-page doc (pg)
      (pdf:in-text-mode pg
       (pdf:set-font pg (pdf:font-name helvetica) 36)
       (pdf:move-text pg 100 750)
       (pdf:draw-text pg "scm-pdf: Example 1"))
      (pdf:in-text-mode pg
       (dotimes (i 25)
                    (pdf:set-font pg (pdf:font-name helvetica) (* i 1.5))
                    (pdf:move-text pg (+ i 5) (+ i 10))
                    (pdf:draw-text pg "Helvetica")))
      (pdf:in-text-mode pg
       (dotimes (i 25)
                    (pdf:set-font pg (pdf:font-name courier) (* i 1.5))
                    (pdf:move-text pg (+ i 5) (- 50 (+ i 10)))
                    (pdf:draw-text pg "Courier")))))))

(define (ex2)
  (pdf:with-document-to-file (doc) "ex2.pdf"
   (let ((helvetica (pdf:build-font doc "Helvetica")))
     (pdf:with-page doc (pg)
      (pdf:in-text-mode pg
       (pdf:set-font pg (pdf:font-name helvetica) 36)
       (pdf:move-text pg 100 750)
       (pdf:draw-text pg "scm-pdf: Example 2"))
      (pdf:translate pg 230 500)
      (do ((j 0 (+ j 1))
           (i 0.67 (* i 1.045)))
        ((= j 101))
        (pdf:in-text-mode pg
         (pdf:set-font pg (pdf:font-name helvetica) i)
         (pdf:move-text pg (* i 3) 0)
         (pdf:draw-text pg "rotation"))
        (pdf:rotate pg 18)))
     (pdf:with-page doc (pg)
      (pdf:in-text-mode pg
       (pdf:set-font pg (pdf:font-name helvetica) 40)
       (pdf:move-text pg 230 500)
       (pdf:draw-text pg "That's All, Folks!"))))))

(define (ex3)
  (pdf:with-document-to-file (doc) "ex3.pdf"
   (let ((helvetica (pdf:build-font doc "Helvetica")))
     (pdf:with-page doc (pg 800 1000)
      (pdf:in-text-mode pg
       (pdf:set-font pg (pdf:font-name helvetica) 36.0)
       (pdf:move-text pg 100 900)
       (pdf:draw-text pg "scm-pdf: Example 3"))
      (pdf:move-to pg (+ 10 (random 500))(+ 10 (random 400)))
      (pdf:set-gray-fill pg 0.5)
      (dotimes (i 50)
               (pdf:line-to pg (+ 50 (random 500)) (+ 50 (random 400))))
      (pdf:close-even-odd-fill-and-stroke pg)
      (pdf:move-to pg (+ 50 (random 500))(+ 400 (random 400)))
      (pdf:set-rgb-fill pg 0.5 0.5 0.8)
      (pdf:set-rgb-stroke pg 0.9 0.5 0.1)
      (dotimes (i 50)
               (pdf:bezier2-to pg (+ 50 (random 500)) (+ 400 (random 400))
                           (+ 50 (random 500)) (+ 400 (random 400))))
      (pdf:close-even-odd-fill-and-stroke pg)))))

(define (ex4)
  (pdf:with-document-to-file (doc) "ex4.pdf"
   (let ((helvetica (pdf:build-font doc "Helvetica")))
     (pdf:with-page doc (pg)
       (pdf:in-text-mode pg
        (pdf:set-font pg (pdf:font-name helvetica) 36.0)
        (pdf:move-text pg 100 750)
        (pdf:draw-text pg "scm-pdf: Example 4"))
       (pdf:set-rgb-stroke pg 0.1 0.1 0.1)
       (pdf:set-rgb-fill pg 0.8 0.8 0.8)
       (let ((x 50) (y 600))
         (dotimes (i 2)
                  (pdf:rectangle pg x y 500 140 10)
                  (pdf:close-fill-and-stroke pg)
                  (set! y (- y 180))))
       (pdf:translate pg 50 670)
       (let ((x 50) (y 0))
         (do ((i 0 (+ i 1))
              (j 8 (* j 1.05)))
           ((= i 4))
           (pdf:set-rgb-fill pg (* 0.1 j) (* 0.01 j) (* 0.02 j))
           (pdf:circle pg x y (* 4 j))
           (pdf:close-fill-and-stroke pg)
           (pdf:ellipse pg (+ x 250) y (* 5 j) (* 4 j))
           (pdf:close-fill-and-stroke pg)
           (set! x (+ x 50))))

       (pdf:translate pg 0 -180)
       (pdf:regular-polygon pg 150 0 50 7 8)
       (pdf:close-fill-and-stroke pg)
       (pdf:star pg 350 0 50 30 6 5)
       (pdf:close-fill-and-stroke pg)

       (pdf:set-rgb-fill pg 0.8 0.6 0.2)
       (pdf:regular-polygon pg 150 0 30 5 4)
       (pdf:close-fill-and-stroke pg)
       (pdf:star pg 350 0 40 20 4 6)
       (pdf:close-fill-and-stroke pg)

       (pdf:set-rgb-fill pg 0.4 0.8 0.7)
       (pdf:regular-polygon pg 150 0 15 3 3)
       (pdf:close-fill-and-stroke pg)
       (pdf:star pg 350 0 35 10 12 1)
       (pdf:close-fill-and-stroke pg)

       (pdf:set-line-width pg 0.5)
       (do ((r 2 (+ r 2)))
         ((= r 100))
         (pdf:set-rgb-stroke pg (* 0.01 (random 100))
                             (* 0.01 (random 100))
                             (* 0.01 (random 100)))
         (pdf:arc pg 250 -230 r (* pi 0.001 (random 2000))
                             (* pi 0.001 (random 2000)))
         (pdf:stroke pg))))))


;; Demonstrates the PDF 1.4-gated features: a document built with
;; pdf-version "1.4" is required before build-ext-gstate will produce
;; alpha-transparency resources; with-clip and with-graphics-state wrap
;; the underlying W/W*/n and q/Q operators so clip regions and state
;; changes (fill color, alpha) are automatically undone afterward.
(define (ex5)
  (pdf:with-document-to-file (doc #t "1.4") "ex5.pdf"
   (let ((helvetica (pdf:build-font doc "Helvetica"))
         (gs-half (pdf:build-ext-gstate doc 0.5))
         (gs-quarter (pdf:build-ext-gstate doc 0.25 #f "/Multiply")))
     (pdf:with-page doc (pg)
      (pdf:in-text-mode pg
       (pdf:set-font pg (pdf:font-name helvetica) 36)
       (pdf:move-text pg 100 750)
       (pdf:draw-text pg "scm-pdf: Example 5"))
      ;; Clip subsequent drawing to a rounded rectangle, then draw a row
      ;; of overlapping, half-transparent circles inside it; the clip
      ;; region and the fill color/alpha changes made here are all
      ;; undone once with-clip's body ends.
      (pdf:with-clip pg ((pdf:rectangle pg 100 400 300 300 20))
       (pdf:set-rgb-fill pg 0.8 0.2 0.2)
       (do ((i 0 (+ i 1))) ((= i 6))
         (pdf:with-graphics-state pg
          (pdf:set-ext-gstate pg (pdf:ext-gstate-name gs-half))
          (pdf:circle pg (+ 150 (* i 40)) 550 80)
          (pdf:fill-path pg))))
      ;; Outside the clip region, draw a second overlapping shape using
      ;; the other ExtGState (lower alpha, Multiply blend mode).
      (pdf:set-rgb-fill pg 0.2 0.2 0.8)
      (pdf:with-graphics-state pg
       (pdf:set-ext-gstate pg (pdf:ext-gstate-name gs-quarter))
       (pdf:circle pg 250 250 100)
       (pdf:fill-path pg)
       (pdf:circle pg 320 250 100)
       (pdf:fill-path pg))))))

(ex1)
(ex2)
(ex3)
(ex4)
(ex5)