问题描述
我不太确定标题是否正确,但是我不确定我的问题在哪里。
我需要加载一个数组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/[email protected]];
// //但是,这非常令人难以置信的加载时间
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中花费了很多时间,这使我首先相信我从磁盘上为每一帧加载图像。原来,有人已经遇到了这个问题,这是真的,我是每帧都加载内存,而不是从磁盘加载内存,而是每帧以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/[email protected]"];
// 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创建的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!