Archive

Posts Tagged ‘objective-c’

Slicing Images With Objective-C

September 22nd, 2010 4 comments

I had a project come across my path recently that needed to implement an optimized photo viewer. To do this, displaying full sized images in the viewer wasn’t very performance friendly so I went with the method of tiled scroll views, like Google Maps uses. I found some code for the photo viewer, of which needed tweaking, but the real challenge was to get these images that were already in the app at full resolution, sliced up into 4 different levels of slices and saved to an individual folder for each photo (for organizational purposes).

So, I looked around on the net and couldn’t find anything useful for this specific purpose so I wrote my own method to do all the work. This method could be run in a loop of the image array or it could be run at the first viewing of each photo.

What the script does is takes a single photo. It then re-sizes this photo 3 different times. Each time the photo is re-sized it loops through columns and rows of the image cropping out 256x256px squares and saving them. Also, it will slice smaller sized tiles for the end column and the bottom rows if the images width or height is not divisible by 256. The 4th level of zoom does not get re-sized, it just slices up the full resolution image.

Above is an example showing Zoom Level 1 (left, fully zoomed out), Zoom Level 2 (middle), and Zoom Level 4 (right, fully zoomed in).

You could tweak the script to have smaller tiles, save as jpg instead of png, have more levels of zoom, save in a different folder hierarchy, etc… This is just the basics for what I needed to get the photo viewer to work.

One thing to note is I’m using some great UIImage Categories from here for resizing the image and cropping out the tiles. You just need to include those in your project and #import “UIImage+Resize.h”

The method is below:

-(void)sliceImageToPieces:(UIImage*)imageToSlice imageName:(NSString*)filename{
    NSArray *sysPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
    NSString *documentPath = [sysPaths objectAtIndex:0];
    NSString *tileImagePath = [documentPath stringByAppendingPathComponent:@"tileImages"];
    BOOL isFolder = YES;
    if (![[NSFileManager defaultManager] fileExistsAtPath:tileImagePath isDirectory:&isFolder]) {
        [[NSFileManager defaultManager] createDirectoryAtPath:tileImagePath withIntermediateDirectories:NO attributes:nil error:nil];
    }
    NSString *imageTilesPath = [tileImagePath stringByAppendingPathComponent:filename];
    if (![[NSFileManager defaultManager] fileExistsAtPath:imageTilesPath isDirectory:&isFolder]) {
        [[NSFileManager defaultManager] createDirectoryAtPath:imageTilesPath withIntermediateDirectories:NO attributes:nil error:nil];
        UIImage *theImage = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:filename ofType:@"jpg"]];
    }
 
    int zoom = 125;
    for(int z=0;z<4;z++){
    if(z != 0)zoom = zoom*2;
        int zoomLevelWidth;
        int zoomLevelHeight;
        switch (z) {
            case 0:
                zoomLevelWidth = (imageToSlice.size.width/4)/2;
                zoomLevelHeight = (imageToSlice.size.height/4)/2;
                break;
            case 1:
                zoomLevelWidth = imageToSlice.size.width/4;
                zoomLevelHeight = imageToSlice.size.height/4;
                break;
            case 2:
                zoomLevelWidth = (imageToSlice.size.width/4)*2;
                zoomLevelHeight = (imageToSlice.size.height/4)*2;
                break;
            default:
                zoomLevelWidth = imageToSlice.size.width;
                zoomLevelHeight = imageToSlice.size.height;
                break;
        }
        UIImage *sizedImage = [imageToSlice resizedImageWithContentMode:UIViewContentModeScaleAspectFit bounds:CGSizeMake(zoomLevelWidth, zoomLevelHeight) interpolationQuality:kCGInterpolationHigh];
        int imageWidth = sizedImage.size.width;
        int imageHeight = sizedImage.size.height;
        int colIterations = ceil((float)imageWidth/256);
        int rowIterations = ceil((float)imageHeight/256);
        for (int col=0; col<colIterations; col++) {
            int x = 256*col;
            int rectWidth;
            if(imageWidth-x < 256){
                rectWidth = imageWidth-x;
            }else {
                rectWidth = 256;
            }
            for (int row=0; row<rowIterations; row++) {
                int y = 256*row;
                int rectHeight;
                if(imageHeight-y < 256){
                    rectHeight = imageHeight-y;
                }else {
                    rectHeight = 256;
                }
                CGRect rect = CGRectMake(x, y, rectWidth, rectHeight);
                UIImage *imageTile = [sizedImage croppedImage:rect];
 
                NSData *newImage = UIImagePNGRepresentation(imageTile);
                NSString *newImagePath = [imageTilesPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%i_%i_%i.png",filename,zoom,col,row]];
                [newImage writeToFile:newImagePath atomically:YES];
            }
        }
    }
}

As always, if you have any questions, leave them in the comments and I’ll try to get you a good answer :)

Categories: iPhone Dev Tags: ,