Afternoon Apps: Captionator
A couple weeks ago, a friend of mine showed me the app I’d Cap That. After making some hilarious pictures, and after a few drinks, I made the claim that I could probably clone the app in a couple of hours.
So the other day, that’s what I tried to do. The app is very simple. It takes a randomly generated caption and burns it on to an image. You can pick an image from your camera or your library.
When I wrote the BD’s Mongolian BBQ app, I took stamps and burned them onto an image to create funny mustache pictures. The way I did that was to position UIImageViews inside of a UIView and then render the view to an image. That strategy works fine, but it also drops the image resolution down quite a bit. (It will be whatever the size of the view is)
So this time, I decided to render the text directly onto the image by hand. This involves getting a graphics context, drawing the image into it, then drawing the text into it, and finally getting the resulting UIImage from the graphics context.
My first approach was to use a UILabel to render the text onto the image. That would take care of all the font sizing issues and save some code. This worked great, until I had white text on a light image. There’s a couple ways to solve this problem like putting a stroke around the text or adding a shadow to the text. I’d Cap That uses a shadow. I decided to go for a more meme style look and stroke the text.
Unfortunately, UILabel doesn’t support adding a stroke around the text. So I looked for some classes online that might get the job done. I found a couple, but they didn’t work like I wanted. Luckily, CoreGraphics lets you draw stroked text, you just have to handle more by yourself.
-(UIImage*)getImage:(UIImage*)image withCaption:(NSString*)captionString
{
UIGraphicsBeginImageContext([image size]);
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
CGFloat captionFontSize = 300;
CGSize captionSize = [captionString sizeWithFont:[UIFont boldSystemFontOfSize:captionFontSize]];
while( captionSize.width > image.size.width )
{
captionFontSize -= 5;
captionSize = [captionString sizeWithFont:[UIFont boldSystemFontOfSize:captionFontSize]];
}
CGRect captionRect = CGRectMake((image.size.width - captionSize.width)/2.0, (image.size.height * .95)-captionSize.height, captionSize.width, captionSize.height);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
CGContextSetLineWidth(context, 3.0f);
CGContextSetTextDrawingMode(context, kCGTextFillStroke);
[captionString drawInRect:captionRect withFont:[UIFont boldSystemFontOfSize:captionFontSize]];
UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outputImage;
}
The problem with rendering the text yourself is that you need to size the font yourself. The way I’m doing it is picking a large font size (300 in this case) then measuring it and adjusting the font size until it fits on the image. There’s likely a better way, but this works and is fast enough.
I haven’t decided if I’m gonna release this app or not, like I did with my other Afternoon Apps. I have the source code up on GitHub though, so feel free to take a look and use whatever you want from it.
There’s some issues with it. The camera view doesn’t work quite right. There aren’t any icons. One little feature in there is you can add to the list of captions. Of course the real secret sauce of I’d Cap That isn’t the app, it’s the hilarious captions.