CATiledLayer而不是渲染切片

时间:2013-04-04 14:00:45

标签: ios xcode bitmap catiledlayer

问题:

我要渲染一个大图像7148x15000px(自定义地图),所以我一直在寻找有用的东西,我发现BitmapSlice,但问题是我第一次运行应用程序(在设备和模拟器上)没有正确加载几个切片,我看到有大黑洞的图像。

代码:

BitmapSliceViewController.h

#import <UIKit/UIKit.h>

@interface BitmapSliceViewController : UIViewController<UIScrollViewDelegate>
    @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

BitmapSliceViewController.m

#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 > 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 = UIImageJPEGRepresentation([UIImage imageWithCGImage:tileImage], 1);

            CGImageRelease(tileImage);
            NSString *path = [NSString stringWithFormat:@"%@/%@%d_%d.png", 
                    directoryPath, prefix, x, y];
            [imageData writeToFile:path atomically:NO];
        }
    }
}

@end

TileView.h

@interface TileView : UIView 

@property (nonatomic, copy) NSString *tileTag;
@property (nonatomic, copy) NSString *tileDirectory;

- (UIImage*)tileAtCol:(int)col row:(int)row;

@end

TileView.m

#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 <= lastRow; row++) {
        for (int col = firstCol; col <= 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

这是应用程序的主要代码,您可以从帖子顶部链接的网站下载整个示例。

正如我所说,主要问题是在应用程序的第一次运行中渲染了一些失败的切片,其他运行似乎正常。

修改位- (UIImage*)tileAtCol:(int)col row:(int)row

- (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;  
}

问题似乎在这里......

有任何想法要解决它吗?

提前致谢

0 个答案:

没有答案