从SpriteSheet加速UIImage创建 [英] Speed up UIImage creation from SpriteSheet

查看:107
本文介绍了从SpriteSheet加速UIImage创建的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不太确定标题是否正确,但是我不确定我的问题在哪里。



我需要加载一个数组Spritesheet中的UIImage,然后将其用作UIImageView中的动画。



Spritesheet由TexturePacker生成,TexturePacker生成巨大的地图集(2048x2048)和json



直到现在,我的工作一直没有问题,甚至只用了0.5-0.8秒就加载了100帧,这我真的很满意。 / p>

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



这是代码:

  //在这一行中,完善
// UIImage * atlas = [UIImage imageNamed: @ media/spritesheets/default-pro7@2x.png];
// //但是,这非常令人难以置信的加载时间
UIImage * atlas = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@ media / spritesheets / default-pro7 @ 2x ofType:@ png]];

CGImageRef atlasCGI = [atlas CGImage];

for(NSDictionary * dict以帧为单位){

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];

//初始化画布尺寸!
canvasSize = CGSizeMake(realWidth,realHeight);

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

bitmapData = malloc(bitmapByteCount);

//创建上下文
context = CGBitmapContextCreate(bitmapData,canvasSize.width,canvasSize.height,8,bitmapBytesPerRow,colorSpace,kCGImageAlphaPremultipliedLast);

//清除背景
CGContextClearRect(context,CGRectMake(0.0f,0.0f,canvasSize.width,canvasSize.height));

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

//将图像绘制到位图上下文中
CGContextDrawImage(context,CGRectMake(realx,0,width,height),imageRef);

//获取结果图像
resultImage = CGBitmapContextCreateImage(context);

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

[images addObject:result];

//清理
free(bitmapData);
CGImageRelease(resultImage);
CGImageRelease(imageRef);
}

我什至可以尝试一个上传系统分析器会话,该会话显示了花费了很多的时间时间加载



解决方案

好吧,我终于弄清楚了问题出在哪里。在使用Instruments Time profiler仔细查看之后,我注意到在copyImageBlockSetPNG中花费了很多时间,这使我首先相信我从磁盘上为每一帧加载图像。原来,有人已经遇到了这个问题 CGContextDrawImage是否在,这是真的,我是每帧都加载内存,而不是从磁盘加载内存,而是每帧以png格式从内存中解压缩。



在那篇文章中有一个解决方案,包括将图像写到上下文中并从中获取图像的未压缩副本。



但是我发现了另一种方法,我相信它更有效率

  NSDictionary * dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:是] 
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(来源);

希望有帮助!


I'm not really sure I got the title exactly right, but I'm not sure where my problem is exactly.

I need to load an array of UIImages from an spritesheet, which I'll then use as animations in a UIImageView.

The spritesheet is generated with TexturePacker, which generates the huge atlas (2048x2048) and a json with the sprites descriptions.

Until now, I've had it working without issues, even loading 100 frames in just 0.5-0.8 secs which I was really happy with.

The problem is now I need to load the spritesheets from the Documents folder (they are downloaded, so can't be integrated in the app), so I have to use UIImage imageWithContentsOfFile instead of UIImage imagenamed. This makes my loading time increase by 5-15 seconds depending the number of frames in the animation. I'm guessing the problem is that because the image isn't being cached, is loading it for every frame, but I don't see why

This is the code:

// With this line, perfect
//UIImage *atlas = [UIImage imageNamed:@"media/spritesheets/default-pro7@2x.png"];
// But with this one, incredibly looooong loading times
UIImage *atlas = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"media/spritesheets/default-pro7@2x" 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);
}

I can even try an upload system profiler sessions which show where is taking so much time loading

解决方案

Well, I finally figured out where the problem was. After looking more carefully with Instruments Time profiler, I noticed a lot of time was spent in copyImageBlockSetPNG , which was what made me believe first that I was loading the image from disk for every frame. turn out, somebody already had this problem Does CGContextDrawImage decompress PNG on the fly?, and it ended being true that I was loading the memory each frame, but not from disk, instead it was being uncompressed from memory in png format for every frame.

In that post theres a solution, which consists in writing the image to a context and getting from it an uncompressed copy of the image.

That works, but I found other way which I believe It's a little bit more efficient

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);

Hope it helps!

这篇关于从SpriteSheet加速UIImage创建的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