DrawBot Documentation

DrawBot is a powerful, free application for MacOSX that invites you to write simple Python scripts to generate two-dimensional graphics. The builtin graphics primitives support rectangles, ovals, (bezier) paths, polygons, text objects and transparency.

Education

DrawBot is an ideal tool to teach the basics of programming. Students get colorful graphic treats while getting familiar with variables, conditional statements, functions and what have you. Results can be saved in a selection of different file formats, including as high resolution, scaleable PDF, svg, movie, png, jpeg, tiff…

DrawBot has proven itself as part of the curriculum at selected courses at the Royal Academy in The Hague.

Python

DrawBot is written in Python. The binary download is fully self-contained (ie. it doesn’t need a Python install around), but the source code is available if you want to roll your own.

Shapes

Different shapes and how to make them.

Primitives

rect(x, y, w, h)

Draw a rectangle from position x, y with the given width and height.

# draw a rectangle
#    x    y    w    h
rect(100, 100, 800, 800)
oval(x, y, w, h)

Draw an oval from position x, y with the given width and height.

# draw an oval
#    x    y    w    h
oval(100, 100, 800, 800)
line((x1, y1), (x2, y2)))

Draws a line between two given points.

# set a stroke color
stroke(0)
# draw a line between two given points
line((100, 100), (900, 900))
polygon((x1, y1), (x2, y2), ..., close=True)

Draws a polygon with n-amount of points. Optionally a close argument can be provided to open or close the path. As default a polygon is a closed path.

# draw a polygon with x-amount of points
polygon((100, 100), (100, 900), (900, 900), (200, 800), close=True)

Drawing Paths

Using bezier paths.

newPath()

Create a new path.

moveTo(xy)

Move to a point x, y.

lineTo(xy)

Line to a point x, y.

curveTo(xy1, xy2, xy3)

Curve to a point x3, y3. With given bezier handles x1, y1 and x2, y2.

qCurveTo(*points)

Quadratic curve with a given set of off curves to a on curve.

arc(center, radius, startAngle, endAngle, clockwise)

Arc with center and a given radius, from startAngle to endAngle, going clockwise if clockwise is True and counter clockwise if clockwise is False.

arcTo(xy1, xy2, radius)

Arc from one point to an other point with a given radius.

pt0 = 74, 48
pt1 = 238, 182
pt2 = 46, 252
radius = 60

def drawPt(pos, r=5):
    x, y = pos
    oval(x-r, y-r, r*2, r*2)

size(300, 300)
fill(None)

path = BezierPath()
path.moveTo(pt0)
path.arcTo(pt1, pt2, radius)

stroke(0, 1, 1)
polygon(pt0, pt1, pt2)
for pt in [pt0, pt1, pt2]:
    drawPt(pt)

stroke(0, 0, 1)
drawPath(path)
stroke(1, 0, 1)
for pt in path.onCurvePoints:
    drawPt(pt, r=3)
for pt in path.offCurvePoints:
    drawPt(pt, r=2)
closePath()

Close the path.

drawPath(path=None)

Draw the current path, or draw the provided path.

# create a new empty path
newPath()
# set the first oncurve point
moveTo((100, 100))
# line to from the previous point to a new point
lineTo((100, 900))
lineTo((900, 900))

# curve to a point with two given handles
curveTo((900, 500), (500, 100), (100, 100))

# close the path
closePath()
# draw the path
drawPath()
clipPath(path=None)

Use the given path as a clipping path, or the current path if no path was given.

Everything drawn after a clipPath() call will be clipped by the clipping path. To “undo” the clipping later, make sure you do the clipping inside a with savedState(): block, as shown in the example.

# create a bezier path
path = BezierPath()
# draw a triangle
# move to a point
path.moveTo((100, 100))
# line to a point
path.lineTo((100, 900))
path.lineTo((900, 900))
# close the path
path.closePath()
# save the graphics state so the clipping happens only
# temporarily
with savedState():
    # set the path as a clipping path
    clipPath(path)
    # the oval will be clipped inside the path
    oval(100, 100, 800, 800)
# no more clipping here

Path Properties

strokeWidth(value)

Sets stroke width.

# set no fill
fill(None)
# set black as the stroke color
stroke(0)
# loop over a range of 10
for i in range(20):
    # in each loop set the stroke width
    strokeWidth(i)
    # draw a line
    line((100, 100), (200, 900))
    # and translate the canvas
    translate(30, 0)
miterLimit(value)

Set a miter limit. Used on corner points.

# create a path
path = BezierPath()
# move to a point
path.moveTo((100, 100))
# line to a point
path.lineTo((150, 700))
path.lineTo((300, 100))
# set stroke color to black
stroke(0)
# set no fill
fill(None)
# set the width of the stroke
strokeWidth(50)
# draw the path
drawPath(path)
# move the canvas
translate(500, 0)
# set a miter limit
miterLimit(5)
# draw the same path again
drawPath(path)
lineJoin(value)

Set a line join.

Possible values are miter, round and bevel.

# set the stroke color to black
stroke(0)
# set no fill
fill(None)
# set a stroke width
strokeWidth(30)
# set a miter limit
miterLimit(30)
# create a bezier path
path = BezierPath()
# move to a point
path.moveTo((100, 100))
# line to a point
path.lineTo((100, 600))
path.lineTo((160, 100))
# set a line join style
lineJoin("miter")
# draw the path
drawPath(path)
# translate the canvas
translate(300, 0)
# set a line join style
lineJoin("round")
# draw the path
drawPath(path)
# translate the canvas
translate(300, 0)
# set a line join style
lineJoin("bevel")
# draw the path
drawPath(path)
lineCap(value)

Set a line cap.

Possible values are butt, square and round.

# set stroke color to black
stroke(0)
# set a strok width
strokeWidth(50)
# translate the canvas
translate(150, 50)
# set a line cap style
lineCap("butt")
# draw a line
line((0, 200), (0, 800))
# translate the canvas
translate(300, 0)
# set a line cap style
lineCap("square")
# draw a line
line((0, 200), (0, 800))
# translate the canvase
translate(300, 0)
# set a line cap style
lineCap("round")
# draw a line
line((0, 200), (0, 800))
lineDash(*value)

Set a line dash with any given amount of lenghts. Uneven lenghts will have a visible stroke, even lenghts will be invisible.

# set stroke color to black
stroke(0)
# set a strok width
strokeWidth(50)
# translate the canvas
translate(150, 50)
# set a line dash
lineDash(2, 2)
# draw a line
line((0, 200), (0, 800))
# translate the canvas
translate(300, 0)
# set a line dash
lineDash(2, 10, 5, 5)
# draw a line
line((0, 200), (0, 800))
# translate the canvase
translate(300, 0)
# reset the line dash
lineDash(None)
# draw a line
line((0, 200), (0, 800))

BezierPath

BezierPath(path=None, glyphSet=None)

Return a BezierPath object. This is a reusable object, if you want to draw the same over and over again.

# create a bezier path
path = BezierPath()

# move to a point
path.moveTo((100, 100))
# line to a point
path.lineTo((100, 200))
path.lineTo((200, 200))
# close the path
path.closePath()

# loop over a range of 10
for i in range(10):
    # set a random color with alpha value of .3
    fill(random(), random(), random(), .3)
    # in each loop draw the path
    drawPath(path)
    # translate the canvas
    translate(50, 50)

path.text("Hello world", font="Helvetica", fontSize=30, offset=(210, 210))

print("All Points:")
print(path.points)

print("On Curve Points:")
print(path.onCurvePoints)

print("Off Curve Points:")
print(path.offCurvePoints)

# print out all points from all segments in all contours
for contour in path.contours:
    for segment in contour:
        for x, y in segment:
            print((x, y))
    print(["contour is closed", "contour is open"][contour.open])

# translate the path
path.translate(0, -100)
# draw the path again
drawPath(path)
# translate the path
path.translate(-300, 0)
path.scale(2)
# draw the path again
drawPath(path)
class BezierPath(path=None, glyphSet=None)

Bases: Mock, drawBot.context.baseContext.SVGContextPropertyMixin, drawBot.context.baseContext.ContextPropertyMixin

A bezier path object, if you want to draw the same over and over again.

contourClass

alias of BezierContour

moveTo(point)

Move to a point x, y.

lineTo(point)

Line to a point x, y.

curveTo(*points)

Draw a cubic bezier with an arbitrary number of control points.

The last point specified is on-curve, all others are off-curve (control) points.

qCurveTo(*points)

Draw a whole string of quadratic curve segments.

The last point specified is on-curve, all others are off-curve (control) points.

closePath()

Close the path.

beginPath(identifier=None)

Begin using the path as a so called point pen and start a new subpath.

addPoint(point, segmentType=None, smooth=False, name=None, identifier=None, **kwargs)

Use the path as a point pen and add a point to the current subpath. beginPath must have been called prior to adding points with addPoint calls.

endPath()

End the current subpath. Calling this method has two distinct meanings depending on the context:

When the bezier path is used as a segment pen (using moveTo, lineTo, etc.), the current subpath will be finished as an open contour.

When the bezier path is used as a point pen (using beginPath, addPoint and endPath), the path will process all the points added with addPoint, finishing the current subpath.

addComponent(glyphName, transformation)

Add a sub glyph. The ‘transformation’ argument must be a 6-tuple containing an affine transformation, or a Transform object from the fontTools.misc.transform module. More precisely: it should be a sequence containing 6 numbers.

A glyphSet is required during initialization of the BezierPath object.

drawToPen(pen)

Draw the bezier path into a pen

drawToPointPen(pointPen)

Draw the bezier path into a point pen.

arc(center, radius, startAngle, endAngle, clockwise)

Arc with center and a given radius, from startAngle to endAngle, going clockwise if clockwise is True and counter clockwise if clockwise is False.

arcTo(point1, point2, radius)

Arc defined by a circle inscribed inside the angle specified by three points: the current point, point1, and point2. The arc is drawn between the two points of the circle that are tangent to the two legs of the angle.

rect(x, y, w, h)

Add a rectangle at possition x, y with a size of w, h

oval(x, y, w, h)

Add a oval at possition x, y with a size of w, h

line(point1, point2)

Add a line between two given points.

polygon(*points, **kwargs)

Draws a polygon with n-amount of points. Optionally a close argument can be provided to open or close the path. As default a polygon is a closed path.

text(txt, offset=None, font='LucidaGrande', fontSize=10, align=None, fontNumber=0)

Draws a txt with a font and fontSize at an offset in the bezier path. If a font path is given the font will be installed and used directly.

Optionally an alignment can be set. Possible align values are: “left”, “center” and “right”.

The default alignment is left.

Optionally txt can be a FormattedString.

textBox(txt, box, font='LucidaGrande', fontSize=10, align=None, hyphenation=None, fontNumber=0)

Draws a txt with a font and fontSize in a box in the bezier path. If a font path is given the font will be installed and used directly.

Optionally an alignment can be set. Possible align values are: “left”, “center” and “right”.

The default alignment is left.

Optionally hyphenation can be provided.

Optionally txt can be a FormattedString. Optionally box can be a BezierPath.

traceImage(path, threshold=0.2, blur=None, invert=False, turd=2, tolerance=0.2, offset=None)

Convert a given image to a vector outline.

Optionally some tracing options can be provide:

  • threshold: the threshold used to bitmap an image
  • blur: the image can be blurred
  • invert: invert to the image
  • turd: the size of small turd that can be ignored
  • tolerance: the precision tolerance of the vector outline
  • offset: add the traced vector outline with an offset to the BezierPath
getNSBezierPath()

Return the nsBezierPath.

setNSBezierPath(path)

Set a nsBezierPath.

pointInside(xy)

Check if a point x, y is inside a path.

bounds()

Return the bounding box of the path in the form (x minimum, y minimum, x maximum, y maximum)` or, in the case of empty path None.

controlPointBounds()

Return the bounding box of the path including the offcurve points in the form (x minimum, y minimum, x maximum, y maximum)` or, in the case of empty path None.

optimizePath()
copy()

Copy the bezier path.

reverse()

Reverse the path direction

appendPath(otherPath)

Append a path.

translate(x=0, y=0)

Translate the path with a given offset.

rotate(angle, center=(0, 0))

Rotate the path around the center point (which is the origin by default) with a given angle in degrees.

scale(x=1, y=None, center=(0, 0))

Scale the path with a given x (horizontal scale) and y (vertical scale).

If only 1 argument is provided a proportional scale is applied.

The center of scaling can optionally be set via the center keyword argument. By default this is the origin.

skew(angle1, angle2=0, center=(0, 0))

Skew the path with given angle1 and angle2.

If only one argument is provided a proportional skew is applied.

The center of skewing can optionally be set via the center keyword argument. By default this is the origin.

transform(transformMatrix, center=(0, 0))

Transform a path with a transform matrix (xy, xx, yy, yx, x, y).

union(other)

Return the union between two bezier paths.

removeOverlap()

Remove all overlaps in a bezier path.

difference(other)

Return the difference between two bezier paths.

intersection(other)

Return the intersection between two bezier paths.

xor(other)

Return the xor between two bezier paths.

intersectionPoints(other=None)

Return a list of intersection points as x, y tuples.

Optionaly provide an other path object to find intersection points.

expandStroke(width, lineCap='round', lineJoin='round', miterLimit=10)

Returns a new bezier path with an expanded stroke around the original path, with a given width. Note: the new path will not contain the original path.

The following optional arguments are available with respect to line caps and joins: * lineCap: Possible values are “butt”, “square” or “round” * lineJoin: Possible values are “bevel”, “miter” or “round” * miterLimit: The miter limit to use for “miter” lineJoin option

points

Return an immutable list of all points in the BezierPath as point coordinate (x, y) tuples.

onCurvePoints

Return an immutable list of all on curve points in the BezierPath as point coordinate (x, y) tuples.

offCurvePoints

Return an immutable list of all off curve points in the BezierPath as point coordinate (x, y) tuples.

contours

Return an immutable list of contours with all point coordinates sorted in segments. A contour object has an open attribute.

svgClass

The svg class, as a string.

svgID

The svg id, as a string.

The svg link, as a string.

Colors

Fill

Set a fill before drawing a shape.

fill(r=None, g=None, b=None, alpha=1)

Sets the fill color with a red, green, blue and alpha value. Each argument must a value float between 0 and 1.

fill(1, 0, 0, .5)
# draw a rect
rect(10, 10, 200, 980)

# only set a gray value
fill(0)
# draw a rect
rect(200, 10, 200, 980)

# only set a gray value with an alpha
fill(0, .5)
# draw a rect
rect(400, 10, 200, 980)

# set rgb with no alpha
fill(1, 0, 0)
# draw a rect
rect(600, 10, 200, 980)

# set rgb with an alpha value
fill(1, 0, 0, .5)
# draw a rect
rect(800, 10, 190, 980)
linearGradient(startPoint=None, endPoint=None, colors=None, locations=None)

A linear gradient fill with:

  • startPoint as (x, y)
  • endPoint as (x, y)
  • colors as a list of colors, described similary as fill
  • locations of each color as a list of floats. (optionally)

Setting a gradient will ignore the fill.

# set a gradient as the fill color
linearGradient(
    (100, 100),                         # startPoint
    (800, 800),                         # endPoint
    [(1, 0, 0), (0, 0, 1), (0, 1, 0)],  # colors
    [0, .2, 1]                          # locations
    )
