Note that there are some explanatory texts on larger screens.

plurals
  1. POCATiledLayer and not rendered slices
    text
    copied!<p><strong>The problem:</strong></p> <p>I've to render a big image 7148x15000px (a custom map), so i've looking around for something usefull and i've found <a href="http://www.cimgf.com/2011/03/01/subduing-catiledlayer/" rel="nofollow">BitmapSlice</a>, but the problem is that the very first time i run the app (on device and simulator) several slices aren't loaded correctly and i see the image with large black holes.</p> <p><strong>Code:</strong></p> <p>BitmapSliceViewController.h</p> <pre><code>#import &lt;UIKit/UIKit.h&gt; @interface BitmapSliceViewController : UIViewController&lt;UIScrollViewDelegate&gt; @property (nonatomic, retain) UIImageView *_zoomView; @property (nonatomic, retain) IBOutlet UIScrollView *scrollView; - (void)saveTilesOfSize:(CGSize)size forImage:(UIImage*)image toDirectory (NSString*)directoryPath usingPrefix:(NSString*)prefix; @end </code></pre> <p>BitmapSliceViewController.m</p> <pre><code>#import "BitmapSliceViewController.h" #import "TileView.h" @implementation BitmapSliceViewController @synthesize scrollView; - (void)dealloc { [super dealloc]; } - (void)viewDidUnload { [super viewDidUnload]; } - (void)viewDidLoad { [super viewDidLoad]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *directoryPath = [paths objectAtIndex:0]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ UIImage *big = [UIImage imageNamed:@"map.jpg"]; [self saveTilesOfSize:(CGSize){256, 256} forImage:big toDirectory:directoryPath usingPrefix:@"map_"]; dispatch_async(dispatch_get_main_queue(), ^{ [scrollView setNeedsDisplay]; }); }); TileView *tv = [[TileView alloc] initWithFrame:(CGRect){{0,0}, (CGSize){7148,15000}}]; [tv setTileTag:@"map_"]; [tv setTileDirectory:directoryPath]; [scrollView addSubview:tv]; [scrollView setContentSize:(CGSize){7148,15000}]; [scrollView setDelegate:self]; } - (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 &gt; fullColumns) fullColumns++; if (rows &gt; fullRows) fullRows++; CGImageRef fullImage = [image CGImage]; for (int y = 0; y &lt; fullRows; ++y) { for (int x = 0; x &lt; fullColumns; ++x) { CGSize tileSize = size; if (x + 1 == fullColumns &amp;&amp; remainderWidth &gt; 0) { // Last column tileSize.width = remainderWidth; } if (y + 1 == fullRows &amp;&amp; remainderHeight &gt; 0) { // Last row tileSize.height = remainderHeight; } CGImageRef tileImage = CGImageCreateWithImageInRect(fullImage, (CGRect){{x*size.width, y*size.height}, tileSize}); NSData *imageData = UIImageJPEGRepresentation([UIImage imageWithCGImage:tileImage], 1); CGImageRelease(tileImage); NSString *path = [NSString stringWithFormat:@"%@/%@%d_%d.png", directoryPath, prefix, x, y]; [imageData writeToFile:path atomically:NO]; } } } @end </code></pre> <p>TileView.h</p> <pre><code>@interface TileView : UIView @property (nonatomic, copy) NSString *tileTag; @property (nonatomic, copy) NSString *tileDirectory; - (UIImage*)tileAtCol:(int)col row:(int)row; @end </code></pre> <p>TileView.m</p> <pre><code>#import "TileView.h" @implementation TileView @synthesize tileTag; @synthesize tileDirectory; + layerClass { return [CATiledLayer class]; } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (!self) return nil; return self; } - (void)dealloc { [super dealloc]; } - (void)drawRect:(CGRect)rect { //CGContextRef context = UIGraphicsGetCurrentContext(); CGSize tileSize = (CGSize){256, 256}; int firstCol = floorf(CGRectGetMinX(rect) / tileSize.width); int lastCol = floorf((CGRectGetMaxX(rect)-1) / tileSize.width); int firstRow = floorf(CGRectGetMinY(rect) / tileSize.height); int lastRow = floorf((CGRectGetMaxY(rect)-1) / tileSize.height); for (int row = firstRow; row &lt;= lastRow; row++) { for (int col = firstCol; col &lt;= lastCol; col++) { UIImage *tile = [self tileAtCol:col row:row]; if (tile) { CGRect tileRect = CGRectMake(tileSize.width * col, tileSize.height * row, tileSize.width, tileSize.height); tileRect = CGRectIntersection(self.bounds, tileRect); [tile drawInRect:tileRect]; // [[UIColor whiteColor] set]; // CGContextSetLineWidth(context, 6.0); // CGContextStrokeRect(context, tileRect); } } } } - (UIImage*)tileAtCol:(int)col row:(int)row { NSString *path = [NSString stringWithFormat:@"%@/%@%d_%d.png", tileDirectory, tileTag, col, row]; return [UIImage imageWithContentsOfFile:path]; } @end </code></pre> <p>This is the main code of the app, you can download the entire example from the site linked on the top of the post.</p> <p>As i said the main problem is the rendering of some slices that fail in the first run of the app, other runs seem works correctly.</p> <p>modifing a bit <code>- (UIImage*)tileAtCol:(int)col row:(int)row</code> </p> <pre><code>- (UIImage*)tileAtCol:(int)col row:(int)row { NSString *path = [NSString stringWithFormat:@"%@/%@%d_%d.png", tileDirectory, tileTag, col, row]; UIImage *img = [UIImage imageWithContentsOfFile:path]; if (img) { NSLog(@"good"); } else { NSLog(@"bad"); } return img; } </code></pre> <p>The problem seems to be here...</p> <p>Any ideas to fix it?</p> <p>Thanks in advance</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload