Programming Digital Media

Shapes

Shapes When we create images from procedural descriptions of shapes, we're no longer concerned with setting pixel values directly. Instead, we execute higher-level actions that result only as a side-effect in determining the colors of pixels.

Apple has provided a Python wrapper for the Quartz 2D programming interface. The scripts below use this interface to make images. Download the script by clicking on the script name or the image and run it with Python as you did for the scripts in the Filters tutorial. Then change some of the parameters that are defined in the beginning of the script to see how it changes the image.

You don't need to install any software to run these scripts. This statement at the beginning of the scripts loads the Quartz interface module:

    from CoreGraphics import *  
"Core Graphics" is the name used for Quartz in the software libraries. (This is why the classes begin with "CG".)

I've created a documentation page for the Quartz/Python interface. You can use your browser's search facility to look up function definitions in these scripts.


circle.py



from CoreGraphics import * 
import math   # For pi 
 
c = CGBitmapContextCreateWithColor( 
    300, 300,  # width, height 
    CGColorSpaceCreateDeviceRGB(), 
    (1, 1, 0, 1))  # yellow with opaque background 
 
c.setRGBFillColor(1, 0, 0, 1)  # opaque red 
c.addArc(150, 150, 100, 0, 2*math.pi, 1) 
c.fillPath() 
c.writeToFile("circle.tif", kCGImageFormatTIFF) 
 
 

circle_text.py



from CoreGraphics import * 
from math import pi 
 
font_name = 'Gill Sans Bold' 
font_size = 60 
text = 'A blue square' 
 
# Letter (8.5x11) "portrait" size for PDF (72dpi): 
page_bounding_box = CGRectMake(0, 0, 612, 792)  
c = CGPDFContextCreateWithFilename( 
        "circle_text.pdf", page_bounding_box) 
 
c.beginPage(page_bounding_box) 
c.setRGBFillColor(1, 1, .8, 1) 
c.addRect(CGRectMake(0, 0, 612, 792)) 
c.fillPath() 
c.setRGBFillColor(1, .3, .1, 1) 
c.addArc(306, 396, 160, 0, 2 * pi, 1) 
c.fillPath() 
 
c.setTextDrawingMode (kCGTextFill) 
c.setTextMatrix (CGAffineTransformIdentity) 
c.selectFont (font_name, font_size, kCGEncodingMacRoman) 
c.setRGBFillColor(.2, .9, .5, 1) 
c.showTextAtPoint (100, 100, text, len (text)) 
 
c.endPage() 
c.finish() 
 

boxes.py



from CoreGraphics import * 
# The "uniform" function returns a random number betwen the arguments. 
from whrandom import uniform 
 
image_width = 1024 
image_height = 768 
 
box_count = 5000 
 
box_min_size = 10 
box_max_size = 30 
 
box_min_red = .2 
box_max_red = .5 
 
box_min_green = .4 
box_max_green = .6 
 
box_min_blue = .5 
box_max_blue = .8 
 
box_min_alpha = .3 
box_max_alpha = .7 
 
c = CGBitmapContextCreateWithColor( 
    image_width, image_height, 
    CGColorSpaceCreateDeviceRGB(), (.3, .5, .4, 1)) 
 
for i in range(box_count): 
    x = uniform(-box_max_size, image_width) 
    y = uniform(-box_max_size, image_height) 
    box_width = uniform(box_min_size, box_max_size) 
    box_height = uniform(box_min_size, box_max_size) 
    box = CGRectMake(x, y, box_width, box_height) 
    c.setRGBFillColor(uniform(box_min_red, box_max_red), 
                      uniform(box_min_green, box_max_green), 
                      uniform(box_min_blue, box_max_blue), 
                      uniform(box_min_alpha, box_max_alpha)) 
    c.addRect(box) 
    c.fillPath() 
 
c.writeToFile("boxes.tif", kCGImageFormatTIFF) 

spiral.py



from CoreGraphics import * 
from math import pi 
 
image_width = 1024 
image_height = 768 
circle_count = 21 
spiral_arm_count = 10 
distance_between_circles = 3 
circle_rotation_increment = pi / 3 
 
# The "fit" function returns a number that has the same relationship 
# to the new range as v did to the old. 
 
def fit(v, oldmin, oldmax, newmin, newmax, clamp = 1): 
    if clamp: 
        if v < oldmin: 
            return float(newmin) 
        elif v > oldmax: 
            return float(newmax) 
    scale = (float(v) - oldmin) / (oldmax - oldmin) 
    if newmin < newmax: 
        return newmin + scale * (newmax - newmin) 
    else: 
        return newmin - scale * (newmin - newmax) 
 
c = CGBitmapContextCreateWithColor( 
    image_width, image_height, 
    CGColorSpaceCreateDeviceRGB(), 
    (1, 1, .8, 1)) 
 
# Translate [0,0] to the center of the image: 
c.translateCTM(image_width / 2.0, image_height / 2.0) 
 
for row in range(spiral_arm_count): 
    xpos = 0.0 
    c.saveGState() 
    c.rotateCTM(fit(row, 0, spiral_arm_count, 0, pi * 2)) 
    for i in range(circle_count): 
        c.saveGState() 
        c.rotateCTM(i * circle_rotation_increment) 
        c.setRGBFillColor(1, 0, 0, fit(i, 0, circle_count-1, 1, 0) ) 
        c.addArc(xpos * distance_between_circles, 0, xpos+1, 0, pi * 2, 1) 
        xpos += i 
        c.fillPath() 
        c.restoreGState() 
    c.restoreGState() 
 
c.writeToFile("spiral.tif", kCGImageFormatTIFF)