# draw a rectangle
rect(10, 10, 980, 980)
radialGradient(startPoint=None, endPoint=None, colors=None, locations=None, startRadius=0, endRadius=100)

A radial gradient fill with:

  • startPoint as (x, y)
  • endPoint as (x, y)
  • colors as a list of colors, described similary as fill
  • locations of each color as a list of floats. (optionally)
  • startRadius radius around the startPoint in degrees (optionally)
  • endRadius radius around the endPoint in degrees (optionally)

Setting a gradient will ignore the fill.

# set a gradient as the fill color
radialGradient(
    (300, 300),                         # startPoint
    (600, 600),                         # endPoint
    [(1, 0, 0), (0, 0, 1), (0, 1, 0)],  # colors
    [0, .2, 1],                         # locations
    0,                                  # startRadius
    500                                 # endRadius
    )
# draw a rectangle
rect(10, 10, 980, 980)
shadow(offset, blur=None, color=None)

Adds a shadow with an offset (x, y), blur and a color. The color argument must be a tuple similarly as fill. The offset`and `blur argument will be drawn independent of the current context transformations.

# a red shadow with some blur and a offset
shadow((100, 100), 100, (1, 0, 0))
# draw a rect
rect(100, 100, 600, 600)

Stroke

Set a stroke before drawing a shape.

stroke(r=None, g=None, b=None, alpha=1)

Sets the stroke color with a red, green, blue and alpha value. Each argument must a value float between 0 and 1.

# set the fill to none
fill(None)
# set a stroke width
stroke(1, 0, 0, .3)
strokeWidth(10)
# draw a rect
rect(10, 10, 180, 980)

# only set a gray value
stroke(0)
# draw a rect
rect(210, 10, 180, 980)

# only set a gray value with an alpha
stroke(0, .5)
# draw a rect
rect(410, 10, 180, 980)

# set rgb with no alpha
stroke(1, 0, 0)
# draw a rect
rect(610, 10, 180, 980)

# set rgb with an alpha value
stroke(1, 0, 0, .5)
# draw a rect
rect(810, 10, 180, 980)

CMYK Fill

Set a fill before drawing a shape. A cmyk color used while exporting to a .pdf or an image. Handy if the file is used for print.

cmykFill(c, m=None, y=None, k=None, alpha=1)

Set a fill using a CMYK color before drawing a shape. This is handy if the file is intended for print.

Sets the CMYK fill color. Each value must be a float between 0.0 and 1.0.

# cyan
cmykFill(1, 0, 0, 0)
rect(0, 0, 250, 1000)
# magenta
cmykFill(0, 1, 0, 0)
rect(250, 0, 250, 1000)
# yellow
cmykFill(0, 0, 1, 0)
rect(500, 0, 250, 1000)
# black
cmykFill(0, 0, 0, 1)
rect(750, 0, 250, 1000)
cmykLinearGradient(startPoint=None, endPoint=None, colors=None, locations=None)

A cmyk linear gradient fill with:

  • startPoint as (x, y)
  • endPoint as (x, y)
  • colors as a list of colors, described similary as cmykFill
  • locations of each color as a list of floats. (optionally)

Setting a gradient will ignore the fill.

# set a gradient as the fill color
cmykLinearGradient(
    (100, 100),                                  # startPoint
    (800, 800),                                  # endPoint
    [(1, 0, 0, 0), (0, 0, 1, 0), (0, 1, 0, 0)],  # colors
    [0, .2, 1]                                   # locations
    )
# draw a rectangle
rect(10, 10, 980, 980)
cmykRadialGradient(startPoint=None, endPoint=None, colors=None, locations=None, startRadius=0, endRadius=100)

A cmyk radial gradient fill with:

  • startPoint as (x, y)
  • endPoint as (x, y)
  • colors as a list of colors, described similary as cmykFill
  • locations of each color as a list of floats. (optionally)
  • startRadius radius around the startPoint in degrees (optionally)
  • endRadius radius around the endPoint in degrees (optionally)

Setting a gradient will ignore the fill.

# set a gradient as the fill color
cmykRadialGradient(
    (300, 300),                                     # startPoint
    (600, 600),                                     # endPoint
    [(1, 0, 0, 1), (0, 0, 1, 0), (0, 1, 0, .2)],    # colors
    [0, .2, 1],                                     # locations
    0,                                              # startRadius
    500                                             # endRadius
    )
# draw a rectangle
rect(10, 10, 980, 980)
cmykShadow(offset, blur=None, color=None)

Adds a cmyk shadow with an offset (x, y), blur and a color. The color argument must be a tuple similarly as cmykFill.

# a cyan with some blur and a offset
cmykShadow((100, 100), 100, (1, 0, 0, 0))
# draw a rect
rect(100, 100, 600, 600)

CMYK Stroke

Set a stroke before drawing a shape. A cmyk color used while exporting to a .pdf or an image. Handy if the file is used for print.

cmykStroke(c, m=None, y=None, k=None, alpha=1)

Set a stroke using a CMYK color before drawing a shape. This is handy if the file is intended for print.

Sets the CMYK stroke color. Each value must be a float between 0.0 and 1.0.

# define x, y and the amount of lines needed
x, y = 20, 20
lines = 49
# calculate the smallest step
colorStep = 1.00 / lines
# set stroke width
strokeWidth(10)
# start a loop
for i in range(lines):
    # set a cmyk color
    # the magenta value is calculated
    cmykStroke(0, i * colorStep, 1, 0)
    # draw a line
    line((x, y), (x, y + 960))
    # translate the canvas
    translate(20, 0)

Color Blend

blendMode(operation)

Set a blend mode.

Available operations are: normal, multiply, screen, overlay, darken, lighten, colorDodge, colorBurn, softLight, hardLight, difference, exclusion, hue, saturation, color, luminosity, clear, copy, sourceIn, sourceOut, sourceAtop, destinationOver, destinationIn, destinationOut, destinationAtop, xOR, plusDarker and plusLighter,

# set a blend mode
blendMode("multiply")
# set a color
cmykFill(1, 0, 0, 0)
# draw a rectangle
rect(10, 10, 600, 600)
# set an other color
cmykFill(0, 1, 0, 0)
# overlap a second rectangle
rect(390, 390, 600, 600)

Color Spaces

Set a colorSpace before setting a color. Color spaces are only aviable for RGB colors.

colorSpace(colorSpace)

Set the color space. Options are genericRGB, adobeRGB1998, sRGB, genericGray, genericGamma22Gray. The default is genericRGB. None will reset it back to the default.

# set a color
r, g, b, a = 0.74, 0.51, 1.04, 1

# get all available color spaces
colorSpaces = listColorSpaces()

x = 0
w = width() / len(colorSpaces)

# start loop
for space in colorSpaces:

    # set a color space
    colorSpace(space)
    # set the color
    fill(r, g, b)
    # draw a rect
    rect(x, 0, w, height())
    x += w
listColorSpaces()

Return a list of all available color spaces.

Canvas

The canvas is the thing DrawBot draws on. It’s the document size, the art board. It has a height and a width which can be set. The dimensions of the canvas are not related to the size of the window.

Pages

The origin of the drawing board is at the bottom left.

newPage(width=None, height=None)

Create a new canvas to draw in. This will act like a page in a pdf or a frame in a mov.

Optionally a width and height argument can be provided to set the size. If not provided the default size will be used.

Alternatively size(‘A4’) with a supported papersizes or size(‘screen’) setting the current screen size as size, can be used.

# loop over a range of 100
for i in range(100):
    # for each loop create a new path
    newPage(500, 500)
    # set a random fill color
    fill(random(), random(), random())
    # draw a rect with the size of the page
    rect(0, 0, width(), height())

All supported papersizes: 10x14, 10x14Landscape, A0, A0Landscape, A1, A1Landscape, A2, A2Landscape, A3, A3Landscape, A4, A4Landscape, A4Small, A4SmallLandscape, A5, A5Landscape, B4, B4Landscape, B5, B5Landscape, Executive, ExecutiveLandscape, Folio, FolioLandscape, Ledger, LedgerLandscape, Legal, LegalLandscape, Letter, LetterLandscape, LetterSmall, LetterSmallLandscape, Quarto, QuartoLandscape, Statement, StatementLandscape, Tabloid, TabloidLandscape.

newDrawing()

Reset the drawing stack to the clean and empty stack.

# draw a rectangle
rect(10, 10, width()-20, height()-20)
# save it as a pdf
saveImage("~/Desktop/aRect.pdf")

# reset the drawing stack to a clear and empty stack
newDrawing()

# draw an oval
oval(10, 10, width()-20, height()-20)
# save it as a pdf
saveImage("~/Desktop/anOval.pdf")
endDrawing()

Explicitly tell drawBot the drawing is done. This is advised when using drawBot as a standalone module.

Size
size(width, height=None)

Set the width and height of the canvas. Without calling size() the default drawing board is 1000 by 1000 points.

Alternatively size(‘A4’) with a supported papersizes or size(‘screen’) setting the current screen size as size, can be used.

Afterwards the functions width() and height() can be used for calculations.

You have to use size() before any drawing-related code, and you can’t use size() in a multi-page document. Use newPage(w, h) to set the correct dimensions for each page.

# set a canvas size
size(200, 200)
# print out the size of the page
print((width(), height()))

# set a color
fill(1, 0, 0)
# use those variables to set a background color
rect(0, 0, width(), height())

All supported papersizes: 10x14, 10x14Landscape, A0, A0Landscape, A1, A1Landscape, A2, A2Landscape, A3, A3Landscape, A4, A4Landscape, A4Small, A4SmallLandscape, A5, A5Landscape, B4, B4Landscape, B5, B5Landscape, Executive, ExecutiveLandscape, Folio, FolioLandscape, Ledger, LedgerLandscape, Legal, LegalLandscape, Letter, LetterLandscape, LetterSmall, LetterSmallLandscape, Quarto, QuartoLandscape, Statement, StatementLandscape, Tabloid, TabloidLandscape.

sizes(paperSize=None)

Returns the width and height of a specified canvas size. If no canvas size is given it will return the dictionary containing all possible page sizes.

Page Attributes
width()

Returns the width of the current page.

height()

Returns the height of the current page.

pageCount()

Returns the current page count.

pages()

Return all pages.

# set a size
size(200, 200)
# draw a rectangle
rect(10, 10, 100, 100)
# create a new page
newPage(200, 300)
# set a color
fill(1, 0, 1)
# draw a rectangle
rect(10, 10, 100, 100)
# create a new page
newPage(200, 200)
# set a color
fill(0, 1, 0)
# draw a rectangle
rect(10, 10, 100, 100)

# get all pages
allPages = pages()
# count how many pages are available
print(len(allPages))

# use the `with` statement
# to set a page as current context
with allPages[1]:
    # draw into the selected page
    fontSize(30)
    text("Hello World", (10, 150))

# loop over allpages
for page in allPages:
    # set the page as current context
    with page:
        # draw an oval in each of them
        oval(110, 10, 30, 30)
frameDuration(seconds)

When exporting to mov or gif each frame can have duration set in seconds.

# setting some variables
# size of the pages / frames
w, h = 200, 200
# frame per seconds
fps = 30
# duration of the movie
seconds = 3
# calculate the lenght of a single frame
duration = 1 / fps
# calculate the amount of frames needed
totalFrames = seconds * fps

# title page
newPage(w, h)
# set frame duration to 1 second
frameDuration(1)
# pick a font and font size
font("Helvetica", 40)
# draw the title text in a box
textBox("Rotated square", (0, 0, w, h * .8), align="center")

# loop over the amount of frames needed
for i in range(totalFrames):
    # create a new page
    newPage(w, h)
    # set the frame duration
    frameDuration(duration)
    # set a fill color
    fill(1, 0, 0)
    # translate to the center of the page
    translate(w / 2, h / 2)
    # rotate around the center
    rotate(i*10)
    # draw the rect
    rect(-50, -50, 50, 50)

# save the image as a mov on the desktop
saveImage('~/Desktop/frameDuration.gif')
linkURL(url, (x, y, w, h))

Add a clickable rectangle for an external url link.

The link rectangle will be set independent of the current context transformations.

linkRect(name, (x, y, w, h))

Add a clickable rectangle for a link within a PDF. Use linkDestination(name, (x, y)) with the same name to set the destination of the clickable rectangle.

The link rectangle will be set independent of the current context transformations.

# a variable with the amount of pages we want
totalPages = 10
# create the first page with a index
newPage()
# set a font size
fontSize(30)
# start a loop over all wanted pages
for i in range(totalPages):
    # set a random fill color
    fill(random(), random(), random())
    # draw a rectangle
    rect(10, 50 * i, 50, 50)
    # add a clickable link rectangle with a unique name
    linkRect(f"beginPage_{i}", (10, 10 + 50 * i, 50, 50))

# start a loop over all wanted pages
for i in range(totalPages):
    # create a new page
    newPage()
    # add a link destination with a given name
    # the name must refer to a linkRect name
    linkDestination(f"beginPage_{i}", (0, 0))
linkDestination(name, (x, y))

Add a destination point for a link within a PDF. Setup a clickable retangle with linkRect(name, (x, y, w, h)) with the same name.

The destination position will be set independent of the current context transformations.

Transformations

translate(x=0, y=0)

Translate the canvas with a given offset.

rotate(angle, center=(0, 0))

Rotate the canvas around the center point (which is the origin by default) with a given angle in degrees.

scale(x=1, y=None, center=(0, 0))

Scale the canvas with a given x (horizontal scale) and y (vertical scale).

If only 1 argument is provided a proportional scale is applied.

The center of scaling can optionally be set via the center keyword argument. By default this is the origin.

skew(angle1, angle2=0, center=(0, 0))

Skew the canvas with given angle1 and angle2.

If only one argument is provided a proportional skew is applied.

The center of skewing can optionally be set via the center keyword argument. By default this is the origin.

transform((xx, xy, yx, yy, x, y))

Transform the canvas with a transformation matrix.

Managing the Graphics State
savedState()

Save and restore the current graphics state in a with statement.

# Use the 'with' statement.
# This makes any changes you make to the graphics state -- such as
# colors and transformations -- temporary, and will be reset to
# the previous state at the end of the 'with' block.
with savedState():
    # set a color
    fill(1, 0, 0)
    # do a transformation
    translate(450, 50)
    rotate(45)
    # draw something
    rect(0, 0, 700, 600)
# already returned to the previously saved graphics state
# so this will be a black rectangle
rect(0, 0, 50, 50)
save()

DrawBot strongly recommends to use savedState() in a with statement instead.

Save the current graphics state. This will save the state of the canvas (with all the transformations) but also the state of the colors, strokes…

restore()

DrawBot strongly recommends to use savedState() in a with statement instead.

Restore from a previously saved graphics state. This will restore the state of the canvas (with all the transformations) but also the state of colors, strokes…

Saving

saveImage(paths, **options)

Save or export the canvas to a specified format. The path argument is a single destination path to save the current drawing actions.

The file extension is important because it will determine the format in which the image will be exported.

All supported file extensions: pdf, png, jpg, jpeg, tif, tiff, svg, gif, bmp, mp4, icns, *, PIL, NSImage. (* will print out all actions.)

