2013-03-08 74 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); 

希望它能幫助!