0

Currently, trying to download the images through URLs and tiling those images in the way of how PhotoScroller app has been done by Apple store. The largest image size is 4000 * 4000 and is in RGB format. I am tiling those images with tilesize 256 * 256. It takes a very long time to tile the image and write the files on the disk. Was looking for a better approach if its possible to tile the files and load on iphone. Total of 4 URL calls and each URL call fetches an image and passes through tiling process and calls PhotoScroller app to launch those images on iphone.

If anyone has come across such issues and know more about it, can you share some ideas.

-(void) startImageDownloading
{

if (!isImageRequested)
{
    isImageRequested = YES;
    self.responseData = [NSMutableData data];

    URL1 = @"http://www.abc.com/image_id=1&size=1"; 
    NSURLRequest *request1 = [NSURLRequest requestWithURL:[NSURL URLWithString:URL1]];
    self.connection1= [[[NSURLConnection alloc] initWithRequest:request1 delegate:self] autorelease];

    URL2 = @"http://www.abc.com/image_id=2&size=2"; 
    NSURLRequest *request2 = [NSURLRequest requestWithURL:[NSURL URLWithString:URL2]];
    self.connection2= [[[NSURLConnection alloc] initWithRequest:request2 delegate:self] autorelease];

    URL3 = @"http://www.abc.com/image_id=3&size=3"; 
    NSURLRequest *request3 = [NSURLRequest requestWithURL:[NSURL URLWithString:URL3]];
    self.connection3= [[[NSURLConnection alloc] initWithRequest:request3 delegate:self] autorelease];


    URL4 = @"http://www.abc.com/image_id=4&size=4";     
    NSURLRequest *request4 = [NSURLRequest requestWithURL:[NSURL URLWithString:URL4]];
    self.connection4= [[[NSURLConnection alloc] initWithRequest:request4 delegate:self] autorelease];

}

}



- (void)saveTilesOfSize:(CGSize)size 
           forImage:(UIImage*)image 
        toDirectory:(NSString*)directoryPath 
        usingPrefix:(NSString*)prefix
   {

CGFloat cols = [image size].width / size.width;
CGFloat rows = [image size].height / size.height;

int fullColumns = floorf(cols);
int fullRows = floorf(rows);

CGFloat remainderWidth = [image size].width - (fullColumns * size.width);
CGFloat remainderHeight = [image size].height - (fullRows * size.height);


if (cols > fullColumns) fullColumns++;
if (rows > fullRows) fullRows++;

CGImageRef fullImage = [image CGImage];

for (int y = 0; y < fullRows; ++y) {
    for (int x = 0; x < fullColumns; ++x) {

        CGSize tileSize = size;

        if (x + 1 == fullColumns && remainderWidth > 0) {
            // Last column
            tileSize.width = remainderWidth;
        }
        if (y + 1 == fullRows && remainderHeight > 0) {
            // Last row
            tileSize.height = remainderHeight;
        }

        CGImageRef tileImage = CGImageCreateWithImageInRect(fullImage,(CGRect){{x*size.width, y*size.height},tileSize});

        NSData *imageData = UIImagePNGRepresentation([UIImage imageWithCGImage:tileImage]);
        CGImageRelease(tileImage);
        NSString *path = [NSString stringWithFormat:@"%@/%@%d_%d.png",directoryPath, prefix, x, y];

        [imageData writeToFile:path atomically:NO];

    }
}    
}
lifemoveson
  • 1,661
  • 8
  • 28
  • 55

2 Answers2

1

Since your images are 4000 x 4000 and in RGB the downloading and tiling is going to take a long time on the iPhone for sure because it is a CPU intensive calculation.

I have seen substantial improvements for saving the file by switching from UIImagePNGRepresentation to UIImageJPEGRepresentation so you could try that.

For the tiling the best way to solve it is to do it on the server and not on the iphone.

werner
  • 859
  • 4
  • 8
  • I did try UIImageJEPGRepresentation and it did not solve my problem. I can think of tiling the images on the server than on the iphone. – lifemoveson Jun 29 '11 at 14:10
  • tiling the images on the server will be your best approach, there is a blogpost from Jeff Lamarche on image tiling [here](http://iphonedevelopment.blogspot.com/2010/10/cutting-large-images-into-tiles-for.html) – werner Jun 29 '11 at 18:34
  • Thanks werner. But if I have to get those tiled images which are like real data meaning the images change frequently and have to be updated, how can I achieve it. Since the images which I get from the URL are like real live data. And for that reason I was tiling each time I get updated data from the server. – lifemoveson Jun 29 '11 at 19:43
1

Seems like you are reconstructing the whole image then saving it to disk for every tile (and presumably rendering it again), this is a resource hog.

Try this approach:

  1. save tiles to disk, and in parallel,

  2. read the tiles from disk and construct them in memory by drawing it in a context. Take a look at UIGraphicsBeginImageContext and [UIImage drawInRect]. (Not sure if resource usage is better than CGImageCreateWithImageInRect)

  3. When it's complete, save it to disk. See UIGraphicsGetImageFromCurrentImageContext

If you encounter memory problem as the image gets bigger, you may want to tweak #3, i.e. add a threshold to the number of tiles to know when to save it to disk before reaching memory limit.

Also, I didn't see in your code how you render the image to display but setNeedsDisplayInRect is useful for this to render only on specified rectangle. However, if you're using CATiledLayer, there will be some issues with this combination, try to play with it more or research for a solution until you get it exactly as you want it.

Manny
  • 6,277
  • 3
  • 31
  • 45
  • Thanks Manny. I guess if I can save the files to disk, in parallel will help me to solve the problem. But not sure how you do it in parallel ? Do you mean to use NSOperationQueue ? – lifemoveson Jun 29 '11 at 14:09
  • I would imagine like this: 4 async connections to retrieve in parallel and saving to disk, then performing rendering on main thread. Sorry for the confusion in parallel, what I meant was more than 1 thread will retrieve from server and process data at the same time. – Manny Jun 30 '11 at 07:07