When exporting an animation or movie, each page represents a frame and the framerate is set by calling frameDuration() after each newPage().

# set the canvas size
size(150, 100)

# draw a background
rect(10, 10, width()-20, height()-20)

# set a fill
fill(1)
# draw some text
text("Hello World!", (20, 40))
# save it as a png and pdf on the current users desktop
saveImage("~/Desktop/firstImage.png")
saveImage("~/Desktop/firstImage.pdf")

saveImage() options can be set by adding keyword arguments. Which options are recognized depends on the output format.

pdf options:

  • multipage: If False, only the last page in the document will be saved into the output PDF. This value is ignored if it is None (default).

png options:

  • imageResolution: The resolution of the output image in PPI. Default is 72.
  • antiAliasing: Indicate if a the image should be rendedered with anti-aliasing. Default is True.
  • multipage: Output a numbered image for each page or frame in the document.
  • imagePNGGamma: The gamma value for the image. It is a floating-point number between 0.0 and 1.0, with 0.0 being black and 1.0 being the maximum color.
  • imagePNGInterlaced: Boolean value that indicates whether the image should be interlaced.
  • imageColorSyncProfileData: A bytes or NSData object containing the ColorSync profile data.

jpg, jpeg options:

  • imageResolution: The resolution of the output image in PPI. Default is 72.
  • antiAliasing: Indicate if a the image should be rendedered with anti-aliasing. Default is True.
  • multipage: Output a numbered image for each page or frame in the document.
  • imageJPEGCompressionFactor: A float between 0.0 and 1.0, with 1.0 resulting in no compression and 0.0 resulting in the maximum compression possible
  • imageJPEGProgressive: Boolean that indicates whether the image should use progressive encoding.
  • imageFallbackBackgroundColor: The background color to use when writing to an image format (such as JPEG) that doesn’t support alpha. The color’s alpha value is ignored. The default background color, when this property is not specified, is white. The value of the property should be an NSColor object or a DrawBot RGB color tuple.
  • imageColorSyncProfileData: A bytes or NSData object containing the ColorSync profile data.

tif, tiff options:

  • imageResolution: The resolution of the output image in PPI. Default is 72.
  • antiAliasing: Indicate if a the image should be rendedered with anti-aliasing. Default is True.
  • multipage: Output a numbered image for each page or frame in the document.
  • imageTIFFCompressionMethod: None, or ‘lzw’ or ‘packbits’, or an NSTIFFCompression constant
  • imageColorSyncProfileData: A bytes or NSData object containing the ColorSync profile data.

svg options:

  • multipage: Output a numbered svg file for each page or frame in the document.

gif options:

  • imageResolution: The resolution of the output image in PPI. Default is 72.
  • antiAliasing: Indicate if a the image should be rendedered with anti-aliasing. Default is True.
  • multipage: Output a numbered image for each page or frame in the document.
  • imageGIFDitherTransparency: Boolean that indicates whether the image is dithered
  • imageGIFRGBColorTable: A bytes or NSData object containing the RGB color table.
  • imageColorSyncProfileData: A bytes or NSData object containing the ColorSync profile data.
  • imageGIFLoop: Boolean that indicates whether the animated gif should loop

bmp options:

  • imageResolution: The resolution of the output image in PPI. Default is 72.
  • antiAliasing: Indicate if a the image should be rendedered with anti-aliasing. Default is True.
  • multipage: Output a numbered image for each page or frame in the document.

mp4 options:

  • ffmpegCodec: The codec to be used by ffmpeg. By default it is ‘libx264’ (for H.264). The ‘mpeg4’ codec gives better results when importing the movie into After Effects, at the expense of a larger file size.
  • imageResolution: The resolution of the output image in PPI. Default is 72.
  • antiAliasing: Indicate if a the image should be rendedered with anti-aliasing. Default is True.
  • imagePNGGamma: The gamma value for the image. It is a floating-point number between 0.0 and 1.0, with 0.0 being black and 1.0 being the maximum color.
  • imagePNGInterlaced: Boolean value that indicates whether the image should be interlaced.
  • imageColorSyncProfileData: A bytes or NSData object containing the ColorSync profile data.

icns options:

  • imageResolution: The resolution of the output image in PPI. Default is 72.
  • antiAliasing: Indicate if a the image should be rendedered with anti-aliasing. Default is True.
  • multipage: Output a numbered image for each page or frame in the document.

PIL options:

  • imageResolution: The resolution of the output image in PPI. Default is 72.
  • antiAliasing: Indicate if a the image should be rendedered with anti-aliasing. Default is True.
  • multipage: Output a numbered image for each page or frame in the document.

NSImage options:

  • imageResolution: The resolution of the output image in PPI. Default is 72.
  • antiAliasing: Indicate if a the image should be rendedered with anti-aliasing. Default is True.
  • multipage: Output a numbered image for each page or frame in the document.
# same example but we just change the image resolution
size(150, 100)
rect(10, 10, width()-20, height()-20)
fill(1)
text("Hello World!", (20, 40))
# save it with an option that controls the resolution (300 PPI)
saveImage("~/Desktop/firstImage300.png", imageResolution=300)
printImage(pdf=None)

Export the canvas to a printing dialog, ready to print.

Optionally a pdf object can be provided.

# set A4 page size
size(595, 842)
# draw something
oval(0, 0, width(), height())
# send it to the printer
printImage()
pdfImage()

Return the image as a pdf document object.

Text

Drawing Text

text(txt, (x, y), align=None)

Draw a text at a provided position.

Optionally an alignment can be set. Possible align values are: “left”, “center” and “right”.

The default alignment is left.

Optionally txt can be a FormattedString.

# set a font and font size
font("Times-Italic", 200)
# draw text
text("hallo", (200, 600))
text("I'm Times", (100, 300))
textBox(txt, box, align=None)

Draw a text in a provided rectangle.

A box could be a (x, y, w, h) or a bezierPath object.

Optionally an alignment can be set. Possible align values are: “left”, “center”, “right” and “justified”.

If the text overflows the rectangle, the overflowed text is returned.

The default alignment is left.

# a box has an x, y, width and height
x, y, w, h = 100, 100, 800, 800
# set a fill
fill(1, 0, 0)
# draw a rectangle with variables from above
rect(x, y, w, h)
# set a diferent fill
fill(1)
# set a font size
fontSize(200)
# draw text in a text box
# with varibales from above
overflow = textBox("hallo, this text is a bit to long",
                (x, y, w, h), align="center")
# a text box returns text overflow
# text that did not make it into the box
print(overflow)

The returned overflow can be used to add new pages until all text is set:

t = '''DrawBot is a powerful, free application for MacOSX that invites you to write simple Python scripts to generate two-dimensional graphics. The builtin graphics primitives support rectangles, ovals, (bezier) paths, polygons, text objects and transparency.
DrawBot is an ideal tool to teach the basics of programming. Students get colorful graphic treats while getting familiar with variables, conditional statements, functions and what have you. Results can be saved in a selection of different file formats, including as high resolution, scaleable PDF.
DrawBot has proven itself as part of the curriculum at selected courses at the Royal Academy in The Hague.'''

# setting some variables
# setting the size
x, y, w, h = 10, 10, 480, 480

# setting the color change over different frames
coloradd = .1

# setting the start background color only red and blue
r = .3
b = 1

# start a loop and run as long there is t variable has some text
while len(t):
    # create a new page
    newPage(500, 500)
    # set a frame duration
    frameDuration(3)
    # set the background fill
    fill(r, 0, b)
    # draw the background
    rect(x, y, w, h)
    # set a fill color
    fill(0)
    # set a font with a size
    font("DrawBot-Bold", randint(50, 100))
    # pick some random colors
    rr = random()
    gg = random()
    bb = random()
    # set a gradient as fill
    radialGradient((250, 250), (250, 250), [(rr, gg, bb), (1-rr, 1-gg, 1-bb)], startRadius=0, endRadius=250)

    # draw the text in a box with the gradient fill
    t = textBox(t, (x, y, w, h))

    # setting the color for the next frame
    r += coloradd
    b -= coloradd

    # set a font
    font("DrawBot-Bold", 20)
    # get the page count text size as a (width, height) tuple
    tw, th = textSize("%s" % pageCount())
    # draw the text
    textBox("%s" % pageCount(), (10, 10, 480, th), align="center")

saveImage("~/Desktop/drawbot.mp4")

Another example, this time using a bezierPath as a text envelope:

# create a fresh bezier path
path = BezierPath()
# draw some text
# the text will be converted to curves
path.text("a", font="Helvetica-Bold", fontSize=500)
# set an indent
indent = 50
# calculate the width and height of the path
minx, miny, maxx, maxy = path.bounds()
w = maxx - minx
h = maxy - miny
# calculate the box where we want to draw the path in
boxWidth = width() - indent * 2
boxHeight = height() - indent * 2
# calculate a scale based on the given path bounds and the box
s = min([boxWidth / float(w), boxHeight / float(h)])
# translate to the middle
translate(width()*.5, height()*.5)
# set the scale
scale(s)
# translate the negative offset, letter could have overshoot
translate(-minx, -miny)
# translate with half of the width and height of the path
translate(-w*.5, -h*.5)
# draw the path
drawPath(path)
# set a font
font("Helvetica-Light")
# set a font size
fontSize(5)
# set white as color
fill(1)
# draw some text in the path
textBox("abcdefghijklmnopqrstuvwxyz"*30000, path)
Helpers
textSize(txt, align=None, width=None, height=None)

Returns the size of a text with the current settings, like font, fontSize and lineHeight as a tuple (width, height).

Optionally a width constrain or height constrain can be provided to calculate the lenght or width of text with the given constrain.

textOverflow(txt, box, align=None)

Returns the overflowed text without drawing the text.

A box could be a (x, y, w, h) or a bezierPath object.

Optionally an alignment can be set. Possible align values are: “left”, “center”, “right” and “justified”.

The default alignment is left.

Optionally txt can be a FormattedString. Optionally box can be a BezierPath.

textBoxBaselines(txt, box, align=None)

Returns a list of x, y coordinates indicating the start of each line for a given text in a given box.

A box could be a (x, y, w, h) or a bezierPath object.

Optionally an alignment can be set. Possible align values are: “left”, “center”, “right” and “justified”.

textBoxCharacterBounds(txt, box, align=None)

Returns a list of typesetted bounding boxes ((x, y, w, h), baseLineOffset, formattedSubString).

A box could be a (x, y, w, h) or a bezierPath object.

Optionally an alignment can be set. Possible align values are: “left”, “center”, “right” and “justified”.

installedFonts(supportsCharacters=None)

Returns a list of all installed fonts.

Optionally a string with supportsCharacters can be provided, the list of available installed fonts will be filtered by support of these characters,

installFont(path)

Install a font with a given path and the postscript font name will be returned. The postscript font name can be used to set the font as the active font.

Fonts are installed only for the current process. Fonts will not be accesible outside the scope of drawBot.

All installed fonts will automatically be uninstalled when the script is done.

# set the path to a font file
path = "path/to/font/file.otf"
# install the font
fontName = installFont(path)
# set the font
font(fontName, 200)
# draw some text
text("Hello World", (10, 10))
# uninstall font
uninstallFont(path)

This function has been deprecated: please use the font path directly in all places that accept a font name.

uninstallFont(path)

Uninstall a font with a given path.

This function has been deprecated: please use the font path directly in all places that accept a font name.

Text Properties

font(fontNameOrPath, fontSize=None, fontNumber=0)

Set a font with the name of the font. If a font path is given the font will be installed and used directly. Optionally a fontSize can be set directly. The default font, also used as fallback font, is ‘LucidaGrande’. The default fontSize is 10pt.

The name of the font relates to the font’s postscript name.

The font name is returned, which is handy when the font was loaded from a path.

font("Times-Italic")
fontSize(fontSize)

Set the font size in points. The default fontSize is 10pt.

fontSize(30)
fallbackFont(fontNameOrPath, fontNumber=0)

Set a fallback font, this is used whenever a glyph is not available in the current font.

fallbackFont("Times")
underline(value)

Set the underline value. Underline must be single, thick, double or None.

underline("single")
fontSize(140)
text("hello underline", (50, 50))
hyphenation(value)

Set hyphenation, True or False.

txt = '''Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.'''
# enable hyphenation
hyphenation(True)
# set font size
fontSize(50)
# draw text in a box
textBox(txt, (100, 100, 800, 800))
lineHeight(value)

Set the line height.

# set line height
lineHeight(150)
# set font size
fontSize(60)
# draw text in a box
textBox("Hello World " * 10, (100, 100, 800, 800))
tracking(value)

Set the tracking between characters. It adds an absolute number of points between the characters.

size(1000, 350)
# set tracking
tracking(100)
# set font size
fontSize(100)
# draw some text
text("hello", (100, 200))
# disable tracking
tracking(None)
# draw some text
text("world", (100, 100))
baselineShift(value)

Set the shift of the baseline.

openTypeFeatures(frac=True, case=True, ...)

Enable OpenType features.

Supported OpenType tags:

c2pc, c2sc, calt, case, cpsp, cswh, dlig, frac, liga, kern, lnum, onum, ordn, pnum, rlig, sinf, smcp, ss01, ss02, ss03, ss04, ss05, ss06, ss07, ss08, ss09, ss10, ss11, ss12, ss13, ss14, ss15, ss16, ss17, ss18, ss19, ss20, subs, sups, swsh, titl, tnum

A resetFeatures argument can be set to True in order to get back to the default state.

newPage(1000, 300)
# set a font
font("Didot")
# set the font size
fontSize(50)
# create a string
someTxt = "aabcde1234567890"
# draw the string
text(someTxt, (100, 220))
# enable some OpenType features
openTypeFeatures(onum=True, smcp=True)
# draw the same string
text(someTxt, (100, 150))
# reset defaults
openTypeFeatures(resetFeatures=True)
# the same string again, back to default features
text(someTxt, (100, 70))
listOpenTypeFeatures(fontNameOrPath=None)

List all OpenType feature tags for the current font.

Optionally a fontNameOrPath can be given. If a font path is given the font will be used directly.

fontVariations(wdth=0.6, wght=0.1, ...)

Pick a variation by axes values.

size(1000, 500)
# pick a font
font("Skia")
# pick a font size
fontSize(200)
# list all axis from the current font
for axis, data in listFontVariations().items():
    print((axis, data))
# pick a variation from the current font
fontVariations(wght=.6)
# draw text!!
text("Hello Q", (100, 100))
# pick a variation from the current font
fontVariations(wght=3, wdth=1.2)
# draw text!!
text("Hello Q", (100, 300))
listFontVariations(fontNameOrPath=None)

List all variation axes for the current font.

Returns a dictionary with all axis tags instance with an info dictionary with the following keys: name, minValue and maxValue. For non variable fonts an empty dictionary is returned.

Optionally a fontNameOrPath can be given. If a font path is given the font will be used directly.

listNamedInstances(fontNameOrPath=None)

List all named instances from a variable font for the current font.

Returns a dictionary with all named instance as postscript names with their location. For non variable fonts an empty dictionary is returned.

Optionally a fontNameOrPath can be given. If a font path is given the font will be used directly.

tabs(*tabs)

Set tabs, tuples of (float, alignment) Aligment can be “left”, “center”, “right” or any other character. If a character is provided the alignment will be right and centered on the specified character.

