2013-03-08 79 views
2

我不太确定我的标题是否正确,但我不确定我的问题到底在哪里。加速从SpriteSheet创建UIImage

我需要从一个spritesheet加载一个UIImages数组,然后在UIImageView中使用它作为动画。

Spritesheet由TexturePacker生成,它生成巨大的地图集(2048x2048)和带有精灵描述的json。

到目前为止,我已经在没有问题的情况下工作,甚至在0.5-0.8秒内加载了100帧,我非常满意。

现在的问题是我需要从Documents文件夹下载Spritesheets(它们下载,所以不能集成到应用程序中),所以我必须使用UIImage imageWithContentsOfFile而不是UIImage imagenamed。 这会使我的加载时间增加5-15秒,具体取决于动画中的帧数。 我猜问题是,由于图像不被缓存,加载它的每一帧,但我不明白为什么

这是代码:

// With this line, perfect 
//UIImage *atlas = [UIImage imageNamed:@"media/spritesheets/[email protected]"]; 
// But with this one, incredibly looooong loading times 
UIImage *atlas = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"media/spritesheets/[email protected]" ofType:@"png"]]; 

CGImageRef atlasCGI = [atlas CGImage]; 

for(NSDictionary* dict in frames) { 

    NSDictionary *frame = [dict objectForKey:@"frame"]; 
    int x = [[frame objectForKey:@"x"] intValue]; 
    int y = [[frame objectForKey:@"y"] intValue]; 
    int width = [[frame objectForKey:@"w"] intValue]; 
    int height = [[frame objectForKey:@"h"] intValue]; 

    NSDictionary *spriteSize = [dict objectForKey:@"spriteSourceSize"]; 
    int realx = [[spriteSize objectForKey:@"x"] intValue]; 

    NSDictionary *size = [dict objectForKey:@"sourceSize"]; 
    int realWidth = [[size objectForKey:@"w"] intValue]; 
    int realHeight = [[size objectForKey:@"h"] intValue]; 

    //Initialize the canvas size! 
    canvasSize = CGSizeMake(realWidth, realHeight); 

    bitmapBytesPerRow = (canvasSize.width * 4); 
    bitmapByteCount  = (bitmapBytesPerRow * canvasSize.height); 

    bitmapData = malloc(bitmapByteCount); 

    //Create the context 
    context = CGBitmapContextCreate(bitmapData, canvasSize.width, canvasSize.height, 8, bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast); 

    // Clear background 
    CGContextClearRect(context,CGRectMake(0.0f,0.0f,canvasSize.width,canvasSize.height)); 

    // Get spriteRect 
    CGRect cropRect = CGRectMake(x, y, width, height); 
    CGImageRef imageRef = CGImageCreateWithImageInRect(atlasCGI, cropRect); 

    //Draw the image into the bitmap context 
    CGContextDrawImage(context, CGRectMake(realx, 0, width, height), imageRef); 

    //Get the result image 
    resultImage = CGBitmapContextCreateImage(context); 

    UIImage *result = result = [UIImage imageWithCGImage:resultImage]; 

    [images addObject:result]; 

    //Cleanup 
    free(bitmapData); 
    CGImageRelease(resultImage); 
    CGImageRelease(imageRef); 
} 

我可以甚至尝试它显示的上传系统分析器会话,其中正在采取这么多的时间装载

enter image description here

+0

如果您只加载一次图集图像,为什么会发生缓存问题? – Till 2013-03-08 20:56:24

+0

我真的不知道,但那就是我知道存在于UIImage imagenamed和UIImage imageWithContentsOfFile之间的唯一区别。 (那么,以及imageWithContentsOfFile可以从应用程序包外部加载图像,这就是为什么我首先需要它。) – asendra 2013-03-08 21:01:36

回答

0

嗯,我终于想通问题出在哪里了。在使用Instruments Time Profiler仔细查看之后,我注意到在copyImageBlockSetPNG中花费了大量时间,这让我相信我首先从每个镜像的磁盘加载镜像。结果是,有人已经有这个问题Does CGContextDrawImage decompress PNG on the fly?,它结束是真的,我是加载每帧的内存,而不是从磁盘,而不是从内存以png格式为每个帧压缩。

在这篇文章中提供了一个解决方案,它包括将图像写入上下文并从中获取未压缩的图像副本。

这一工程,但我发现,我相信这是其他的方式一点点更有效

NSDictionary *dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] 
              forKey:(id)kCGImageSourceShouldCache]; 
NSData *imageData = [NSData dataWithContentsOfFile:@"path/to/image.png"]]; 
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)(imageData), NULL); 
CGImageRef atlasCGI = CGImageSourceCreateImageAtIndex(source, 0, (__bridge CFDictionaryRef)dict); 
CFRelease(source); 

希望它能帮助!