iOS 5 By Tutorials ebook

Blog Archives

Transparent JPEG Images

When you distribute images with your app you usually pick the PNG or JPEG format. The advantage of JPEG is that it often compresses better — especially for photos — but unlike PNG it unfortunately does not support transparency.

The transparency in a PNG file comes from the so-called “alpha channel”. For every pixel not only red, green and blue values are stored but also an “alpha” value that determines how transparent that pixel is. A value of 255 means this pixel is fully opaque, 0 is fully transparent, and anything in between will mix the pixel’s RGB values with the underlying color.

This is probably an old trick, but by saving a JPEG image not as one but as two image files you can still have transparent images. The first image is the regular JPEG with as much compression as you can get away with, the second image is the alpha channel. This is a grayscale image with black representing fully transparent, white fully opaque, and gray everything in between.

 

Source image and its alpha channel
We can combine these two images at runtime to make the image transparent again. Because of the JPEG compression we lose a little bit of clarity but if you tweak the compression settings you can usually get away with it.

I wrote a simple category on UIImage that lets you do this.

Preparing your images

1) Export your image from Photoshop as a PNG with transparency.

2) Export the image again as a JPEG, using suitable compression settings. The background should have a solid color, typically white or black but any color will do.

3) Save the alpha channel to a separate JPEG or PNG image. I couldn’t find an easy way to do this from Photoshop, but the ImageMagick tool can do it without problems.

If you have ImageMagick installed, open a Terminal and go to the folder that contains the exported PNG image. Then type:

convert -alpha Extract -type optimize -strip -quality 60 +dither \
    Source.png Alpha.jpg

This extracts the alpha channel from the PNG image and saves it as a JPEG file. You can tweak the level of compression with the -quality parameter. If you specify “Alpha.png” instead of “Alpha.jpg”, ImageMagick saves the alpha channel as a grayscale PNG-8 file. You should use whichever one makes the smallest file size.

Combining the images

1) Add the two JPEG images (the non-transparent source image and the alpha channel) to the app.

2) At some point, call the mh_combineWithAlphaImage:backgroundColor: method to combine these two images into a new, transparent, image.

3) Depending on your app you may want to do this only once and then store the transparent image as a PNG in your app’s Caches folder.

That’s it, quite easy.

Some notes

The alpha image does not have to be a JPEG, it can also be a PNG file. If it is a JPEG then it can have different quality/compression settings from the main image.

The current implementation works well but is not as fast as it could be. It also uses more memory than is strictly necessary. I might rewrite this at some point to use the Accelerate framework or Core Image.

Not all images compress better as JPEG. You should use JPEG only where it makes sense.

Check out the source code at Github.

Bird image by Sias van Schalkwyk

 

MHTabBarController – A custom tab bar for iOS 5 using the new container APIs

Creating your own container view controllers, i.e. view controllers that can contain other view controllers, used to be a pain but now iOS 5 makes it a lot easier.

Especially for iPad apps that is great, because all of that screen space means you probably want to divide it up amongst more than one view controller.

Today I was messing around with these new container APIs and built my own tab bar controller. It works just like a regular UITabBarController, except the tabs look quite different and the pages slide in and out of the screen with a nice animation.

Screenshot of MHTabBarController in the demo app
If you want to learn more about how to do this, then check out the source code or get the iOS 5 by Tutorials ebook. It has a full chapter on these new view controller containment APIs, plus twenty or so other chapters on more iOS 5 goodness!

Making UIBarButtonItems in Photoshop

Recently I was working on an app that required brightly tinted tool bars and navigation bars:

A UIToolBar with a light blue tint color

As you can see, the light blue color makes the bar button hard to see and its label hard to read. Changing the background color of the button is really easy on iOS 5 because its UIBarButtonItem also has a .tintColor property. But if you still need to support iOS 4 then you’re out of luck.

In that case, the only solution is to put a UIButton inside the UIBarButtonItem and give it a background image that looks like a regular bar button. It’s a roundabout way of doing things but it works.