t = " hello w o r l d"
# replace all spaces by tabs
t = t.replace(" ", "\t")
# set some tabs
tabs((85, "center"), (232, "right"), (300, "left"))
# draw the string
text(t, (10, 10))
# reset all tabs
tabs(None)
# draw the same string
text(t, (10, 50))
language(language)

Set the preferred language as language tag or None to use the default language.

Support is depending on local OS.

language() will activate the locl OpenType features, if supported by the current font.

size(1000, 600)
# a long dutch word
word = "paardenkop"
# a box where we draw in
box = (100, 50, 400, 500)
# set font size
fontSize(118)
# enable hyphenation
hyphenation(True)
# draw the text with no language set
textBox(word, box)
# set language to dutch (nl)
language("nl")
# shift up a bit
translate(500, 0)
# darw the text again with a language set
textBox(word, box)
Font Properties
fontContainsCharacters(characters)

Return a bool if the current font contains the provided characters. Characters is a string containing one or more characters.

fontContainsGlyph(glyphName)

Return a bool if the current font contains a provided glyph name.

fontFilePath()

Return the path to the file of the current font.

listFontGlyphNames()

Return a list of glyph names supported by the current font.

fontDescender()

Returns the current font descender, based on the current font and fontSize.

fontAscender()

Returns the current font ascender, based on the current font and fontSize.

fontXHeight()

Returns the current font x-height, based on the current font and fontSize.

fontCapHeight()

Returns the current font cap height, based on the current font and fontSize.

fontLeading()

Returns the current font leading, based on the current font and fontSize.

fontLineHeight()

Returns the current line height, based on the current font and fontSize. If a lineHeight is set, this value will be returned.

txt = "Hello World"
x, y = 10, 100

# set a font
font("Helvetica")
# set a font size
fontSize(100)
# draw the text
text(txt, (x, y))

# calculate the size of the text
textWidth, textHeight = textSize(txt)

# set a red stroke color
stroke(1, 0, 0)
# loop over all font metrics
for metric in (0, fontDescender(), fontAscender(), fontXHeight(), fontCapHeight()):
    # draw a red line with the size of the drawn text
    line((x, y+metric), (x+textWidth, y+metric))

Formatted Strings

FormattedString(txt=None, font=None, fontSize=10, fallbackFont=None, fill=(0, 0, 0), cmykFill=None, stroke=None, cmykStroke=None, strokeWidth=1, align=None, lineHeight=None, tracking=None, baselineShift=None, openTypeFeatures=None, tabs=None, language=None, indent=None, tailIndent=None, firstLineIndent=None, paragraphTopSpacing=None, paragraphBottomSpacing=None)

Return a string object that can handle text formatting.

size(1000, 200)
# create a formatted string
txt = FormattedString()

# adding some text with some formatting
txt.append("hello", font="Helvetica", fontSize=100, fill=(1, 0, 0))
# adding more text
txt.append("world", font="Times-Italic", fontSize=50, fill=(0, 1, 0))

# setting a font
txt.font("Helvetica-Bold")
txt.fontSize(75)
txt += "hello again"

# drawing the formatted string
text(txt, (10, 30))


# create a formatted string
txt = FormattedString()

# adding some text with some formatting
txt.append("hello", font="Didot", fontSize=50)
# adding more text with an
txt.append("world", font="Didot", fontSize=50, openTypeFeatures=dict(smcp=True))

text(txt, (10, 150))
class FormattedString(txt=None, **kwargs)

Bases: drawBot.context.baseContext.SVGContextPropertyMixin, drawBot.context.baseContext.ContextPropertyMixin

FormattedString is a reusable object, if you want to draw the same over and over again. FormattedString objects can be drawn with the text(txt, (x, y)) and textBox(txt, (x, y, w, h)) methods.

clear()
append(txt, **kwargs)

Add txt to the formatted string with some additional text formatting attributes:

  • font: the font to be used for the given text, if a font path is given the font will be installed and used directly.
  • fallbackFont: the fallback font
  • fontSize: the font size to be used for the given text
  • fill: the fill color to be used for the given text
  • cmykFill: the cmyk fill color to be used for the given text
  • stroke: the stroke color to be used for the given text
  • cmykStroke: the cmyk stroke color to be used for the given text
  • strokeWidth: the strokeWidth to be used for the given text
  • align: the alignment to be used for the given text
  • lineHeight: the lineHeight to be used for the given text
  • tracking: set tracking for the given text in absolute points
  • baselineShift: set base line shift for the given text
  • openTypeFeatures: enable OpenType features
  • fontVariations: pick a variation by axes values
  • tabs: enable tabs
  • indent: the indent of a paragraph
  • tailIndent: the tail indent of a paragraph
  • firstLineIndent: the first line indent of a paragraph
  • paragraphTopSpacing: the spacing at the top of a paragraph
  • paragraphBottomSpacing: the spacing at the bottom of a paragraph
  • language: the language of the text

All formatting attributes follow the same notation as other similar DrawBot methods. A color is a tuple of (r, g, b, alpha), and a cmykColor is a tuple of (c, m, y, k, alpha).

Text can also be added with formattedString += “hello”. It will append the text with the current settings of the formatted string.

font(fontNameOrPath, fontSize=None, fontNumber=0)

Set a font with the name of the font. If a font path is given the font will used directly. Optionally a fontSize can be set directly. The default font, also used as fallback font, is ‘LucidaGrande’. The default fontSize is 10pt.

The name of the font relates to the font’s postscript name.

The font name is returned, which is handy when the font was loaded from a path.

fontNumber(fontNumber)
fallbackFont(fontNameOrPath, fontNumber=0)

Set a fallback font, used whenever a glyph is not available in the normal font. If a font path is given the font will be installed and used directly.

fallbackFontNumber(fontNumber)
fontSize(fontSize)

Set the font size in points. The default fontSize is 10pt.

fill(*fill)

Sets the fill color with a red, green, blue and alpha value. Each argument must a value float between 0 and 1.

stroke(*stroke)

Sets the stroke color with a red, green, blue and alpha value. Each argument must a value float between 0 and 1.

cmykFill(*cmykFill)

Set a fill using a CMYK color before drawing a shape. This is handy if the file is intended for print.

Sets the CMYK fill color. Each value must be a float between 0.0 and 1.0.

cmykStroke(*cmykStroke)

Set a stroke using a CMYK color before drawing a shape. This is handy if the file is intended for print.

Sets the CMYK stroke color. Each value must be a float between 0.0 and 1.0.

strokeWidth(strokeWidth)

Sets stroke width.

align(align)

Sets the text alignment. Possible align values are: left, center and right.

lineHeight(lineHeight)

Set the line height.

tracking(tracking)

Set the tracking between characters. It adds an absolute number of points between the characters.

baselineShift(baselineShift)

Set the shift of the baseline.

underline(underline)

Set the underline value. Underline must be single, thick, double or None.

url(url)

set the url value. url must be a string or None

openTypeFeatures(*args, **features)

Enable OpenType features and return the current openType features settings.

If no arguments are given openTypeFeatures() will just return the current openType features settings.

size(1000, 200)
# create an empty formatted string object
t = FormattedString()
# set a font
t.font("Didot")
# set a font size
t.fontSize(60)
# add some text
t += "0123456789 Hello"
# enable some open type features
t.openTypeFeatures(smcp=True, onum=True)
# add some text
t += " 0123456789 Hello"
# draw the formatted string
text(t, (10, 80))
listOpenTypeFeatures(fontNameOrPath=None, fontNumber=0)

List all OpenType feature tags for the current font.

Optionally a fontNameOrPath can be given. If a font path is given the font will be used directly.

fontVariations(*args, **axes)

Pick a variation by axes values and return the current font variations settings.

If no arguments are given fontVariations() will just return the current font variations settings.

listFontVariations(fontNameOrPath=None, fontNumber=0)

List all variation axes for the current font.

Returns a dictionary with all axis tags instance with an info dictionary with the following keys: name, minValue and maxValue. For non variable fonts an empty dictionary is returned.

Optionally a fontNameOrPath can be given. If a font path is given the font will be used directly.

listNamedInstances(fontNameOrPath=None, fontNumber=0)

List all named instances from a variable font for the current font.

Returns a dictionary with all named instance as postscript names with their location. For non variable fonts an empty dictionary is returned.

Optionally a fontNameOrPath can be given. If a font path is given the font will be used directly.

tabs(*tabs)

Set tabs,tuples of (float, alignment) Aligment can be “left”, “center”, “right” or any other character. If a character is provided the alignment will be right and centered on the specified character.

# create a new formatted string
t = FormattedString()
# set some tabs
t.tabs((85, "center"), (232, "right"), (300, "left"))
# add text with tabs
t += " hello w o r l d".replace(" ", "\t")
# draw the string
text(t, (10, 10))
indent(indent)

Set indent of text left of the paragraph.

# setting up some variables
x, y, w, h = 10, 10, 500, 600

txtIndent = 100
txtFirstLineIndent = 200
txtTailIndent = -100
txtFontSize = 22

paragraphTop = 3
paragraphBottom = 10

txt = '''DrawBot is an ideal tool to teach the basics of programming. Students get colorful graphic treats while getting familiar with variables, conditional statements, functions and what have you. Results can be saved in a selection of different file formats, including as high resolution, scaleable PDF, svg, movie, png, jpeg, tiff...'''

# a new page with preset size
newPage(w+x*2, h+y*2)
# draw text indent line
stroke(1, 0, 0)
line((x+txtIndent, y), (x+txtIndent, y+h))
# draw text firstline indent line
stroke(1, 1, 0)
line((x+txtFirstLineIndent, y), (x+txtFirstLineIndent, y+h))
# draw tail indent
pos = txtTailIndent
# tail indent could be negative
if pos <= 0:
    # substract from width of the text box
    pos = w + pos
stroke(0, 0, 1)
line((x+pos, y), (x+pos, y+h))
# draw a rectangle
fill(0, .1)
stroke(None)
rect(x, y, w, h)

# create a formatted string
t = FormattedString(fontSize=txtFontSize)
# set alignment
t.align("justified")
# add text
t += txt
# add hard return
t += "\n"
# set style for indented text
t.fontSize(txtFontSize*.6)
t.paragraphTopSpacing(paragraphTop)
t.paragraphBottomSpacing(paragraphBottom)
t.firstLineIndent(txtFirstLineIndent)
t.indent(txtIndent)
t.tailIndent(txtTailIndent)
# add text
t += txt
# add hard return
t += "\n"
# reset style
t.fontSize(txtFontSize)
t.indent(None)
t.tailIndent(None)
t.firstLineIndent(None)
t.paragraphTopSpacing(None)
t.paragraphBottomSpacing(None)
# add text
t += txt
# draw formatted string in a text box
textBox(t, (x, y, w, h))
tailIndent(indent)

Set indent of text right of the paragraph.

If positive, this value is the distance from the leading margin. If 0 or negative, it’s the distance from the trailing margin.

firstLineIndent(indent)

Set indent of the text only for the first line.

paragraphTopSpacing(value)

set paragraph spacing at the top.

paragraphBottomSpacing(value)

set paragraph spacing at the bottom.

language(language)

Set the preferred language as language tag or None to use the default language.

language() will activate the locl OpenType features, if supported by the current font.

size()

Return the size of the text.

getNSObject()
copy()

Copy the formatted string.

fontContainsCharacters(characters)

Return a bool if the current font contains the provided characters. Characters is a string containing one or more characters.

fontContainsGlyph(glyphName)
fontFilePath()

Return the path to the file of the current font.

fontFileFontNumber()
listFontGlyphNames()

Return a list of glyph names supported by the current font.

fontAscender()

Returns the current font ascender, based on the current font and fontSize.

fontDescender()

Returns the current font descender, based on the current font and fontSize.

fontXHeight()

Returns the current font x-height, based on the current font and fontSize.

fontCapHeight()

Returns the current font cap height, based on the current font and fontSize.

fontLeading()

Returns the current font leading, based on the current font and fontSize.

fontLineHeight()

Returns the current line height, based on the current font and fontSize. If a lineHeight is set, this value will be returned.

appendGlyph(*glyphNames)

Append a glyph by his glyph name or glyph index using the current font. Multiple glyph names are possible.

size(1300, 400)
# create an empty formatted string object
t = FormattedString()
# set a font
t.font("Menlo-Regular")
# set a font size
t.fontSize(300)
# add some glyphs by glyph name
t.appendGlyph("A", "ampersand", "Eng", "Eng.alt")
# add some glyphs by glyph ID (this depends heavily on the font)
t.appendGlyph(50, 51)
# draw the formatted string
text(t, (100, 100))
svgClass

The svg class, as a string.

svgID

The svg id, as a string.

The svg link, as a string.

Images

Drawing Images

image(path, (x, y), alpha=1, pageNumber=None)

Add an image from a path with an offset and an alpha value. This should accept most common file types like pdf, jpg, png, tiff and gif.

Optionally an alpha can be provided, which is a value between 0 and 1.

Optionally a pageNumber can be provided when the path referes to a multi page pdf file.

# the path can be a path to a file or a url
image("https://d1sz9tkli0lfjq.cloudfront.net/items/1T3x1y372J371p0v1F2Z/drawBot.jpg", (100, 100), alpha=.3)

Image Properties

imageSize(path)

Return the width and height of an image.

print(imageSize("https://d1sz9tkli0lfjq.cloudfront.net/items/1T3x1y372J371p0v1F2Z/drawBot.jpg"))
imagePixelColor(path, (x, y))

Return the color r, g, b, a of an image at a specified x, y possition.

# path to the image
path = u"https://d1sz9tkli0lfjq.cloudfront.net/items/1T3x1y372J371p0v1F2Z/drawBot.jpg"

# get the size of the image
w, h = imageSize(path)

# setup a variable for the font size as for the steps
s = 15

# shift it up a bit
translate(100, 100)

# set a font with a size
font("Helvetica-Bold")
fontSize(s)

# loop over the width of the image
for x in range(0, w, s):
    # loop of the height of the image
    for y in range(0, h, s):
        # get the color
        color = imagePixelColor(path, (x, y))
        if color:
            r, g, b, a = color
            # set the color
            fill(r, g, b, a)
            # draw some text
            text("W", (x, y))
imageResolution(path)

Return the image resolution for a given image.

numberOfPages(path)

Return the number of pages for a given pdf or (animated) gif.

ImageObject

ImageObject(path=None)

Return a Image object, packed with filters. This is a reusable object.

size(550, 300)
# initiate a new image object
im = ImageObject()

# draw in the image
# the 'with' statement will create a custom context
# only drawing in the image object
with im:
    # set a size for the image
    size(200, 200)
    # draw something
    fill(1, 0, 0)
    rect(0, 0, width(), height())
    fill(1)
    fontSize(30)
    text("Hello World", (10, 10))

# draw in the image in the main context
image(im, (10, 50))
# apply some filters
im.gaussianBlur()

# get the offset (with a blur this will be negative)
x, y = im.offset()
# draw in the image in the main context
image(im, (300+x, 50+y))
class ImageObject(path=None)

An image object with support for filters.

Optional a path to an existing image can be provided.

For more info see: Core Image Filter Reference.

size()

Return the size of the image as a tuple.

offset()

Return the offset of the image, the origin point can change due to filters.

clearFilters()

Clear all filters.

open(path)

Open an image with a given path.

copy()

Return a copy.

lockFocus()

Set focus on image.

unlockFocus()

Set unlock focus on image.

boxBlur(radius=None)

Blurs an image using a box-shaped convolution kernel.

Attributes: radius a float.

discBlur(radius=None)

Blurs an image using a disc-shaped convolution kernel.

Attributes: radius a float.

gaussianBlur(radius=None)

Spreads source pixels by an amount specified by a Gaussian distribution.

Attributes: radius a float.

maskedVariableBlur(mask=None, radius=None)

Blurs the source image according to the brightness levels in a mask image.

Attributes: mask an Image object, radius a float.

motionBlur(radius=None, angle=None)

Blurs an image to simulate the effect of using a camera that moves a specified angle and distance while capturing the image.

Attributes: radius a float, angle a float in degrees.

noiseReduction(noiseLevel=None, sharpness=None)

Reduces noise using a threshold value to define what is considered noise.

Attributes: noiseLevel a float, sharpness a float.

zoomBlur(center=None, amount=None)

Simulates the effect of zooming the camera while capturing the image.

Attributes: center a tuple (x, y), amount a float.

colorClamp(minComponents=None, maxComponents=None)

Modifies color values to keep them within a specified range.

Attributes: minComponents a tuple (x, y, w, h), maxComponents a tuple (x, y, w, h).

colorControls(saturation=None, brightness=None, contrast=None)

Adjusts saturation, brightness, and contrast values.

Attributes: saturation a float, brightness a float, contrast a float.

colorMatrix(RVector=None, GVector=None, BVector=None, AVector=None, biasVector=None)

Multiplies source color values and adds a bias factor to each color component.

Attributes: RVector a tuple (x, y, w, h), GVector a tuple (x, y, w, h), BVector a tuple (x, y, w, h), AVector a tuple (x, y, w, h), biasVector a tuple (x, y, w, h).

colorPolynomial(redCoefficients=None, greenCoefficients=None, blueCoefficients=None, alphaCoefficients=None)

Modifies the pixel values in an image by applying a set of cubic polynomials.

Attributes: redCoefficients a tuple (x, y, w, h), greenCoefficients a tuple (x, y, w, h), blueCoefficients a tuple (x, y, w, h), alphaCoefficients a tuple (x, y, w, h).

exposureAdjust(EV=None)

Adjusts the exposure setting for an image similar to the way you control exposure for a camera when you change the F-stop.

Attributes: EV a float.

gammaAdjust(power=None)

Adjusts midtone brightness.

Attributes: power a float.

hueAdjust(angle=None)

Changes the overall hue, or tint, of the source pixels.

Attributes: angle a float in degrees.

linearToSRGBToneCurve()

Maps color intensity from a linear gamma curve to the sRGB color space.

SRGBToneCurveToLinear()

Maps color intensity from the sRGB color space to a linear gamma curve.

temperatureAndTint(neutral=None, targetNeutral=None)

Adapts the reference white point for an image.

Attributes: neutral a tuple, targetNeutral a tuple.

toneCurve(point0=None, point1=None, point2=None, point3=None, point4=None)

Adjusts tone response of the R, G, and B channels of an image.

Attributes: point0 a tuple (x, y), point1 a tuple (x, y), point2 a tuple (x, y), point3 a tuple (x, y), point4 a tuple (x, y).

vibrance(amount=None)

Adjusts the saturation of an image while keeping pleasing skin tones.

Attributes: amount a float.

whitePointAdjust(color=None)

Adjusts the reference white point for an image and maps all colors in the source using the new reference.

Attributes: color RGBA tuple Color (r, g, b, a).

colorCrossPolynomial(redCoefficients=None, greenCoefficients=None, blueCoefficients=None)

Modifies the pixel values in an image by applying a set of polynomial cross-products.

Attributes: redCoefficients a tuple (x, y, w, h), greenCoefficients a tuple (x, y, w, h), blueCoefficients a tuple (x, y, w, h).

colorInvert()

Inverts the colors in an image.

colorMap(gradientImage=None)

Performs a nonlinear transformation of source color values using mapping values provided in a table.

Attributes: gradientImage an Image object.

colorMonochrome(color=None, intensity=None)

Remaps colors so they fall within shades of a single color.

Attributes: color RGBA tuple Color (r, g, b, a), intensity a float.

colorPosterize(levels=None)

Remaps red, green, and blue color components to the number of brightness values you specify for each color component.

Attributes: levels a float.

falseColor(color0=None, color1=None)

Maps luminance to a color ramp of two colors.

Attributes: color0 RGBA tuple Color (r, g, b, a), color1 RGBA tuple Color (r, g, b, a).

maskToAlpha()

Converts a grayscale image to a white image that is masked by alpha.

maximumComponent()

Returns a grayscale image from max(r,g,b).

minimumComponent()

Returns a grayscale image from min(r,g,b).

photoEffectChrome()

Applies a preconfigured set of effects that imitate vintage photography film with exaggerated color.

photoEffectFade()

Applies a preconfigured set of effects that imitate vintage photography film with diminished color.

photoEffectInstant()

Applies a preconfigured set of effects that imitate vintage photography film with distorted colors.

photoEffectMono()

Applies a preconfigured set of effects that imitate black-and-white photography film with low contrast.

photoEffectNoir()

Applies a preconfigured set of effects that imitate black-and-white photography film with exaggerated contrast.

photoEffectProcess()

Applies a preconfigured set of effects that imitate vintage photography film with emphasized cool colors.

photoEffectTonal()

Applies a preconfigured set of effects that imitate black-and-white photography film without significantly altering contrast.

photoEffectTransfer()

Applies a preconfigured set of effects that imitate vintage photography film with emphasized warm colors.

sepiaTone(intensity=None)

Maps the colors of an image to various shades of brown.

Attributes: intensity a float.

vignette(radius=None, intensity=None)

Reduces the brightness of an image at the periphery.

Attributes: radius a float, intensity a float.

vignetteEffect(center=None, intensity=None, radius=None)

Modifies the brightness of an image around the periphery of a specified region.

Attributes: center a tuple (x, y), intensity a float, radius a float.

additionCompositing(backgroundImage=None)

Adds color components to achieve a brightening effect.

Attributes: backgroundImage an Image object.

colorBlendMode(backgroundImage=None)

Uses the luminance values of the background with the hue and saturation values of the source image.

Attributes: backgroundImage an Image object.

colorBurnBlendMode(backgroundImage=None)

Darkens the background image samples to reflect the source image samples.

Attributes: backgroundImage an Image object.

colorDodgeBlendMode(backgroundImage=None)

Brightens the background image samples to reflect the source image samples.

Attributes: backgroundImage an Image object.

darkenBlendMode(backgroundImage=None)

Creates composite image samples by choosing the darker samples (from either the source image or the background).

Attributes: backgroundImage an Image object.

differenceBlendMode(backgroundImage=None)

Subtracts either the source image sample color from the background image sample color, or the reverse, depending on which sample has the greater brightness value.

Attributes: backgroundImage an Image object.

divideBlendMode(backgroundImage=None)

Divides the background image sample color from the source image sample color.

Attributes: backgroundImage an Image object.

exclusionBlendMode(backgroundImage=None)

Produces an effect similar to that produced by the differenceBlendMode filter but with lower contrast.

Attributes: backgroundImage an Image object.

hardLightBlendMode(backgroundImage=None)

Either multiplies or screens colors, depending on the source image sample color.

Attributes: backgroundImage an Image object.

hueBlendMode(backgroundImage=None)

Uses the luminance and saturation values of the background image with the hue of the input image.

Attributes: backgroundImage an Image object.

lightenBlendMode(backgroundImage=None)

Creates composite image samples by choosing the lighter samples (either from the source image or the background).

Attributes: backgroundImage an Image object.

linearBurnBlendMode(backgroundImage=None)

Darkens the background image samples to reflect the source image samples while also increasing contrast.

Attributes: backgroundImage an Image object.

linearDodgeBlendMode(backgroundImage=None)

Brightens the background image samples to reflect the source image samples while also increasing contrast.

Attributes: backgroundImage an Image object.

luminosityBlendMode(backgroundImage=None)

Uses the hue and saturation of the background image with the luminance of the input image.

Attributes: backgroundImage an Image object.

maximumCompositing(backgroundImage=None)

Computes the maximum value, by color component, of two input images and creates an output image using the maximum values.

Attributes: backgroundImage an Image object.

minimumCompositing(backgroundImage=None)

Computes the minimum value, by color component, of two input images and creates an output image using the minimum values.

Attributes: backgroundImage an Image object.

multiplyBlendMode(backgroundImage=None)

Multiplies the input image samples with the background image samples.

Attributes: backgroundImage an Image object.

multiplyCompositing(backgroundImage=None)

Multiplies the color component of two input images and creates an output image using the multiplied values.

Attributes: backgroundImage an Image object.

overlayBlendMode(backgroundImage=None)

Either multiplies or screens the input image samples with the background image samples, depending on the background color.

Attributes: backgroundImage an Image object.

pinLightBlendMode(backgroundImage=None)

Conditionally replaces background image samples with source image samples depending on the brightness of the source image samples.

Attributes: backgroundImage an Image object.

saturationBlendMode(backgroundImage=None)

Uses the luminance and hue values of the background image with the saturation of the input image.

Attributes: backgroundImage an Image object.

screenBlendMode(backgroundImage=None)

Multiplies the inverse of the input image samples with the inverse of the background image samples.

Attributes: backgroundImage an Image object.

softLightBlendMode(backgroundImage=None)

Either darkens or lightens colors, depending on the input image sample color.

Attributes: backgroundImage an Image object.

sourceAtopCompositing(backgroundImage=None)

Places the input image over the background image, then uses the luminance of the background image to determine what to show.

Attributes: backgroundImage an Image object.

sourceInCompositing(backgroundImage=None)

Uses the background image to define what to leave in the input image, effectively cropping the input image.

Attributes: backgroundImage an Image object.

sourceOutCompositing(backgroundImage=None)

Uses the background image to define what to take out of the input image.

Attributes: backgroundImage an Image object.

sourceOverCompositing(backgroundImage=None)

Places the input image over the input background image.

Attributes: backgroundImage an Image object.

subtractBlendMode(backgroundImage=None)

Subtracts the background image sample color from the source image sample color.

Attributes: backgroundImage an Image object.

bumpDistortion(center=None, radius=None, scale=None)

Creates a bump that originates at a specified point in the image.

Attributes: center a tuple (x, y), radius a float, scale a float.

bumpDistortionLinear(center=None, radius=None, angle=None, scale=None)

Creates a concave or convex distortion that originates from a line in the image.

Attributes: center a tuple (x, y), radius a float, angle a float in degrees, scale a float.

circleSplashDistortion(center=None, radius=None)

Distorts the pixels starting at the circumference of a circle and emanating outward.

Attributes: center a tuple (x, y), radius a float.

circularWrap(center=None, radius=None, angle=None)

Wraps an image around a transparent circle.

Attributes: center a tuple (x, y), radius a float, angle a float in degrees.

droste(insetPoint0=None, insetPoint1=None, strands=None, periodicity=None, rotation=None, zoom=None)

Recursively draws a portion of an image in imitation of an M. C. Escher drawing.

Attributes: insetPoint0 a tuple (x, y), insetPoint1 a tuple (x, y), strands a float, periodicity a float, rotation a float, zoom a float.

displacementDistortion(displacementImage=None, scale=None)

Applies the grayscale values of the second image to the first image.

Attributes: displacementImage an Image object, scale a float.

glassDistortion(texture=None, center=None, scale=None)

Distorts an image by applying a glass-like texture.

Attributes: texture an Image object, center a tuple (x, y), scale a float.

glassLozenge(point0=None, point1=None, radius=None, refraction=None)

Creates a lozenge-shaped lens and distorts the portion of the image over which the lens is placed.

Attributes: point0 a tuple (x, y), point1 a tuple (x, y), radius a float, refraction a float.

holeDistortion(center=None, radius=None)

Creates a circular area that pushes the image pixels outward, distorting those pixels closest to the circle the most.

Attributes: center a tuple (x, y), radius a float.

pinchDistortion(center=None, radius=None, scale=None)

Creates a rectangular area that pinches source pixels inward, distorting those pixels closest to the rectangle the most.

Attributes: center a tuple (x, y), radius a float, scale a float.

stretchCrop(size=None, cropAmount=None, centerStretchAmount=None)

Distorts an image by stretching and or cropping it to fit a target size.

Attributes: size, cropAmount a float, centerStretchAmount a float.

torusLensDistortion(center=None, radius=None, width=None, refraction=None)

Creates a torus-shaped lens and distorts the portion of the image over which the lens is placed.

Attributes: center a tuple (x, y), radius a float, width a float, refraction a float.

twirlDistortion(center=None, radius=None, angle=None)

Rotates pixels around a point to give a twirling effect.

Attributes: center a tuple (x, y), radius a float, angle a float in degrees.

vortexDistortion(center=None, radius=None, angle=None)

Rotates pixels around a point to simulate a vortex.

Attributes: center a tuple (x, y), radius a float, angle a float in degrees.

aztecCodeGenerator(size=None, message=None, correctionLevel=None, layers=None, compactStyle=None)

Generates an Aztec code (two-dimensional barcode) from input data.

Attributes: message as bytes, correctionLevel a float, layers a float, compactStyle a bool.

QRCodeGenerator(size=None, message=None, correctionLevel=None)

Generates a Quick Response code (two-dimensional barcode) from input data.

Attributes: message as bytes, correctionLevel a single letter string, options are: ‘L’ (7%), ‘M’ (15%), ‘Q’ (25%) or ‘H’ (30%).

code128BarcodeGenerator(size=None, message=None, quietSpace=None)

Generates a Code 128 one-dimensional barcode from input data.

Attributes: message a bytes, quietSpace a float.

checkerboardGenerator(size, center=None, color0=None, color1=None, width=None, sharpness=None)

Generates a checkerboard pattern.

Attributes: center a tuple (x, y), color0 RGBA tuple Color (r, g, b, a), color1 RGBA tuple Color (r, g, b, a), width a float, sharpness a float.

constantColorGenerator(size, color=None)

Generates a solid color.

Attributes: color RGBA tuple Color (r, g, b, a).

lenticularHaloGenerator(size=None, center=None, color=None, haloRadius=None, haloWidth=None, haloOverlap=None, striationStrength=None, striationContrast=None, time=None)

Simulates a lens flare.

Attributes: center a tuple (x, y), color RGBA tuple Color (r, g, b, a), haloRadius a float, haloWidth a float, haloOverlap a float, striationStrength a float, striationContrast a float, time a float.

PDF417BarcodeGenerator(size=None, message=None, minWidth=None, maxWidth=None, minHeight=None, maxHeight=None, dataColumns=None, rows=None, preferredAspectRatio=None, compactionMode=None, compactStyle=None, correctionLevel=None, alwaysSpecifyCompaction=None)

Generates a PDF417 code (two-dimensional barcode) from input data.

Attributes: message a string, minWidth a float, maxWidth a float, minHeight a float, maxHeight a float, dataColumns a float, rows a float, preferredAspectRatio a float, compactionMode a float, compactStyle a bool, correctionLevel a float, alwaysSpecifyCompaction a bool.

