Speeding up UIImage creation from SpriteSheet

I'm not sure I got the name for sure, but I'm not sure where my problem is.

I need to load an array of UIImages from a sprite, which I will use as animation in a UIImageView.

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

Until now, I worked without problems, even loading 100 frames in just 0.5-0.8 seconds, and I was very pleased.

Now the problem is loading sprites from the Documents folder (they are downloaded, therefore they cannot be integrated into the application), so I have to use UIImage imageWithContentsOfFile instead of UIImage imagenamed . This increases the loading time by 5-15 seconds depending on the number of frames in the animation. I assume the problem is that since the image is not cached, it loads it for every frame, but I don’t understand 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 boot system profiling sessions that show how long the download takes.

enter image description here

+3
source share
1 answer

Well, I finally figured out where the problem is. After a more thorough study of the Tools Time profiler, I noticed that a lot of time was spent in copyImageBlockSetPNG, and this made me first believe that I downloaded the image from disk for each frame. It turned out that someone already had this problem CGContextDrawImage unpacks PNG on the fly? , and it ended up loading memory every frame, but not from disk, instead it was uncompressed from PNG format memory for each frame.

This article is a solution that consists in writing the image in context and getting an uncompressed copy of the image from it.

This works, but I found another way which, in my opinion, is a 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 this helps!

+1
source

All Articles