views:

354

answers:

1

I'm trying to speed up my drawing code. Instead of creating a graphics context, drawing the current image into it, and drawing over it, I'm trying to create a context using some pixel data, and just modify that directly. The problem is, I'm pretty new to core graphics and I can't create the initial image. I want just a solid red image, but I get nothing. Here's what I'm using for the initial image. I assume the problem will be the same with the rest of the code.

pixels = malloc(320*460*4);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pixels, 320, 460, 8, 4*320, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);

CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextAddRect(context, CGRectMake(0, 0, 320, 460));
CGContextFillPath(context);
trace = [[UIImageView alloc] initWithImage:UIGraphicsGetImageFromCurrentImageContext()];
CGContextRelease(context);

Edit: UIGraphicsGetImageFromCurrentImageContext() turned out to be the problem. A working solution follows, but note that this is no faster than the much simpler UIGraphicsBeginImageContext()

pixels = malloc(320*460*4);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pixels, 320, 460, 8, 4*320, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextAddRect(context, CGRectMake(0, 0, 320, 460));
CGContextFillPath(context);
CGDataProviderRef dp = CGDataProviderCreateWithData(NULL, pixels, 320*460*4, NULL);
CGImageRef img = CGImageCreate(320, 460, 8, 32, 4*320, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big, dp, NULL, NO, kCGRenderingIntentDefault);
trace = [[UIImageView alloc] initWithImage:[UIImage imageWithCGImage:img]];
CGImageRelease(img);
CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
+1  A: 

For starters, it seems like the context you're drawing to is unconnected to the UIGraphics "current image context". Have you called UIGraphicsBeginImageContext(CGSize size) somewhere?

Not sure that will get you what you need, but it certainly means you're less likely to get nil back as the current image context.

quixoto
The problem is if I use that, then to draw to it I need to use `UIGraphicsGetCurrentContext()` which doesn't allow me to use the pixel data I have, but thanks for pointing me in the right direction. I'll try to replace `UIGraphicsGetImageFromCurrentImageContext()`
David Kanarek
I think I'm a little unsure what you're fundamentally trying to accomplish here. Why can't you have a UIView subclass as usual and fill your background inside the drawRect: call? Where does the image/bitmap requirement come from?
quixoto
I think I'm going to have to try that route. Because these updates happen so fast, it takes too long to redraw the whole image. I was hoping to use the same source data and just change a small amount of it. Sadly, your answer did get me going in the right direction, but that route turns out to be too slow as well. I'm giving you credit because you found the problem and led me to the solution. Thanks for your help.
David Kanarek
Updated the question with a solution.
David Kanarek
Again, not sure what exactly you're shooting for here, but do note that in the normal view redraw path, drawRect: gets the invalid rect as its argument. You only need to redraw the part that's requested. If you're moving stuff around and have frame rate problems because you're rebuilding the entire window every frame, you might get better performance if you limit redraw to the invalid rect. Conversely, you can explicitly invalidate a sub-rect of the window with setNeedsDisplayInRect:Hope that's helpful.
quixoto
Indeed it is. It's going to be some time before I can get it tested, but I'm hopeful the partial updates will improve performance. Thanks again.
David Kanarek