randomGenerator(size)

Generates an image of infinite extent whose pixel values are made up of four independent, uniformly-distributed random numbers in the 0 to 1 range.

starShineGenerator(size, center=None, color=None, radius=None, crossScale=None, crossAngle=None, crossOpacity=None, crossWidth=None, epsilon=None)

Generates a starburst pattern that is similar to a supernova; can be used to simulate a lens flare.

Attributes: center a tuple (x, y), color RGBA tuple Color (r, g, b, a), radius a float, crossScale a float, crossAngle a float in degrees, crossOpacity a float, crossWidth a float, epsilon a float.

stripesGenerator(size, center=None, color0=None, color1=None, width=None, sharpness=None)

Generates a stripe pattern.

Attributes: center a tuple (x, y), color0 RGBA tuple Color (r, g, b, a), color1 RGBA tuple Color (r, g, b, a), width a float, sharpness a float.

sunbeamsGenerator(size=None, center=None, color=None, sunRadius=None, maxStriationRadius=None, striationStrength=None, striationContrast=None, time=None)

Generates a sun effect.

Attributes: center a tuple (x, y), color RGBA tuple Color (r, g, b, a), sunRadius a float, maxStriationRadius a float, striationStrength a float, striationContrast a float, time a float.

crop(rectangle=None)

Applies a crop to an image.

Attributes: rectangle a tuple (x, y, w, h).

lanczosScaleTransform(scale=None, aspectRatio=None)

Produces a high-quality, scaled version of a source image.

Attributes: scale a float, aspectRatio a float.

perspectiveCorrection(topLeft=None, topRight=None, bottomRight=None, bottomLeft=None)

Applies a perspective correction, transforming an arbitrary quadrilateral region in the source image to a rectangular output image.

Attributes: topLeft a tuple (x, y), topRight a tuple (x, y), bottomRight a tuple (x, y), bottomLeft a tuple (x, y).

perspectiveTransform(topLeft=None, topRight=None, bottomRight=None, bottomLeft=None)

Alters the geometry of an image to simulate the observer changing viewing position.

Attributes: topLeft a tuple (x, y), topRight a tuple (x, y), bottomRight a tuple (x, y), bottomLeft a tuple (x, y).

straightenFilter(angle=None)

Rotates the source image by the specified angle in radians.

Attributes: angle a float in degrees.

gaussianGradient(size, center=None, color0=None, color1=None, radius=None)

Generates a gradient that varies from one color to another using a Gaussian distribution.

Attributes: center a tuple (x, y), color0 RGBA tuple Color (r, g, b, a), color1 RGBA tuple Color (r, g, b, a), radius a float.

linearGradient(size, point0=None, point1=None, color0=None, color1=None)

Generates a gradient that varies along a linear axis between two defined endpoints.

Attributes: point0 a tuple (x, y), point1 a tuple (x, y), color0 RGBA tuple Color (r, g, b, a), color1 RGBA tuple Color (r, g, b, a).

radialGradient(size, center=None, radius0=None, radius1=None, color0=None, color1=None)

Generates a gradient that varies radially between two circles having the same center.

Attributes: center a tuple (x, y), radius0 a float, radius1 a float, color0 RGBA tuple Color (r, g, b, a), color1 RGBA tuple Color (r, g, b, a).

circularScreen(center=None, width=None, sharpness=None)

Simulates a circular-shaped halftone screen.

Attributes: center a tuple (x, y), width a float, sharpness a float.

CMYKHalftone(center=None, width=None, angle=None, sharpness=None, GCR=None, UCR=None)

Creates a color, halftoned rendition of the source image, using cyan, magenta, yellow, and black inks over a white page.

Attributes: center a tuple (x, y), width a float, angle a float in degrees, sharpness a float, GCR a float, UCR a float.

dotScreen(center=None, angle=None, width=None, sharpness=None)

Simulates the dot patterns of a halftone screen.

Attributes: center a tuple (x, y), angle a float in degrees, width a float, sharpness a float.

hatchedScreen(center=None, angle=None, width=None, sharpness=None)

Simulates the hatched pattern of a halftone screen.

Attributes: center a tuple (x, y), angle a float in degrees, width a float, sharpness a float.

lineScreen(center=None, angle=None, width=None, sharpness=None)

Simulates the line pattern of a halftone screen.

Attributes: center a tuple (x, y), angle a float in degrees, width a float, sharpness a float.

areaAverage(extent=None)

Returns a single-pixel image that contains the average color for the region of interest.

Attributes: extent a tuple (x, y, w, h).

areaHistogram(extent=None, count=None, scale=None)

Returns a 1D image (inputCount wide by one pixel high) that contains the component-wise histogram computed for the specified rectangular area.

Attributes: extent a tuple (x, y, w, h), count a float, scale a float.

rowAverage(extent=None)

Returns a 1-pixel high image that contains the average color for each scan row.

Attributes: extent a tuple (x, y, w, h).

columnAverage(extent=None)

Returns a 1-pixel high image that contains the average color for each scan column.

Attributes: extent a tuple (x, y, w, h).

histogramDisplayFilter(height=None, highLimit=None, lowLimit=None)

Generates a histogram image from the output of the areaHistogram filter.

Attributes: height a float, highLimit a float, lowLimit a float.

areaMaximum(extent=None)

Returns a single-pixel image that contains the maximum color components for the region of interest.

Attributes: extent a tuple (x, y, w, h).

areaMinimum(extent=None)

Returns a single-pixel image that contains the minimum color components for the region of interest.

Attributes: extent a tuple (x, y, w, h).

areaMaximumAlpha(extent=None)

Returns a single-pixel image that contains the color vector with the maximum alpha value for the region of interest.

Attributes: extent a tuple (x, y, w, h).

areaMinimumAlpha(extent=None)

Returns a single-pixel image that contains the color vector with the minimum alpha value for the region of interest.

Attributes: extent a tuple (x, y, w, h).

sharpenLuminance(sharpness=None)

Increases image detail by sharpening.

Attributes: sharpness a float.

unsharpMask(radius=None, intensity=None)

Increases the contrast of the edges between pixels of different colors in an image.

Attributes: radius a float, intensity a float.

blendWithAlphaMask(backgroundImage=None, maskImage=None)

Uses alpha values from a mask to interpolate between an image and the background.

Attributes: backgroundImage an Image object, maskImage an Image object.

blendWithMask(backgroundImage=None, maskImage=None)

Uses values from a grayscale mask to interpolate between an image and the background.

Attributes: backgroundImage an Image object, maskImage an Image object.

bloom(radius=None, intensity=None)

Softens edges and applies a pleasant glow to an image.

Attributes: radius a float, intensity a float.

comicEffect()

Simulates a comic book drawing by outlining edges and applying a color halftone effect.

convolution3X3(weights=None, bias=None)

Modifies pixel values by performing a 3x3 matrix convolution.

Attributes: weights a float, bias a float.

convolution5X5(weights=None, bias=None)

Modifies pixel values by performing a 5x5 matrix convolution.

Attributes: weights a float, bias a float.

convolution7X7(weights=None, bias=None)

Modifies pixel values by performing a 7x7 matrix convolution.

Attributes: weights a float, bias a float.

convolution9Horizontal(weights=None, bias=None)

Modifies pixel values by performing a 9-element horizontal convolution.

Attributes: weights a float, bias a float.

convolution9Vertical(weights=None, bias=None)

Modifies pixel values by performing a 9-element vertical convolution.

Attributes: weights a float, bias a float.

crystallize(radius=None, center=None)

Creates polygon-shaped color blocks by aggregating source pixel-color values.

Attributes: radius a float, center a tuple (x, y).

depthOfField(point0=None, point1=None, saturation=None, unsharpMaskRadius=None, unsharpMaskIntensity=None, radius=None)

Simulates a depth of field effect.

Attributes: point0 a tuple (x, y), point1 a tuple (x, y), saturation a float, unsharpMaskRadius a float, unsharpMaskIntensity a float, radius a float.

edges(intensity=None)

Finds all edges in an image and displays them in color.

Attributes: intensity a float.

edgeWork(radius=None)

Produces a stylized black-and-white rendition of an image that looks similar to a woodblock cutout.

Attributes: radius a float.

gloom(radius=None, intensity=None)

Dulls the highlights of an image.

Attributes: radius a float, intensity a float.

heightFieldFromMask(radius=None)

Produces a continuous three-dimensional, loft-shaped height field from a grayscale mask.

Attributes: radius a float.

hexagonalPixellate(center=None, scale=None)

Maps an image to colored hexagons whose color is defined by the replaced pixels.

Attributes: center a tuple (x, y), scale a float.

highlightShadowAdjust(highlightAmount=None, shadowAmount=None)

Adjust the tonal mapping of an image while preserving spatial detail.

Attributes: highlightAmount a float, shadowAmount a float.

lineOverlay(noiseLevel=None, sharpness=None, edgeIntensity=None, threshold=None, contrast=None)

Creates a sketch that outlines the edges of an image in black.

Attributes: noiseLevel a float, sharpness a float, edgeIntensity a float, threshold a float, contrast a float.

pixellate(center=None, scale=None)

Makes an image blocky by mapping the image to colored squares whose color is defined by the replaced pixels.

Attributes: center a tuple (x, y), scale a float.

pointillize(radius=None, center=None)

Renders the source image in a pointillistic style.

Attributes: radius a float, center a tuple (x, y).

shadedMaterial(shadingImage=None, scale=None)

Produces a shaded image from a height field.

Attributes: shadingImage an Image object, scale a float.

spotColor(centerColor1=None, replacementColor1=None, closeness1=None, contrast1=None, centerColor2=None, replacementColor2=None, closeness2=None, contrast2=None, centerColor3=None, replacementColor3=None, closeness3=None, contrast3=None)

Replaces one or more color ranges with spot colors.

Attributes: centerColor1 RGBA tuple Color (r, g, b, a), replacementColor1 RGBA tuple Color (r, g, b, a), closeness1 a float, contrast1 a float, centerColor2 RGBA tuple Color (r, g, b, a), replacementColor2 RGBA tuple Color (r, g, b, a), closeness2 a float, contrast2 a float, centerColor3 RGBA tuple Color (r, g, b, a), replacementColor3 RGBA tuple Color (r, g, b, a), closeness3 a float, contrast3 a float.

spotLight(lightPosition=None, lightPointsAt=None, brightness=None, concentration=None, color=None)

Applies a directional spotlight effect to an image.

Attributes: lightPosition a tulple (x, y, z), lightPointsAt a tuple (x, y), brightness a float, concentration a float, color RGBA tuple Color (r, g, b, a).

affineClamp(transform=None)

Performs an affine transform on a source image and then clamps the pixels at the edge of the transformed image, extending them outwards.

Attributes: transform.

affineTile(transform=None)

Applies an affine transform to an image and then tiles the transformed image.

Attributes: transform.

eightfoldReflectedTile(center=None, angle=None, width=None)

Produces a tiled image from a source image by applying an 8-way reflected symmetry.

Attributes: center a tuple (x, y), angle a float in degrees, width a float.

fourfoldReflectedTile(center=None, angle=None, acuteAngle=None, width=None)

Produces a tiled image from a source image by applying a 4-way reflected symmetry.

Attributes: center a tuple (x, y), angle a float in degrees, acuteAngle a float in degrees, width a float.

fourfoldRotatedTile(center=None, angle=None, width=None)

Produces a tiled image from a source image by rotating the source image at increments of 90 degrees.

Attributes: center a tuple (x, y), angle a float in degrees, width a float.

fourfoldTranslatedTile(center=None, angle=None, acuteAngle=None, width=None)

Produces a tiled image from a source image by applying 4 translation operations.

Attributes: center a tuple (x, y), angle a float in degrees, acuteAngle a float in degrees, width a float.

glideReflectedTile(center=None, angle=None, width=None)

Produces a tiled image from a source image by translating and smearing the image.

Attributes: center a tuple (x, y), angle a float in degrees, width a float.

kaleidoscope(count=None, center=None, angle=None)

Produces a kaleidoscopic image from a source image by applying 12-way symmetry.

Attributes: count a float, center a tuple (x, y), angle a float in degrees.

opTile(center=None, scale=None, angle=None, width=None)

Segments an image, applying any specified scaling and rotation, and then assembles the image again to give an op art appearance.

Attributes: center a tuple (x, y), scale a float, angle a float in degrees, width a float.

parallelogramTile(center=None, angle=None, acuteAngle=None, width=None)

Warps an image by reflecting it in a parallelogram, and then tiles the result.

Attributes: center a tuple (x, y), angle a float in degrees, acuteAngle a float in degrees, width a float.

perspectiveTile(topLeft=None, topRight=None, bottomRight=None, bottomLeft=None)

Applies a perspective transform to an image and then tiles the result.

Attributes: topLeft a tuple (x, y), topRight a tuple (x, y), bottomRight a tuple (x, y), bottomLeft a tuple (x, y).

sixfoldReflectedTile(center=None, angle=None, width=None)

Produces a tiled image from a source image by applying a 6-way reflected symmetry.

Attributes: center a tuple (x, y), angle a float in degrees, width a float.

sixfoldRotatedTile(center=None, angle=None, width=None)

Produces a tiled image from a source image by rotating the source image at increments of 60 degrees.

Attributes: center a tuple (x, y), angle a float in degrees, width a float.

triangleTile(center=None, angle=None, width=None)

Maps a triangular portion of image to a triangular area and then tiles the result.

Attributes: center a tuple (x, y), angle a float in degrees, width a float.

twelvefoldReflectedTile(center=None, angle=None, width=None)

Produces a tiled image from a source image by rotating the source image at increments of 30 degrees.

Attributes: center a tuple (x, y), angle a float in degrees, width a float.

accordionFoldTransition(targetImage=None, bottomHeight=None, numberOfFolds=None, foldShadowAmount=None, time=None)

Transitions from one image to another of differing dimensions by unfolding and crossfading.

Attributes: targetImage an Image object, bottomHeight a float, numberOfFolds a float, foldShadowAmount a float, time a float.

barsSwipeTransition(targetImage=None, angle=None, width=None, barOffset=None, time=None)

Transitions from one image to another by passing a bar over the source image.

Attributes: targetImage an Image object, angle a float in degrees, width a float, barOffset a float, time a float.

copyMachineTransition(targetImage=None, extent=None, color=None, time=None, angle=None, width=None, opacity=None)

Transitions from one image to another by simulating the effect of a copy machine.

Attributes: targetImage an Image object, extent a tuple (x, y, w, h), color RGBA tuple Color (r, g, b, a), time a float, angle a float in degrees, width a float, opacity a float.

disintegrateWithMaskTransition(targetImage=None, maskImage=None, time=None, shadowRadius=None, shadowDensity=None, shadowOffset=None)

Transitions from one image to another using the shape defined by a mask.

Attributes: targetImage an Image object, maskImage an Image object, time a float, shadowRadius a float, shadowDensity a float, shadowOffset a tuple (x, y).

dissolveTransition(targetImage=None, time=None)

Uses a dissolve to transition from one image to another.

Attributes: targetImage an Image object, time a float.

flashTransition(targetImage=None, center=None, extent=None, color=None, time=None, maxStriationRadius=None, striationStrength=None, striationContrast=None, fadeThreshold=None)

Transitions from one image to another by creating a flash.

Attributes: targetImage an Image object, center a tuple (x, y), extent a tuple (x, y, w, h), color RGBA tuple Color (r, g, b, a), time a float, maxStriationRadius a float, striationStrength a float, striationContrast a float, fadeThreshold a float.

modTransition(targetImage=None, center=None, time=None, angle=None, radius=None, compression=None)

Transitions from one image to another by revealing the target image through irregularly shaped holes.

Attributes: targetImage an Image object, center a tuple (x, y), time a float, angle a float in degrees, radius a float, compression a float.

pageCurlTransition(targetImage=None, backsideImage=None, shadingImage=None, extent=None, time=None, angle=None, radius=None)

Transitions from one image to another by simulating a curling page, revealing the new image as the page curls.

Attributes: targetImage an Image object, backsideImage an Image object, shadingImage an Image object, extent a tuple (x, y, w, h), time a float, angle a float in degrees, radius a float.

pageCurlWithShadowTransition(targetImage=None, backsideImage=None, extent=None, time=None, angle=None, radius=None, shadowSize=None, shadowAmount=None, shadowExtent=None)

Transitions from one image to another by simulating a curling page, revealing the new image as the page curls.

Attributes: targetImage an Image object, backsideImage an Image object, extent a tuple (x, y, w, h), time a float, angle a float in degrees, radius a float, shadowSize a float, shadowAmount a float, shadowExtent a tuple (x, y, w, h).

rippleTransition(targetImage=None, shadingImage=None, center=None, extent=None, time=None, width=None, scale=None)

Transitions from one image to another by creating a circular wave that expands from the center point, revealing the new image in the wake of the wave.

Attributes: targetImage an Image object, shadingImage an Image object, center a tuple (x, y), extent a tuple (x, y, w, h), time a float, width a float, scale a float.

swipeTransition(targetImage=None, extent=None, color=None, time=None, angle=None, width=None, opacity=None)

Transitions from one image to another by simulating a swiping action.

Attributes: targetImage an Image object, extent a tuple (x, y, w, h), color RGBA tuple Color (r, g, b, a), time a float, angle a float in degrees, width a float, opacity a float.

Variables

Variable(variables, workSpace, continuous=True)

Build small UI for variables in a script.

The workSpace is usually globals() as you want to insert the variable in the current workspace. It is required that workSpace is a dict object.

The continuous argument controls whether the script is run when UI elements change. The default is True, which will execute the script immediately and continuously when the user input changes. When set to False, there will be an “Update” button added at the bottom of the window. The user will have to click this button to execute the script and see the changes. This is useful when the script is slow, and continuous execution would decrease responsiveness.

_images/variables.png
# create small ui element for variables in the script

Variable([
    # create a variable called 'w'
    # and the related ui is a Slider.
    dict(name="w", ui="Slider"),
    # create a variable called 'h'
    # and the related ui is a Slider.
    dict(name="h", ui="Slider",
            args=dict(
                # some vanilla specific
                # setting for a slider
                value=100,
                minValue=50,
                maxValue=300)),
    # create a variable called 'useColor'
    # and the related ui is a CheckBox.
    dict(name="useColor", ui="CheckBox"),
    # create a variable called 'c'
    # and the related ui is a ColorWell.
    dict(name="c", ui="ColorWell")
    ], globals())

# draw a rect
rect(0, 0, w, h)

# check if the 'useColor' variable is checked
if useColor:
    # set the fill color from the variables
    fill(c)
# set the font size
fontSize(h)
# draw some text
text("Hello Variable", (w, h))
# Variable == vanilla power in DrawBot
from AppKit import NSColor
# create a color
_color = NSColor.colorWithCalibratedRed_green_blue_alpha_(0, .5, 1, .8)
# setup variables using different vanilla ui elements.
Variable([
    dict(name="aList", ui="PopUpButton", args=dict(items=['a', 'b', 'c', 'd'])),
    dict(name="aText", ui="EditText", args=dict(text='hello world')),
    dict(name="aSlider", ui="Slider", args=dict(value=100, minValue=50, maxValue=300)),
    dict(name="aCheckBox", ui="CheckBox", args=dict(value=True)),
    dict(name="aColorWell", ui="ColorWell", args=dict(color=_color)),
    dict(name="aRadioGroup", ui="RadioGroup", args=dict(titles=['I', 'II', 'III'], isVertical=False)),
], globals())

print(aList)
print(aText)
print(aSlider)
print(aCheckBox)
print(aColorWell)
print(aRadioGroup)

Quick Reference

# DrawBot reference

# set a size for the canvas
size(500, 500)

# using the functions width, height and pageCount
print("width:", width())
print("height:", height())

print("pageCount:", pageCount())

# simple shapes

# draw rect x, y, width, height
rect(10, 10, 100, 100)

# draw oval x, y, width, height
oval(10, 120, 100, 100)
oval(120, 120, 100, 100)

# draw polygon
polygon((10, 250), (100, 250), (100, 400), (50, 300), close=False)

# create path
newPath()
# move to point
moveTo((300, 100))
lineTo((400, 100))

# first control point (x1, y1)
# second control point (x2, y2)
# end point (x3, y3)
curveTo((450, 150), (450, 250), (400, 300))
lineTo((300, 300))
# close the path
closePath()
# draw the path
drawPath()

newPage()
# image: path, (x, y), alpha
image("https://github.com/typemytype/drawbot/raw/master/docs/content/assets/drawBot.jpg", (10, 10), .5)

newPage()
print("pageCount:", pageCount())
# colors
# fill(r, g, b)
# fill(r, g, b, alpha)
# fill(grayvalue)
# fill(grayvalue, alpha)
# fill(None)
fill(.5)
rect(10, 10, 100, 100)

fill(1, 0, 0)
rect(10, 120, 100, 100)

fill(0, 1, 0, .5)
oval(50, 50, 100, 100)

fill(None)

# stroke(r, g, b)
# stroke(r, g, b, alpha)
# stroke(grayvalue)
# stroke(grayvalue, alpha)
# stroke(None)
strokeWidth(8)
stroke(.8)
rect(200, 10, 100, 100)

stroke(.1, .1, .8)
rect(200, 120, 100, 100)

strokeWidth(20)
stroke(1, 0, 1, .5)
oval(250, 50, 100, 100)


newPage()
# stroke attributes

print("pageCount:", pageCount())
fill(None)
stroke(0)
strokeWidth(8)

lineCap("square")
lineJoin("miter")
miterLimit(5)
polygon((10, 10), (10, 400), (50, 350), close=False)

lineCap("round")
lineJoin("round")
polygon((110, 10), (110, 400), (150, 350), close=False)

lineCap("butt")
lineJoin("bevel")
polygon((210, 10), (210, 400), (250, 350), close=False)

lineDash(10, 10, 2, 5)
polygon((310, 10), (310, 400), (350, 350), close=False)

newPage()
print("pageCount:", pageCount())

text("Hello World", (10, 10))

fontSize(100)
fill(1, 0, 0)
stroke(0)
strokeWidth(5)
text("Hello World", (10, 20))

font("Times-Italic", 25)
fill(0, .5, 1)
stroke(None)
textBox("Hello World " * 100, (10, 150, 300, 300))


print("textSize:", textSize("Hallo"))

newPage()
# canvas transformations
print("pageCount:", pageCount())

fill(None)
stroke(0)
strokeWidth(3)
save()
rect(10, 10, 100, 100)


scale(2)
rect(10, 10, 100, 100)
restore()

save()
rotate(30)
rect(10, 10, 100, 100)
restore()

save()
skew(30)
rect(10, 10, 100, 100)
restore()

newPage()
print("pageCount:", pageCount())

#    c m y k alpha
cmykFill(0, 1, 0, 0)
rect(10, 10, 100, 100)

strokeWidth(5)
cmykFill(None)
cmykStroke(0, 1, 1, 0)
rect(10, 110, 100, 100)

cmykLinearGradient((10, 210), (10, 310), ([1, 1, 1, 1], [0, 1, 1, 0]))
rect(10, 210, 100, 100)

cmykStroke(None)

cmykRadialGradient((50, 410), (50, 410), ([1, 0, 1, 0], [1, 1, 0, 0], [0, 1, 1, 0]), startRadius=0, endRadius=300)
rect(10, 310, 100, 150)

cmykShadow((10, 10), 20, (0, 1, 1, 0))
oval(130, 310, 300, 150)

newPage()
print("pageCount:", pageCount())

fill(1, 0, 1)
linearGradient((10, 10), (200, 20), ([1, 1, 0], [0, 1, 1]))

rect(10, 10, 200, 200)

radialGradient((50, 410), (50, 410), ([1, 0, 1], [1, 1, 0], [0, 1, 1]), startRadius=0, endRadius=300)
rect(10, 310, 100, 150)

shadow((10, 10), 20, (1, 0, 0))
oval(130, 310, 300, 150)

newPage()

save()

path = BezierPath()
path.oval(20, 20, 300, 100)
clipPath(path)

fill(1, 0, 0, .3)
rect(10, 10, 100, 100)

fontSize(30)
text("Hello World", (50, 80))

restore()

oval(200, 20, 50, 50)

saveImage(u"~/Desktop/drawBotTest.pdf")
saveImage(u"~/Desktop/drawBotTest.png")
saveImage(u"~/Desktop/drawBotTest.svg")
saveImage(u"~/Desktop/drawBotTest.mp4")

print("Done")

DrawBot App

_images/drawBotApp.png

Drawbot has three main views:

  • A Code Editor: the place to write code.
  • An Output View for print statements and tracebacks (reports for when your script fails).
  • The Preview will preview the current page – and all generated pages, in the case of documents with multiple pages.

The Preferences window contains some settings related to the appearance of the DrawBot editor.

Code Editor

The place where you can tell Python to draw things on the page and/or print things in the console.

The syntax colors can be customized in the Preferences window.

Code interaction

The code editor also makes it easy and fun to interact with values in your program. When selected, some kinds of Python objects can be modified dynamically by pressing the Cmd key. The effects depend on the type of object:

  • bool: select and Cmd-click to turn the value on/off like a switch.
  • int or float: select the number, press Cmd and move the mouse up/down or right/left to increase/decrease the number. The default step is 1, by pressing alt the step is changed to 0.1. Additional shift can be pressed to multiply the steps by 10. Using the arrow keys also works.
  • in tuples with numbers it is possible to select two neighbouring numbers and modify them together at the same time – this is specially useful when working with coordinate pairs or dimensions.
Live coding

The live coding mode executes the code as you type, so you can see changes without having to re-run the program every time. This is useful when working with text or making demonstrations.

This feature can be turned on/off in the Python menu.

Use it with caution: depending on the size of your program and the amount of interaction, Drawbot can get a bit slow.

Preview

The Preview area is where your generated graphics are displayed.

Current page

The main preview area shows the drawing canvas or current page.

The zoom level can be increased with Cmd+ and decreased with Cmd-.

In case of multi-page documents, the visualization settings can be changed by right-clicking on the page and choosing between single or double pages and continuous or individual.

Pages overview

Besides the current page there is also a secondary pane to the left where all pages can be seen at once (in case of multi-page documents). This pane is hidden by default, and can be opened by pulling the vertical division to the right.

Preferences

The Preferences window offers fine-grained control over the code editor’s syntax colors and font.

_images/preferences.png

Additional options include turning the animation of the icon and the auto-update feature on/off.

DrawBot Package

A .drawbot package is a DrawBot app readable file containing python files. Making it easy to share and exchange drawbot scripts.

Use a .drawbot package

Double click the or drop the .drawbot file on top of DrawBot.

Build a .drawbot package

Use the build in package builder to build a .drawbot package.

_images/packageBuilder.png
drawBot package specification

A .drawbot package is a folder with an extension.

<name>.drawbot (package)
    info.plist
    lib/
        main.py
        anotherScript.py
        anImage.jpg
        ...

The info plist dictionary can have the following keywords:

  • name: optional, default to <name>.drawBot
  • version: optional, default to 0.0, but advised to set
  • developer: optional, default to None
  • developerURL: optional, default to None
  • requiresVersion: optional, default to all versions
  • mainScript: optional, default to ‘lib/main.py’ if this isn’t specified?)

Download

requirements: osX 10.9+

License

The BSD License

Copyright (c) 2003-2019 Just van Rossum, Erik van Blokland, Frederik Berlaen

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

DrawBot Icon

The making of (by Andy Clymer)

from ufoLib.glifLib import readGlyphFromString
from fontTools.pens.cocoaPen import CocoaPen
from fontParts.fontshell.glyph import RGlyph
import random
import os

tryAndError = False
drawPencil = True
drawBubbles = True

# Big pencil for the file icon?
# (and then only save the first frame)
bigPencil = False

# Left handed?
leftHand = True

# Reduced color palette for file icon?
reducedPalette = False

folderPath = os.path.split(__file__)[0]
savePath = os.path.join(folderPath, "icon.gif")
singleFileSavePath = os.path.join(folderPath, "icon_%s.png")
#savePath = os.path.join(folderPath, "icon.png")


lightOrange = [1, 0.75, 0, 1]
orange = [1, 0.5, 0, 1]
redOrange = [1, 0.25, 0.1, 1]
darkOrange = [0.3, 0.15, 0, .4]
pinkish = [1, 0.5, 0.6, 1]
magenta = [0.9, 0.1, 0.5, 1]
purple = [0.7, 0.1, 0.8, 1]
darkPurple = [0.5, 0, 0.5]
brightPurple = [1, 0.1, 1, 1]
gray = [0.8, 0.8, 0.8, 1]
white = [1, 1, 1, 1]


# Glif string
iconGlifString = b"""<?xml version="1.0" encoding="UTF-8"?>
<glyph name="A" format="1">
  <advance width="0"/>
  <outline>
    <contour>
      <point x="95" y="407" type="line"/>
      <point x="328" y="442"/>
      <point x="422" y="391"/>
      <point x="422" y="258" type="curve" smooth="yes"/>
      <point x="422" y="124"/>
      <point x="328" y="73"/>
      <point x="95" y="108" type="curve"/>
    </contour>
    <contour>
      <point x="218" y="305" type="curve"/>
      <point x="218" y="210" type="line"/>
      <point x="275" y="206"/>
      <point x="300" y="221"/>
      <point x="300" y="258" type="curve" smooth="yes"/>
      <point x="300" y="295"/>
      <point x="275" y="310"/>
    </contour>
  </outline>
</glyph>
"""

# Read the string into a glyph object
iconGlyph = RGlyph()
pen = iconGlyph.getPointPen()
readGlyphFromString(iconGlifString, glyphObject=iconGlyph, pointPen=pen)

iconGlyph.scaleBy((1.12, 1.2))

# Fetch the path of the glyph as a NSBezierPath
pen = CocoaPen(None)
iconGlyph.draw(pen)
iconPath = pen.path
# ...and then convert it to a DrawBot BezierPath
iconPath = BezierPath(iconPath)

# Remove the inside contour of the glyph, and read another path
iconGlyph.removeContour(1)
# Fetch the path of the glyph as a NSBezierPath
pen = CocoaPen(None)
iconGlyph.draw(pen)
iconOutsidePath = pen.path
# ...and then convert it to a DrawBot BezierPath
iconOutsidePath = BezierPath(iconOutsidePath)



