Merging/stacking two images with Cocoa/OSX
For a quick 'n dirty solution you can use the NSImage drawing APIs:
NSImage *background = [NSImage imageNamed:@"background"];
NSImage *overlay = [NSImage imageNamed:@"overlay"];
NSImage *newImage = [[NSImage alloc] initWithSize:[background size]];
[newImage lockFocus];
CGRect newImageRect = CGRectZero;
newImageRect.size = [newImage size];
[background drawInRect:newImageRect];
[overlay drawInRect:newImageRect];
[newImage unlockFocus];
CGImageRef newImageRef = [newImage CGImageForProposedRect:NULL context:nil hints:nil];
If you don't like that, most of the CGContext APIs you'd expect are available cross platform—for drawing with a little more control. Similarly, you could look into NSGraphicsContext.
If anyone, like me, needs a Swift version.
This is a functional Swift 5 version:
let background = NSImage(named: "background")
let overlay = NSImage(named: "overlay")
let newImage = NSImage(size: background.size)
newImage.lockFocus()
var newImageRect: CGRect = .zero
newImageRect.size = newImage.size
background.draw(in: newImageRect)
overlay.draw(in: newImageRect)
newImage.unlockFocus()
I wish I had the time to do the same with the CGContext example.
This is pretty easy when you render to a CGContext
.
If you want an image as a result, you can create and render to a CGBitmapContext
, then request the image after render.
General flow, with common details and contextual info omitted:
CGImageRef CreateCompositeOfImages(CGImageRef pBackground,
const CGRect pBackgroundRect,
CGImageRef pForeground,
const CGRect pForegroundRect)
{
// configure context parameters
CGContextRef gtx = CGBitmapContextCreate( %%% );
// configure context
// configure context to render background image
// draw background image
CGContextDrawImage(gtx, pBackgroundRect, pBackground);
// configure context to render foreground image
// draw foreground image
CGContextDrawImage(gtx, pForegroundRect, pForeground);
// create result
CGImageRef result = CGBitmapContextCreateImage(gtx);
// cleanup
return result;
}
You would need to create a CGImage from your PNG.
Additional APIs you may be interested in using:
CGContextSetBlendMode
CGContextSetAllowsAntialiasing
CGContextSetInterpolationQuality
.
I know a lot of people will generally advise you to use higher level abstractions (i.e. AppKit and UIKit), but CoreGraphics is a great library for rendering in both of those contexts. If you are interested in graphics implementations which are easy to use in both OS X and iOS, CoreGraphics is a good choice to base your work upon if you are comfortable working with those abstractions.