views:

492

answers:

4

This somewhat related to another post - but that one got kinda messed up - so I start from scratch:

I have a CATiledLayer with a HUGE image in it (5780x6700px).

The tiled layer is in a scrollview. When I start to scroll around, everything's fine up to a point where obviously too many tiles have been rendered. Then I get a memory warning and the app crashes.

I tried to remove the tiledlayer from the view when I get the memory warning, clear it's contents (rootLayer.contents = nil AND tiledLayer.contents = nil) and then re-attach it empty to the view. didn't work...

Would be thankful for any input...

Edit:

Thanks for the hints so far. Some of my assumptions seem to be wrong. I loaded the image in a function and then retained it - which is a contradiction to the CATiledLayer behaviour, I guess. Plus the UIImage imageNamed: seemed to cause some errors as well. Now I load the image in drawLayer:(CALayer *) inContentext(CGContextRef) ctx and use UIImage imageWithContentsOfFile: to load it.

This seems to work without causing the memory to go low.

However - the tiles are drawn painfully slow :(

Here's my setup for the tiledLayer:

-(CATiledLayer *)initTiledLayers: (int)level{

    //[tiledLayer release];

    CGRect pageRect;

    CATiledLayer *myLayer = [CATiledLayer layer];
    myLayer.delegate = self;

    if(level == 1){     
        pageRect = CGRectMake(0,  0,  690, 800);
        myLayer.tileSize = CGSizeMake(800, 800);
        myLayer.levelsOfDetail = 10;
        myLayer.levelsOfDetailBias = 2;
    }else if(level == 2){
        pageRect = CGRectMake(0,  0,  1445, 1675);
        myLayer.tileSize = CGSizeMake(600, 600);
        myLayer.levelsOfDetail = 8;
        myLayer.levelsOfDetailBias = 2;
    }else if(level == 3){   
        pageRect = CGRectMake(0,  0,  2890, 3350);
        myLayer.tileSize = CGSizeMake(400, 400);
        myLayer.levelsOfDetail = 4;
        myLayer.levelsOfDetailBias = 1;
    }else if(level == 4){
        pageRect = CGRectMake(0,  0, 5780, 6700);
        myLayer.tileSize = CGSizeMake(150, 150);
        myLayer.levelsOfDetail = 4;
        myLayer.levelsOfDetailBias = 0;
    }

    myLayer.frame = pageRect;

    return myLayer;
    [myLayer release];
}

(int)level indicates which image to be used (I'm switching images on certain zoom-levels). Level4 is the biggest image...

And here's the drawLayer-function:

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
    CGContextSetRGBFillColor(ctx, 1.0, 1.0, 1.0, 1.0);
CGContextFillRect(ctx, CGContextGetClipBoundingBox(ctx));
CGContextTranslateCTM(ctx, 0.0, layer.bounds.size.height);
CGContextClearRect(ctx, CGRectMake(0,0,layer.bounds.size.width, layer.bounds.size.height));
CGContextScaleCTM(ctx, 1.0, -1.0);

    UIImage *map = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"Karte0%d", actLevel] ofType:@"jpg"]];
    UIImage *wanderwege = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"Karte0%d_wanderwege", actLevel] ofType:@"png"]];
    UIImage *rhb = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"Karte0%d_rhb", actLevel] ofType:@"png"]];
    UIImage *abstecher = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"Karte0%d_abstecher", actLevel] ofType:@"png"]];

    CGRect imageRect = CGRectMake (0.0, 0.0, map.size.width, map.size.height);
    CGContextDrawImage (ctx, imageRect, [map CGImage]);

    imageRect = CGRectMake (0.0, 0.0, wanderwege.size.width, wanderwege.size.height);
    CGContextDrawImage (ctx, imageRect, [wanderwege CGImage]);

    imageRect = CGRectMake (0.0, 0.0, rhb.size.width, rhb.size.height);
    CGContextDrawImage (ctx, imageRect, [rhb CGImage]);

    imageRect = CGRectMake (0.0, 0.0, abstecher.size.width, abstecher.size.height);
    CGContextDrawImage (ctx, imageRect, [abstecher CGImage]);

}

Yeah - I know - I actually draw 4 images into the context. The PNGs are overlays which I need to dynamically add to the main-image...

I tried to merge the images into one - but this seems to be even more mem/cpu-consuming ;)

Any further help is greatly appreciated!

A: 

hey were you able to find a fix. I've been using code similar to what you posted. I am also trying to display large png's at multiple zoom levels. Tiles load too slowly

mosca1337
A: 

I found out, that I didn't use the tiledLayer correctly. Also, I was using PNGs as overlays and had to set the blend-mode on the tiledLayer correctly to get rid of the black screens...

[edit] and not to forget (as Andrew mentions below), the big image has to be cut into tiles (zoomify for PSD, for example). If you use the tiled layer with one big image, it doesn't work...

Swissdude
+1  A: 

Why do you draw the all image in the delegate callback?

The problem is CATiledLayer breaks all the content into rectangles and passes clipped context into delegate callback: - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx

This happens for all the rectangles and as there are many of them and the image you draw is big and time consuming, the overall process lasts "ages".

In my practice I had many small objects that were rendered only if they were visible within the frame defined by the clipped context.

In your case (1 big pdf) I would try to draw only the part of the image. Not sure if it helps anyway :)

Andrew Gubanov
A: 

hi Swissdude, i have the same problem, i tried a lot, but i can' figure out how can have it working, can you help me posting a sample project?

Daniele