""" Helper functions """

def interpolate(f, a, b):
    v = (a + (b - a) * f)
    return v

def interpolateColor(f, color0=None, color1=None):
    # Default the two colors to pinkish orange and magenta:
    if not color0:
        if reducedPalette:
            color0 = white
        else: color0 = lightOrange
    if not color1:
        if reducedPalette:
            color1 = orange
        else: color1 = orange
    newColor = []
    # Interpolate
    for i in range(4):
        newColor.append(interpolate(f, color0[i], color1[i]))
    return tuple(newColor)


def drawBubble(size, phase):
    # Shift the phase
    if phase > 1:
        phase = phase - 1
    # Scale the phase, so that it doesn't happen all the time
    phase *= 3
    # Draw if it's durring the current phase
    if phase < 1:
        fill(1, 1, 1, 1-phase)
        stroke(1, 1, 1, 1)
        strokeWidth(10 * (1-phase))
        phaseSize = phase*size
        oval(-0.5*phaseSize, -0.5*phaseSize, phaseSize, phaseSize)


# Make some random bubble data
bubbles = []
if drawBubbles:
    for i in range(100):
        bubbles.append(
            (random.randint(0, 512), # x
            random.randint(0, 512), # y
            random.randint(30, 100), # size
            random.random()) # phase
            )


""" Start drawing """


size(512, 512)

def drawIcon(timeFactor):
    # timeFactor is the timeline position, between 0 and 1

    # Temporary background color
    #fill(0.85)
    #rect(0, 0, 512, 512)

    translate(256, 256)
    scale(1.1)
    translate(-256, -256)
    translate(-27, -51)


    fill(None)
    # Transparent shadow under the "D"
    with savedState():

        #fill(*darkOrange)
        stroke(*darkOrange)
        strokeWidth(60)

        drawPath(iconPath)


    # Gradient within the "D"
    save()
    # Clip
    clipPath(iconPath)
    # Move to the center of the canvas
    translate(256, 256)
    circleCount = 30
    for i in range(circleCount):
        f = i/circleCount
        angle = (f * 360) + (360 * timeFactor)
        x = 120 * sin(radians(angle+90))
        y = 120 * cos(radians(angle+90))
        colorFactor = f * f * f # Use an exponential curve for the color factor
        stroke(None)
        fill(*interpolateColor(colorFactor))
        #shadow((0, 0), 50, interpolateColor(colorFactor)) # Extra smoothness?
        oval(x-150, y-150, 300, 300)
    restore()

    # Bubbles
    for bubble in bubbles:
        save()
        clipPath(iconPath)
        translate(bubble[0], bubble[1])
        drawBubble(bubble[2], timeFactor + bubble[3])
        restore()

    # Pencil location
    angle = (f * 360) + (360 * timeFactor) + 70
    x = 120 * sin(radians(angle+90)) + 80
    y = 90 * cos(radians(angle+90)) + 10
    if not leftHand:
        x -= 60
        y -= 20

    # Shadow inside the "D"
    save()
    shadowPath = iconPath.copy()
    # Add the pencil shadow
    shadowX = 256
    shadowY = 300
    if leftHand:
        shadowX -= 40
        shadowY -= 10
    if drawPencil:
        if not bigPencil:
            shadowPath.oval(shadowX+x, shadowY+y, 50, 50)
    clipPath(iconPath)
    translate(-20, -20)
    strokeWidth(61)
    stroke(0, 0, 0, 0.25)
    drawPath(shadowPath)
    restore()

    # White stroke on top of the "D"
    fill(None)
    stroke(1)
    strokeWidth(30)
    drawPath(iconPath)

    # Pencil
    if drawPencil:
        save()
        translate(256, 286)
        # Rotate the pencil with each step
        pencilRotationAngle = 10 * cos(radians(angle))
        translate(x, y)
        # Pencil
        rotate(pencilRotationAngle)
        # And an additional amount for the base angle of the pencil
        if leftHand:
            rotate(50)
        else: rotate(-25)
        if bigPencil:
            scale(1.9, 1.9)
            strokeWidth(14)
            translate(25, 10)
        else: strokeWidth(18)
        fill(None)
        if reducedPalette:
            stroke(1)
            fill(*orange)
        else:
            stroke(*darkPurple)
            fill(*brightPurple)
        polygon((0, 0), (-40, 40), (-40, 140), (40, 140), (40, 40), close=True)
        # Pencil end
        oval(-40, 130, 80, 40)
        # Pencil tip
        if reducedPalette:
            fill(1)
        else: fill(*darkPurple)
        stroke(None)
        oval(-20, 0, 40, 40)
        restore()



totalFrames = 21
if tryAndError:
    totalFrames = 1
for i in range(totalFrames):
    f = i / totalFrames
    if not i == 0:
        newPage()
    frameDuration(1/10)
    drawIcon(f)
    if not tryAndError:
        pass#saveImage(singleFileSavePath % i)


if not tryAndError:
    saveImage(savePath)

Courseware

Teaching with DrawBot

Python is a great language for introducing the basic concepts of programming to entry level students. There are many tutorials and introduction packages available for the language (see the overview on the python site).

DrawBot combines the easy to learn Python with a compact but powerful application in which code, result and feedback are visible at a glance. This section collects scripts and advice on how to specifically use DrawBot in a programming course. Step by step

Each of the scripts on this page focus on a particular section of Python. Click on the link and copy the text of the script to a new DrawBot window. Read the comments (the lines starting with a #) for clues and help.

Basic math

How do numbers look in Python? how to write simple sums, multiplication, substrations etc.

# this is a comment

print("some basic numbers:")
print(12)  # this is an integer number
print(12.5)  # this is a floating point

print("results of adding:")
print(12 + 13)  # results in an integer
print(12 + 0.5)  # results in a float
print(0.5 + 12)  # ditto

print("results of subtracting:")
print(12 - 8)
print(12 - 25)

print("results of multiplication:")
print(12 * 8)
print(12 * -25)

print("results of dividing:")
print(12 / 2)
print(11 / 2)
print(11 // 2)  # integer division
print(11 % 2)   # modulo

print("results of 'the power of':")
print(2 ** 8)
print(10 ** 2)
print(2 ** 0.5)

print("let's cause an error:")
print(1 / 0)

Strings

Strings contain text, a sequence of letters like beads on a string. This script shows what strings can do.

print('this is a so called "string"')
print("this is a so called 'string'")
print("this is a so called \"string\"")

print("one string " + "another string")

a = "one string"
b = "another string"

print(a + " " + b)

print("many " * 10)


print("non-ascii should generally work:")
print("Åbenrå © Ђ ק")
print("and now an error:")
print("many " * 10.0)
# string multiplication really wants an
# integer number; a float that happens to
# be a whole number is not good enough

Variables

Variables are similar to storage boxes, they need to have a name and contain something. This script shows how to name variables in Python, and some neat tricks they can perform.

a = 12
b = 15
c = a * b
CAP = "a string"

print(c)

print(CAP)

# variable names cannot start with a
# number:
#1a = 12

# variable names can contain numbers,
# just not at the start:
a1 = 12

# underscores are allowed:
_a = 12
a_ = 13

#   a-z  A-Z  0-9  _

# everything is an object
# this "rebinds" the name 'a' to a new
# object:
a = a + 12

# variable names are case sensitive
# meaning that:
x = 12
# is a different variable from
X = 13
print(x)
print(X)

y = 102
# so this is an error:
print(Y)

Lists and loops

Lists are sequences of things, like a string is a sequence of letters. But lists can contain things like numbers, variables and other lists. Loops are uses to jump through a list and look at each one of the items. Loops are a powerful and fast way to work with lots of items.

# let's introduce 'lists' (or 'arrays' as
# they are called in some other languages)
alist = [1, -2, "asdsd", 4, 50]
print(alist)
alist.append(1234)
print(alist)
# fetching an item from the list:
print(alist[0])  # the first item
print(alist[1])  # the second
# negative numbers start from the end:
print(alist[-1])  # the last item
print(alist[-2])  # the one before last

print("nested lists:")
print([1, 2, 3, ["a", "b", "c"]])
print([1, 2, 3, ["a", ["deeper"]]])

# assigning a list to another name does
# not make a copy: you just create another
# reference to the same object
anotherlist = alist
anotherlist.append(-9999)
print(anotherlist)
print(alist)
acopy = list(alist)
acopy.append(9999)
print(acopy)
print(alist)

# strings are also sequences:
astring = "abcdefg"
print(astring[2])
print(astring[-1])  # from the end

print("getting 'slices' from a list:")
print(alist)
print(alist[2:5])


print("there's a nice builtin function that")
print("creates a list of numbers:")
print(range(10))  # from 0 to 10 (not incl. 10!)
print(range(5, 10))  # from 5 to 10 (not incl. 10!)
print(range(1, 19, 3)) # from 1 to 19 in steps of 3

print("let's loop over this list:")
print(alist)
for item in alist:
    # this is the body of the "for" loop
    print(item)
    # more lines following can follow
    # you need to indent consistently,
    # this would not work:
#        print("hello")
    # also: use the tab key to manually
    # indent. There are shortcuts to indent
    # or dedent blocks of code: cmd-[ and cmd-]

print("loop over some numbers:")
for item in range(10):
    print(item)

print("loop over some numbers, doing 'math':")
for i in range(10):
    print(i, i * 0.5)

print("nested loops:")
for x in range(1, 5):  # outer loop
    print("---")
    for y in range(x, x + 5):  # inner loop
        print(x, y, x * y)

print("three loops:")
for x in range(2):
    for y in range(2):
        for z in range(2):
            print(x, y, z)

print("three loops with a counter:")
count = 1
for x in range(2):
    for y in range(2):
        for z in range(2):
            print(x, y, z, count)
            count = count + 1
            # alternate spelling:
            #count += 1

Functions

Functions are small programs with the program. Rather than write something over and over again, you can write a function and recycle the code in different parts of your program.

# defining a function:
def myfunction():
    print("hello!")

# calling the function:
myfunction()

# a common error
# not calling the function:
myfunction   # note missing ()


# defining a function that takes an
# 'argument' (or 'parameter')
def mysecondfunction(x, y):
    print("hello!")
    print(x, y)

# calling the function with 2 arguments
mysecondfunction(123, 456)


def add2numbers(x, y):
    # you can see 'global' vars
    print(aglobalvariable)
    result = x + y
    return result

aglobalvariable = "hi!"
thereturnedvalue = add2numbers(1, 2)
print(thereturnedvalue)
# 'result' was a local name inside
# add2number, so it is not visible at the
# top level. So the next line would cause
# an error:
#print(result)


def anotherfunc(x, y):
    # calling add2numbers function:
    return add2numbers(x, y)

print(anotherfunc(1, 2))

Conditions

Sometimes your program needs to respond to particular values or situations. If this value is 4, then go there. If it isn’t, just go on.

# comparisons

# let's define some variables
a = 12
b = 20
print(a, b)

print("are a and b equal?")
print(a == b)

print("are a and b not equal?")
print(a != b)

print("is a greater than b?")
print(a > b)

print("is a less than b?")
print(a < b)

print("is a greater than or equal to b?")
print(a >= b)

print("is a less than or equal to b?")
print(a <= b)

result = a < b
print("result is:")
print(result)

print("these are the 'boolean' values:")
print("the True value:")
print(True)
print("the False value:")
print(False)

if a < b:
    print("a is less than b")

if a > b:
    print("a is greater than b")

print("if/else")
if a < b:
    print("A")
else:
    print("B")

print("if/elif/else")
if a > b:
    print("A")
elif a == 12:
    print("B")
else:
    print("C")

print("if/elif/elif/.../else")
if a > b:
    print("A")
elif a == 10:
    print("B 10")
elif a == 11:
    print("B 11")
elif a == 12:
    print("B 12")
elif a == 13:
    print("B 13")
else:
    print("C")

# boolean logic
if a > 15 and b > 15:
    print("both a and b are greater than 15")
else:
    print("either one of a and b is NOT greater than 15")

if a > 15 or b > 15:
    print("a OR b are greater than 15")
else:
    print("neither a or b ate greater than 15")

print("a result:")
print(a > 15 or b > 15)

# inversing a truth value:
print("not True:"
print(not True)
print("not False:")
print(not False)
print("not not False:"
print(not not False)
print("not not not False:")
print(not not not False)

# grouping subexpressions by using parentheses:
if (a > b and b == 13) or b == 25:
    print("...")
if a > b and (b == 13 or b == 25):
    print("...")
# parentheses nest:
#if a > b and (b == 13 or (b == 25 and a == 12)):
#   ...

Random numbers

Fun things to do with random numbers. The computer is full of them.

# the random() function returns a pseudo-
# random number between zero and one
print("a random number between 0.0 and 1.0:")
print(random())

# the randint() function returns a pseudo-
# random integer number in the range you
# specify.
print("a random integer between 0 and 4:")
print(randint(0, 4))
print("a random integer between 10 and 20:")
print(randint(10, 20))

# use a random number to do different
# things.
print("choose randomly between A and B, 6 times:")
for i in range(6):
    if random() > 0.5:
        print("A")
    else:
        print("B")

Shapes

Drawing a couple of the basic shapes. Have a look at the Drawing Primitives pages for a detailed overview of shapes.

# draw a rectangle
# rect(x, y, width, height)
rect(20, 50, 100, 200)

rect(130, 50, 100, 200)

oval(240, 50, 100, 200)

oval(20, 250, 100, 100)

oval(130, 250, 100, 100)

rect(240, 250, 100, 100)

for x in range(20, 300, 50):
    rect(x, 370, 40, 40)

for x in range(20, 300, 50):
    if random() > 0.5:
        rect(x, 420, 40, 40)
    else:
        oval(x, 420, 40, 40)

Colors

Shapes can also be colored. This script shows how work with shapes in colors and transparency values.

# set the current fill color
# the three numbers are values for
# red, green and blue (RGB)
# the values are numbers between
# 0 and 1
fill(0, 0, 0.75)

# draw two rectangles
rect(50, 50, 150, 250)
rect(150, 150, 150, 250)

# set a color
# note the fourth number: it's the
# transparency
fill(1, 0, 0, 0.25)
rect(250, 250, 150, 250)
rect(350, 350, 150, 250)

History

The DrawBot project started in 2003 as a program named “DesignRobots”, written for the occasion of a Python workshop at the TypoTechnica conference. Since then the application evolved into a Cocoa application with a powerful API and image export functionality.

Version 0.9a

First release as Cocoa application. Supports rectangles, ovals, bezier paths, but not text. Unofficial Fork of Version 0.9a

There is an unofficial forked version of DrawBot around. Unfortunately this version does not document the differences with the current DrawBot. This has led to considerable confusion and frustration with users.

Version 2.0

In use at the TypeMedia department of the Royal Academy in The Hague for about then 10 years!. Many Improvements on the API and text support. (2007)

Version 3+

Complete rewritten and many improvements on the API.

Credits

Thanks to Python and PyObjC for making this possible and Tal Leming for wrapping PyObjC in vanilla.

A tip of the hat to John Maeda for showing the way with Design By Numbers, Casey Reas and Ben Fry, the folks from Processing.

Finally thanks for the support and feedback from the users!

Thanks Andy for the icon!

Toots

Tweets