Exporting PDFs from Field

Field's 2d drawing facilities may be used to draw UI, notation, debugging information, and the like. But they may also make geometry for artworks directly, forming a 2d parametric drawing system that's part vector- and part image-based — ideal for procedural print-making.

Ultimately, you need to get the lines you make out of Field. To this end Field supports the exportation of lines as PDF's using this simple command:

outputFilename = makePDF()

makePDF(...) has lots of options, discussed below, but it defaults to exporting everything in the canvas to a new temp filename (which it returns).

For example, an algorithmic drawing noodle:

p = FLine()
for n in range(0, 1500):
    p.moveTo(Math.random()*300, Math.random()*300)
    p.relCubicTo(Math.random()*10, Math.random()*10, Math.random()*10, Math.random()*10, Math.random()*300, Math.random()*300)
    if (n%2==1):
        p(color=Vector4(0,0,0,0.3), derived=1)
        p = FLine()


results in a canvas with:

Note: if you are primarily using Field to generate PDFs you might want to set the background color of the canvas to something other than Field's default grey. For example:


will give you a white canvas background.


makePDF(geometry, bounds, background, scale, filename) — this command turns geometry FLines into PDFs. All of its parameters are keywords and optional.

To export one visual element:

makePDF(geometry=_self.lines, filename="/Users/marc/Desktop/aPdf.pdf")

To export many pieces of geometry, this exports the geometry in every visual element whose name starts with "toExport":

makePDF(geometry=[x.lines for x in _self.find["toExport.*"]], filename="/Users/marc/Desktop/aPdf.pdf")

To export everything in the canvas:

file = makePDF(filename="/Users/marc/Desktop/aPdf.pdf")

(Note the call to openFile which opens a file in whatever would open it if you double-clicked on it in the Finder). In Preview this looks like:

All of these commands above build a page size and a bounding box from the geometry that you pass in. To change the mapping between Field's internal unit (essentially pixels if you don't zoom in or out) and PDF's idea of points, use the scale parameter:

makePDF(filename="/Users/marc/Desktop/aPdf.pdf", scale=5)

This results in a page that's 5 times bigger (and a drawing that's 5 times bigger as well). Line thicknesses, however, remain the same size.

To craft the relationship between the page bounding box and the geometry, pass in a Rect or another FLine that defines the boundary that you want to draw:

makePDF(filename="/Users/marc/Desktop/aPdf.pdf", scale=5, bounds=Rect(40,40,1000,1000))

One final thing to note: images do export to pdfs with makePDF. And, since you can rasterize FLine collections to images and place these images directly on-top of the geometry that created them you can form very "hybrid" practices moving between PDF and image inside Field.

Pixels are not Dots

One limitation of this approach — crafting PDF's on screen to ultimately make high resolution prints — stems simply from the fact that a 72dpi or a 100dpi screen really isn't the same kind of thing as a 2400dpi printer. Clearly you can iterate your way towards this (and, ultimately, making high quality algorithmically generated prints just uses a lot of paper). But Field offers a couple of extension points that enable you to take the geometry on screen and filter it as it heads towards the PDF file, as a first, experimental step.

For example, in general, to make things look good on screen we find ourselves overlapping a large number of transparent lines; in print-making we have much more resolution at this fine scale, lines 1 point thick, transparent or otherwise, appear fat and clumsy.

On the right, a close zoom of a pdf with some overlapping transparent, 1pt (that is, thickness=1) lines with alpha 0.1. On the left, something that looks much better when printed.

Simultaneously, very thin lines that are 'transparent' ultimately become a mess of dots, since printers don't generally vary the 'transparency' of their ink.

In Field we can write something like this:

def transformThicknessAndOpacity(inside, thickness, opacity):
    return Vector2(opacity*opacity*thickness, [thickness, 1][thickness>=1])

To intercept and modify the thicknesses and opacities of lines. A similar transform exists for colors (SimplePDFLineDrawing.colorTransform).


As of this writing, a few things don't "come out" in the PDF renderer — text labels being the most important. For now, you are better off converting it to actual pieces of geometry and rendering that. You'll have much better control over its appearance at high resolution.

Occasionally you'll find differences between Field's OpenGL based renderer and the PDF model — most noticeably long continuous transparent lines that overlap themselves appear as uniform colored areas in PDF's where in OpenGL their intersection areas are "darker". For tight control over line parameters (end caps and so on) you are better off stroking the line in Field before handing it to PDF.

There are also a few properties that you can set on lines that are honored only by the PDF renderer. Typically things to do with additional "adobe-centric" blending modes and transparency. Look at the FLine property documentation for details.