Previously, I would draw these bar button-lookalike images myself in Photoshop. By setting the appropriate layer styles on a rounded rectangle vector object you can make a decent approximation of what a real bar button item looks like.

This time, however, I wanted to take advantage of the actual images that UIKit itself uses to compose the UIBarButtonItem when you change the tintColor of the underlying toolbar or navigation bar.

To pull this off, you can download UIKit Artwork Extractor. Compile the app and run it on the Simulator (or on your device). It will extract all the images that are built into the various iPhone and iPad frameworks and save them to a folder on your computer.

After you have extracted the images, go into the “Shared” subfolder and look for:

  • UITintedButtonHighlight.png
  • UITintedButtonMask.png
  • UITintedButtonShadow.png

You can combine these three images with a fill color to produce a tinted UIBarButtonItem background image, like this:

How to add the different images to produce the final bar button image

The actual layers pane should look like this:

The Layers pane in Photoshop

The “Fill color” layer is simply a rectangle filled with the tint color that you want the button to have. As you can see, both the fill layer and the “shadow” layer are clipped against the red “mask” layer. If you don’t do that, the button won’t have a transparent background in the corners.

To export the image, merge all the visible layers (but not the background!) and save the image as PNG. This gives you a 11×30 pixels stretchable image.

You can use the following category to create the fake bar button items in your code. It requires that the image named “BarButton.png” is added to your project.

@implementation UIBarButtonItem (FakeButtons)
 
- (id)initWithTitle:(NSString *)title width:(CGFloat)width target:(id)target action:(SEL)action
{
	UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
	[button setTitle:title forState:UIControlStateNormal];
	[button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
	button.titleLabel.font = [UIFont boldSystemFontOfSize:12];
	button.titleLabel.shadowColor = [UIColor colorWithWhite:0 alpha:0.5];
	button.titleLabel.shadowOffset = CGSizeMake(0, -1);
	button.frame = CGRectMake(0, 0, width, 30);
 
	UIImage *image = [[UIImage imageNamed:@"BarButton"] stretchableImageWithLeftCapWidth:5 topCapHeight:0];
	[button setBackgroundImage:image forState:UIControlStateNormal];
 
	return (self = [self initWithCustomView:button]);
}
 
@end

In the “Shared” folder you will also find images for the UINavigationController back button (named UITintedBackButtonXXX.png), but be advised that bar button items with a custom view won’t work on UINavigationItem’s backBarButtonItem property. You’ll have to put your custom back button on leftBarButtonItem instead.

Tip: If you also want to have Retina-sized images, run Artwork Extractor on a Retina device or on the Simulator in Retina mode. It’s very enlightening to look through the rest of the extracted artwork as well.

Drawing Retina Graphics

Since the arrival of the iPhone 4, developers need to put two versions of each image into their apps: a low-resolution “Image.png” for all previous iPhone models and a high-resolution “Image@2x.png” for the iPhone 4′s Retina screen.

There are several strategies for creating these higher-resolution images:

  1. Draw the image using vectors at 1x scale and scale up 200% to get the Retina image.
  2. Draw the image using vectors at 2x scale and scale down 50% to get the low-res image.
  3. Draw the image using pixels at 2x scale and scale down. You can also combine pixels and vectors.
  4. Draw the 1x and 2x images separately, either as vectors or bitmaps.

Ideally, you’d use vectors for everything because they scale better than bitmaps. Vector graphics can scale up or down without quality loss. However, if your image includes a texture background then you’ll need to use a bitmap anyway. Just never scale bitmaps up, only down. Continue reading…

MHNibTableViewCell, Easily Load Table View Cells from NIB Files

Most iOS projects use a table view somewhere. Often the standard table view cell types are sufficient to present your data, but sometimes you need more complex cells. You can do this programmatically but I prefer to use Interface Builder.

After typing the same nib loading code over and over, I decided to abstract it into a class, MHNibTableViewCell. This class makes it very easy to use table view cells that are completely designed in Interface Builder.

Continue reading…