Re: Best way to composite/tile multiple CGImages to one image
Re: Best way to composite/tile multiple CGImages to one image
- Subject: Re: Best way to composite/tile multiple CGImages to one image
- From: Jim Crate <email@hidden>
- Date: Tue, 18 Mar 2014 10:22:10 -0400
On Mar 14, 2014, at 5:30 PM, Trygve Inda <email@hidden> wrote:
> So what is the best way to use CoreImage in this case?
>
> I get the original large CGImageRef using an AVImageGenerator which grabs a
> frame from a video file.
I would start with something like this:
CIImage *img = [CIImage emptyImage];
for … {
// calculate tile position from index, create NSAffineTransform for scaling/translating
CGImageRef tileRef = // get image from AV framework
CIImage *tile = [CIImage imageWithCGImage:tileRef];
CIFilter *f = [CIFilter filterWithName:@"CIAffineTransform"];
[f setValue:transform forKey:kCIInputTransformKey];
[f setValue:tile forKey:kCIInputImageKey];
tile = [f valueForKey:kCIOutputImageKey];
CIFilter *f = [CIFilter filterWithName:@"CISourceOverCompositing"];
[f setValue:img forKey:kCIInputBackgroundImageKey];
[f setValue:tile forKey:kCIInputImageKey];
img = [f valueForKey:kCIOutputImageKey];
// you’ll need to figure out whether it is safe to CGImageRelease your grabbed CGImageRef here
// or if you need to keep track of them and release them at the end of the process
}
// you’ll have to figure out your colorspace and bitmap info
CGColorSpaceRef colorSpace = CGImageGetColorSpace(imgRef);
CGBitmapInfo bitmapInfo = CGImageGetAlphaInfo(imgRef);
CGContextRef cgContext = CGBitmapContextCreate(NULL, destRect.size.width, destRect.size.height, 8, 0, colorSpace, bitmapInfo);
CIContext *ciContext = [CIContext contextWithCGContext:cgContext options:nil];
CGImageRef tiledImageRef = [ciContext createCGImage:img fromRect:[img extent]];
// save the image using ImageIO
CGImageDestinationRef destRef = CGImageDestinationCreateWithURL((__bridge CFURLRef)destURL, (__bridge CFStringRef)imageType, 1, NULL);
CGImageDestinationSetProperties(destRef, (__bridge CFDictionaryRef)propsDict);
CGImageDestinationAddImage(destRef, tiledImageRef, (__bridge CFDictionaryRef)propsDict);
CGImageDestinationFinalize(destRef);
CGImageRelease(imageRef);
CFRelease(destRef);
If you wanted better thumbnail image quality, you could use the Lanczos filter first, then just use the NSAffineTransform to translate the picture to the proper tile position. Also, I see there is an imageByApplyingTransform method that takes a CGAffineTransform, so it may be even simpler if you’d rather use that.
See the following URLs for more info:
https://developer.apple.com/library/mac/documentation/graphicsimaging/conceptual/CoreImaging/ci_intro/ci_intro.html
https://developer.apple.com/library/mac/documentation/graphicsimaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html
Another option would be to use:
- (void)generateCGImagesAsynchronouslyForTimes:(NSArray *)requestedTimes completionHandler:(AVAssetImageGeneratorCompletionHandler)handler
and do the CIImage processing in the completion handler. I’m not sure how you would determine that you were finished grabbing images, though, so that method may be more suited to the type of processing you would do if each frame grab was saved to an individual file, for instance. If you want to use multiple cores, it may be easier to use an NSOperationQueue and effectively process each run through the loop as an individual operation, and then you can generate the jpeg in a final operation that depends on the other operations finishing (very simple, but get it working first).
Jim
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden