No doubt you're excited about the new iPad being released next Friday. Me too! I've been hoping for an iPad with a Retina display since the days of the original iPad. In celebration, here are a few tips to make creating your images a little easier. These of course work for iPhone too.
{emailcloak=off}First, it goes without saying (but I'll say it anyway), you need to create the high res version of the image to start with. I use Adobe's Illustrator and Photoshop for most of my graphics. (Actually, my Wife uses Illustrator mostly, while I import her stuff into Photoshop for any pixel level tweaks and to ensure sizes are consistent etc). For the most part, that means I have images in Photoshop with one image per layer. I use one .psd file for all images of the same size in the app.
When I have a part of the app that needs multiple images, say for a menu, each menu item will be on it's own layer, if there are separate overstate images, they also get their own layer.
Make sure your canvas width and heights are even numbers. If you have an odd number you'll get slight cosmetic errors and off by 1 pixel effects.
Name the layer with the desired filename for that image. Eg: btnMenuItem1@2x etc. Make sure you include the @2x part.
Now you can use Photoshop's Export Layers as Files script to quickly create PNG's of all the images in your .psd file. Leave the File Prefix blank, and make sure you uncheck the 'Trim Layers' option which is always defaulted to on or some of your image sizes will be altered and could end up odd.
Next you're going to need to do some setup.
Setup Step 1: We're going to use the awesome ImageMagick tools, so you'll need to install them. The quickest way is to use MacPorts, follow the instructions here.
Setup Step 2: Copy the following script to somewhere in your path. I use ~/bin, but other options will work.
~/bin/1x (Download):
#!/bin/bash ## Copyright (C) 2012 Cerebral Gardens http://www.cerebralgardens.com/ ## ## Permission is hereby granted, free of charge, to any person obtaining a copy of this ## software and associated documentation files (the "Software"), to deal in the Software ## without restriction, including without limitation the rights to use, copy, modify, ## merge, publish, distribute, sublicense, and/or sell copies of the Software, and to ## permit persons to whom the Software is furnished to do so, subject to the following ## conditions: ## ## The above copyright notice and this permission notice shall be included in all copies ## or substantial portions of the Software. ## ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, ## INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ## PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ## HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF ## CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE ## OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. CONVERT=/opt/local/bin/convert IDENTIFY=/opt/local/bin/identify if [ $# -lt 1 ] ; then echo "Usage: ${0} filename@2x.ext" exit fi for ARG in "$@"; do FILEPATH=`dirname "${ARG}"` FILENAME=`basename "${ARG}"` FULLNAME=${FILEPATH}/${FILENAME} PHOTOSHOPTEST=${FILENAME#_[0-9][0-9][0-9][0-9]_} if [ "${PHOTOSHOPTEST}" != "${FILENAME}" ] ; then mv "${FULLNAME}" "${FILEPATH}/${PHOTOSHOPTEST}" SOURCEFILE=${PHOTOSHOPTEST} else SOURCEFILE=${FILENAME} fi IMAGENAME=`expr "${SOURCEFILE}" : '\(.*\)@2x.png'` EXTENSION=`expr "${SOURCEFILE}" : '.*@2x.\(png\)'` DESTFILE=${IMAGENAME}.${EXTENSION} FAILNAME=. BLANKS=" " if [ "${DESTFILE}" != ${FAILNAME} ] ; then ${CONVERT} "${FILEPATH}/${SOURCEFILE}" -resize 50% "${FILEPATH}/${DESTFILE}" FILENAME_LENGTH=${#IMAGENAME} SOURCE_WIDTH=`${IDENTIFY} -format "%W" "${FILEPATH}/${SOURCEFILE}"` SOURCE_HEIGHT=`${IDENTIFY} -format "%H" "${FILEPATH}/${SOURCEFILE}"` DEST_WIDTH=`${IDENTIFY} -format "%W" "${FILEPATH}/${DESTFILE}"` DEST_HEIGHT=`${IDENTIFY} -format "%H" "${FILEPATH}/${DESTFILE}"` echo "${IMAGENAME} - @2x : ${SOURCE_WIDTH}x${SOURCE_HEIGHT}" echo "${BLANKS:1:${FILENAME_LENGTH}} @1x : ${DEST_WIDTH}x${DEST_HEIGHT}" else echo "Skipping: " "${FULLNAME}" fi done
Once you're setup, and after running the export script, you'll have a series of files in the export folder with names like _0000_btnMenuItem1@2x.png, _0001_btnMenuItem2@2x.png etc. Drop to a terminal in that folder (Go2Shell works great for this). And run the script you created above for each file you've exported. You can do this one file at a time:
1x _0001_btnMenuItem2\@2x.png
or for a collection of files at once,
1x *
What this script does, is chop off the _xxxx_ part of the filename (if it's there), then create a @1x version of the image with the appropriate filename. It will skip any file that doesn’t match the filename@2x.ext format.
The script will also print out the original image dimensions along with the new image dimensions as a quick way to ensure you don't have an odd sized image. (It's ok for the @1x image to have odd dimensions).
Take a look at the sizes of your final images. Apple recommends using PNG files, but they're not always the best solution. Some images just do not compress well as PNG files and are better suited as JPG files (assuming you don't need alpha transparency). For example, an @2x image in my upcoming iPad game was over 5 mb in size as a PNG and just 305 kb as a JPG. There is no discernible difference in the way the file looks or behaves as a JPG, but 10 million users (fingers crossed) will each save 6 mb of space on their iPads (the @1x version went from 1.3 mb to 85 kb).
Check out Slender in the Mac App Store. Run your project through it and it'll catch any odd size images, or extra images you're no longer referencing in your app. It can even automatically remove the extra images from your project for you (saving a backup first of course).
On a completely unrelated note, we've launched a Cerebral Gardens Facebook page. If you use Facebook, it would be swell if you'd head over there and do the like thing. Thanks!