I'm currently working a lot with CoreGraphics on OSX.
I've run Time Profiler over my code and found the biggest hang-up is in CGContextDrawImage. It's part of a loop that gets called many times per second.
I don't have any way of optimizing this code per se (since it's in the Apple libraries) - but I am wondering if there's a speedier alternative or way to improve the speed.
I'm using CGContextDraw image after some blend-mode code such as: CGContextSetBlendMode(context, kCGBlendModeDifference);
so alternative implementations would need to be able to support blending.
Time profiler results:
3658.0ms 15.0% 0.0 CGContextDrawImage
3658.0ms 15.0% 0.0 ripc_DrawImage
3539.0ms 14.5% 0.0 ripc_AcquireImage
3539.0ms 14.5% 0.0 CGSImageDataLock
3539.0ms 14.5% 1.0 img_data_lock
3465.0ms 14.2% 0.0 img_interpolate_read
2308.0ms 9.4% 7.0 resample_band
1932.0ms 7.9% 1932.0 resample_byte_h_3cpp_vector
369.0ms 1.5% 369.0 resample_byte_v_Ncpp_vector
1157.0ms 4.7% 2.0 img_decode_read
1150.0ms 4.7% 8.0 decode_data
863.0ms 3.5% 863.0 decode_swap
267.0ms 1.0% 267.0 decode_byte_8bpc_3
Update:
The actual source is something along the lines of the following:
/////////////////////////////////////////////////////////////////////////////////////////
- (CGImageRef)createBlendedImage:(CGImageRef)image
secondImage:(CGImageRef)secondImage
blendMode:(CGBlendMode)blendMode
{
// Get the image width and height
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
// Set the frame
CGRect frame = CGRectMake(0, 0, width, height);
// Create context with alpha channel
CGContextRef context = CGBitmapContextCreate(NULL,
width,
height,
CGImageGetBitsPerComponent(image),
CGImageGetBytesPerRow(image),
CGImageGetColorSpace(image),
kCGImageAlphaPremultipliedLast);
if (!context) {
return nil;
}
// Draw the image inside the context
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextDrawImage(context, frame, image);
// Set the blend mode and draw the second image
CGContextSetBlendMode(context, blendMode);
CGContextDrawImage(context, frame, secondImage);
// Get the masked image from the context
CGImageRef blendedImage = CGBitmapContextCreateImage(context);
CGContextRelease(context);
return blendedImage;
}
/////////////////////////////////////////////////////////////////////////////////////////
- (CGImageRef)createImageTick
{
// `self.image` and `self.previousImage` are two instance properties (CGImageRefs)
// Create blended image (stage one)
CGImageRef stageOne = [self createBlendedImage:self.image
secondImage:self.previousImage
blendMode:kCGBlendModeXOR];
// Create blended image (stage two) if stage one image is 50% red
CGImageRef stageTwo = nil;
if ([self isImageRed:stageOne]) {
stageTwo = [self createBlendedImage:self.image
secondImage:stageOne
blendMode:kCGBlendModeSourceAtop];
}
// Release intermediate image
CGImageRelease(stageOne);
return stageTwo;
}
@JeremyRoman et al: Thank you so much for your comments. I am drawing the same image a couple of times per loop, onto different contexts with different filters, and combining with new images. Does resampling include switching from RGB to RGBA? What could I try to speed up or eliminate resampling? – Chris Nolet
This is what Core Image is for. See the Core Image Programming Guide for details. CGContext
is designed for rendering final images to the screen, which it sounds like is not your goal with every image you're creating.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With