Another Cocoa technology I had to battle with

So, I was messing around with a Cocoa app I created to test out some imaging code I had created. The point of this code was to deliver a really large image in smaller tiles and the Cocoa app would take those images and stitch them together into one large image. Now, the code I wrote delivered these small tiles quickly, and the point of the code was to handle the tiles, not to deliver one big image, so I used NSImage to put these tiles together.

Now… that didn’t work out too well. After many attempts, debugging and coding permutations, I realized that NSImage might not have been the best choice for drawing for one reason: it’s not that fast.

So, on to the web. After some digging around, and some patient reading, I found that CGImage would be the better way to go. Great! Now I have to admit, all of the projects I have done in the past were with whole images, not diced up ones. So, looking at the Cocoa API, I wondered, how do I draw just one Rect.

Now, before I go any further, I would like to point out something. I don’t write about anything unless I had a hard time finding information about something and I couldn’t find it on the web. And to my surprise, I really couldn’t find that much information about tiling images.

Okay, so, back to my problem. I implemented tiled drawing, and it wasn’t too hard to do, but then I started having some problems. My original code was expecting only one tile at a time to be drawn in. However, there were sections of the image that were not being drawn.

My - (void)drawRect:(NSRect)inrect method was being called every time, or at least from what I could see, but, tiles were still missing.

So what gives?

Well, by accident I found out that you can get more than one tile at a time. Cocoa tries to make the drawing as efficient as possible if it detects that it can draw two or more tiles at the same time. So, I also had to use:

- (void)getRectsBeingDrawn:(const NSRect **)rects count:(NSInteger *)count

This method tells me how many tiles were given to me, so instead of only drawing one tile, I was now able to draw many tiles:

- (void)drawRect:(NSRect)inrect
{
	/* Prevent anyone else from trying to update the view by locking our mutex*/
	[self lockMyView];

	/* Get the array of rects Cocoa wants us to draw */
	const NSRect* 	arrayOfRects;
    NSInteger		countOfTiles;
	[self getRectsBeingDrawn:&arrayOfRects tileCount:&countOfTiles];

	if (countOfTiles==1)
	{
		/* We only have one tile to draw... easy! */
		[self drawMyTile:(*arrayOfRects)];
	}
	else
	{
		/* We have more than one tile to draw. */
		for (int i = 0; i <= countOfTiles; i++ )
		{
			NSRect currentRect;
			currentRect.origin.x = arrayOfRects[i].origin.x;
			currentRect.origin.y = arrayOfRects[i].origin.y;
			currentRect.size.width = arrayOfRects[i].size.width;
			currentRect.size.height = arrayOfRects[i].size.height;
			
			[self drawMyTile:currentRect];
		} 
	}

	/* It is now safe to allow view updates */
	[self unlockMyView];
}

Alright! Another problem solved!

Leave a Reply

Your email address will not be published. Required fields are marked *