Friday, May 25, 2012

Quartz (2)

This second Quartz example is really more about arrays than drawing. I made a simple category on NSArray that returns a random object from any array. We set up three arrays from which to grab random values for the color, the origin and the size of a rectangle to draw. Both the origins and sizes need to be wrapped into NSValue objects in order to store them into the arrays. The original structs can then be retrieved by reference.

In a similar way, the rgb and alpha values are recovered from the NSColor to provide them to CGContextSetRGBFillColor. In playing around with the code I decided to bias toward higher values of red. We use a venerable C construct for that.

// clang x.m -o prog -framework Cocoa -fobjc-gc-only
#import <Cocoa/Cocoa.h>

CGContextRef setup(){
    NSString *s = [NSString stringWithUTF8String:"x.pdf"];
    NSURL *url = [NSURL fileURLWithPath:s];
    CGContextRef ctx = NULL;
    ctx = CGPDFContextCreateWithURL (

    CGRect rect = CGRectMake (0, 0, 500, 400);              
    CGContextBeginPage(ctx, &rect);
    return ctx;

@interface NSArray (RandomChoiceArray)
- (id)getRandomObject;

@implementation NSArray (RandomChoiceArray)
- (id)getRandomObject {
    int n = [self count];
    int i = (random() % n);
    return [self objectAtIndex:i];
- (void)testRandom:(int)n {
    for (int i = 0; i < n; i++) {
        NSLog(@"%@", [[self getRandomObject] description]);

int main(int argc, char * argv[]) {
    CGContextRef ctx = setup();
    NSColorList *CL;
    CL = [NSColorList colorListNamed:@"Crayons"];
    NSArray *colorNames = [CL allKeys];
    //[colorNames testRandom:10];
    NSSize hz, vt;
    hz = NSMakeSize(150,50);
    vt = NSMakeSize(50,150);
    NSValue *v, *h;
    h = [NSValue value:&hz withObjCType:@encode(NSSize)];
    v = [NSValue value:&vt withObjCType:@encode(NSSize)];
    NSArray *sizes = [NSArray arrayWithObjects:h, v, nil];
    //[sizes testRandom:4];
    NSMutableArray *ma;
    ma = [NSMutableArray arrayWithCapacity:10];
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            int x = i*50;
            int y = j*50;
            NSPoint pt = NSMakePoint(x,y);
            NSValue *p;
            p = [NSValue value:&pt withObjCType:@encode(NSPoint)];
            [ma addObject:p];
    NSArray *origins = [NSArray arrayWithArray:ma];
    //[origins testRandom:10];
    CGFloat r, g, b, a, m;
    m = 0.7;
    for (int i = 0; i < 250; i++) {
        NSString *c = [colorNames getRandomObject];
        NSColor *color = [CL colorWithKey:c];
        id obj = [origins getRandomObject];
        NSPoint pt;
        [obj getValue:&pt];
        NSSize sz;
        obj = [sizes getRandomObject];
        [obj getValue:&sz];
        CGRect rect = CGRectMake(pt.x,pt.y,sz.width,sz.height); 
        //NSLog (@"%@", NSStringFromRect(r));
        [color getRed:&r green:&g blue:&b alpha:&a];
        r = r < m ? m : r;
        CGContextSetRGBFillColor (ctx,r,g,b,a);
        CGContextFillRect (ctx,rect);
    return 0;