DrawBot – die Mutter aller Knotenschachteln
Alle Knotenschachteln – egal ob NodeBox 1, PlotDevice, NodeBox for OpenGL oder Shoebot – gehen auf eine Macintosh-App zurück: Auf DrawBot.
DrawBot ist eine mächtige, freie (BSD-Lizenz), in Python geschriebene Anwendung für macOS für die Erstellung zweidimensionaler Graphiken. DrawBot kann, im Gegensatz zum Beispiel zu Processing, mehrere Seiten mit einem Skript erzeugen. DrawBots Exportformate sind PDF (auch via Menü), SVG, PNG, JPEG, TIFF, animated GIF, MP4-Video und noch einige mehr (via saveImage). Die Anwendung kommt als binäre, vollständige Applikation (erstellt mit py2app), sie kann aber auch als Modul in anderen Python-Anwendungen eingesetzt werden. Aber auch das Modul ist Mac-only, da mit PyObjC erstellt, und damit verwandt mit seinem Nachfolgerprojekt Nodebox 1.
Einer der Hauptentwickler von DrawBot ist der Typograph Just van Rossum, ein Bruder des Python-»Erfinders« Guido van Rossum1.
Ich selber bin erst verhältnismäig spät (im August 2021) über DrawBot gestolpert und habe dann auch ein paar Mal damit herumgespielt und dabei über ein Reboot nachgedacht. Grund dafür war auch hier, dass DrawBot auflösungsunabhängige Dateien ausgibt, die sich beliebig verlustfrei aufblasen lassen.
Das war natürlich ein Ansporn für mich, die zufälligen Kreise, die ich in den letzten Tagen mit NodeBox 1 und mit PlotDevice auflösungsunabhängig realisiert hatte, auch mal nach DrawBot zu portieren. Das Ergebnis ist dasselbe (auch wenn ich dieses Mal – um nicht immer gleich aussehende Screenshots zu haben – als Hintergrundfarbe Packpapierbraun gewählt hatte). Doch hier erst einmal der Quellcode:
from random import randint
WIDTH, HEIGHT = 640, 400
malewitsch = [(42/255.0, 40/255.0, 45/255.0),
(160/255.0, 51/255.0, 46/255.0),
(54/255.0, 50/255.0, 80/255.0),
(50/255.0, 80/255.0, 105/255.0),
(180/255.0, 144/255.0, 55/255.0),
(215/255.0, 158/255.0, 40/255.0),
(140/255.0, 82/255.0, 48/255.0)]
a = 0.6 # Alpha (Transparenz)
numCircles = 200
def makeFillColor(color, a):
r = color[0]
g = color[1]
b = color[2]
fill(r, g, b, a)
size(WIDTH, HEIGHT)
# Hintergrundfarbe (Packpapier)
bgColor = (230/255.0, 226/255.0, 204/255.0)
makeFillColor(bgColor, 1)
rect(0, 0, width(), height())
strokeWidth(1)
for _ in range(numCircles):
x = randint(50, WIDTH - 50)
y = randint(50, HEIGHT - 50)
stroke(0) # Schwarzer Rand
makeFillColor(malewitsch[(randint(0, len(malewitsch) -1))], 1.0)
d = 6. # Durchmesser
r = d//2. # Radius
oval(x - r, y - r, d, d)
stroke(0, 0.0) # no stroke
makeFillColor(malewitsch[(randint(0, len(malewitsch) -1))], a)
d = randint(20, 60) # Durchmesser
r = d//2. # Radius
oval(x - r, y - r, d, d)
print("I did it, Babe!")Bis auf Nuancen ist er wieder nahezu identisch mit den PlotDevice- und NodeBox-1-Beispielen2. Ein Unterschied ist, dass DrawBox die RGB-Werte als Nachkommazahlen zwischen Null und Eins erwartet. Ein anderer, dass der Ursprung des Koordinatensystems bei DrawBot in der linken unteren Ecke liegt. Das musste aber in diesem Beispiel nur dabei beachtet werden, dass die Radii (da der Ursprung der oval()-Funktion in der linken oberen Ecke liegt und somit der dritte und vierte Parameter nicht die Radii, sondern der Durchmesser, genauer die Breite und die Höhe des Ovals, sind), von der x- und y-Koordinate abgezogen werden müssen, um die Kreise zentriert zu zeichnen.
Ein weiterer »Trick« ist auch, dass ich mit stroke(0, 0.0) den zweiten, äußeren Kreis ohne Umrandung gezeichnet habe. Denn eine voll transparente Umrandung ist keine Umrandung.
Auch das Spielen mit DrawBot hat mir viel Spaß gemacht. Jetzt weiß ich wirklich nicht, welche der drei Applikationen ich für mein mögliches Projekt »Generative Art auf Papier und zwischen zwei Pappedeckel gepresst« einsetzen soll. Ich werde mit allen drei wohl noch ein wenig spielen müssen, um mich entscheiden zu können. Aber da ich ja bekanntlich ein großes Spielkalb bin … Still digging!
Fußnoten
Funfakt am Rande: Im Gegensatz zu seinem Bruder, der den
snake_casezu einem Quasi-Standard für Python erhoben hat, bevorzugt Just van Rossum dencamelCaseund setzt das auch konsequent in DrawBot um.↩︎Die »neue« Funktion
makeFillColor()(camelCase 🤓) ist vielleicht der Ausweg, wie ich RGB-Farbwerte auch in NodeBox 1 und PlotDevice mit unterschiedlichen Alpha-Werten (für die Transparenz) kombinieren kann, ohne gleich ein zweites Array anlegen zu müssen.↩︎

