I'm looking for solution of animation about 50 images on retina iPad each has 2048*1536 size. I want to animate them on finger move(change images on uiimageview sync with touches moved event). Images loads slowly and animation freezes. I want to find any solution to solve that problem. Thanks.
There are a couple of issues that make this situation very hard to deal with. First, the memory usage of 50 full screen images is very large. For some background on how much memory that actually requires, see this blog post Video and Memory usage on iOS devices. The second issue you have run into is CPU usage. A retina iPad has multiple CPUs, but decoding huge PNG images still takes a lot of CPU cycles and that will prevent the animations from running smoothly. So, the only way you will get this to work well is to avoid decoding the image data at runtime and also avoid holding all the decoded data in memory because that would crash the device. The best solution is to simply mmap() all the decoded data and decode it ahead of time, that makes it possible to blit image data into CoreGraphics without actually having to copy the data. If you would like to use my library that does all that, it is linked at the bottom of the blog post.
Related
My app is saving and retrieving data from Parse.com. And showing images, buttons, scrollviews, etc.. (the normal stuff). Then when I got near finishing my app, it started to receive memory warnings and the app started crashing often. I checked it in the Instruments and noticed the live bytes was extremely high at some points, and I can't figure out why.
Is the app crashing because of the high live bytes? What should value of the live bytes be?
Obiously something is going on in the VM. But I have no idea what this is. What is the VM: CG raster data? And this: VM: CG Image? I am not using CGImages only UIImages
Is the app crashing because of the high live bytes?
Yes.
What should value of the live bytes be?
There's not fixed number. The limits change from OS version to OS version, and sometimes depend on the device and what else is going on at the moment. The right thing to do is (a) try not to use so much, and (b) heed the warnings and dispose of stuff you don't need.
Obiously something is going on in the VM. But I have no idea what this is. What is the VM: CG raster data? And this: VM: CG Image? I am not using CGImages only UIImages
A UIImage is just a wrapper around a CGImage.
You have too many images alive at the same time. That's the problem you have to fix.
So, how many is too many? It depends on how big they are.
Also, note that the "raster data" is the decompressed size. A 5Mpix RGBA 8bpp image takes 20MB of RAM for its raster data, whether the file is 8MB or 8KB.
I still feel the number is too high though, or is 30-40 MB an okey number handling 3-6 full-screen sized images at a time? This is when tested on a 4 year old iPhone4, iOS 7. If that matters.
On an iPhone 4, "full-screen" means 640x960 pixels. 8bpp RGBA means 4 bytes per pixel. So, with 6 such images, that's 640*960*4*6 = 14MB. So, that's the absolute minimum storage you should expect if you've loaded and drawn 6 full-screen images.
So, why do you actually see more than twice that?
Well, as Images and Memory Management in the class reference says:
In low-memory situations, image data may be purged from a UIImage object to free up memory on the system. This purging behavior affects only the image data stored internally by the UIImage object and not the object itself. When you attempt to draw an image whose data has been purged, the image object automatically reloads the data from its original file. This extra load step, however, may incur a small performance penalty.
So think of that 14MB as basically a cache that iOS uses to speed things up, in case you want to draw the images again. If you run a little low on memory, it'll purge the cache automatically, so you don't have to worry about it.
So, that leaves you with 16-24MB, which is presumably used by the buffers of your UI widgets and layers and by the compositor behind the scenes. That's a bit more than the theoretical minimum of 14MB, but not horribly so.
If you want to reduce memory usage further, what you probably need to do is not draw all 6 images. If they're full-screen, there's no way the user can see more than 1 or 2 at a time. So, you could load and render them on demand instead of preloading them (or, if you can predict which one will usually be needed next, preload 1 of them instead of all of them), and destroy them when they're no longer visible. Since you'd then only have 2 images instead of 6, that should drop your memory usage from 16-24MB + a 14MB cache to 5-9MB + a 5MB cache. This obviously means a bit more CPU—it probably won't noticeably affect responsiveness or battery drain, but you'd want to test that. And, more importantly, it will definitely make your code more complicated.
Obviously, if it's appropriate for your images, you could also do things like using non-Retina images (which will cut memory by 75%) or dropping color depth from RGBA-8 to ARGB-1555 (50%), but most images don't look as good that way (which is why we have high-color Retina displays).
I have images for displaying in UICollectionView. I saved all my images in array, so I don't load it from disk or network.
When my image appears first time, device has some lag. But when this image appears later there is all ok. There is no problems with my code< and I don't want ask about it. I want understand can I load image to GPU memory in advance. So when image will be appear in first time on screen there is no lag, because this image (or maybe it is called texture) will be in memory cache and device will spend little time for drawing from memory.
So tell me is it possible without going deep in OpenGL, can I do it with CoreFramework?
So I didn't find solution, but I load some UIImageViews with my images on start not in the frame of my viewcontroller view. And After this hack I have not problem with lag
I'm working on an iPad-only iOS app that essentially downloads large, high quality images (JPEG) from Dropbox and shows the selected image in a UIScrollView and UIImageView, allowing the user to zoom and pan the image.
The app is mainly used for showing the images to potential clients who are interested in buying them as framed prints. The way it works is that the image is first shown, zoomed and panned to show the potential client if they like the image. If they do like it, they can decide if they want to crop a specific area (while keeping to specific aspect ratios/sizes) and the final image (cropped or not) is then sent as an email attachment to production.
The problem I've been facing for a while now, is that even though the app will only be running on new iPads (ie. more memory etc.), I'm unable to find a method of handling the images so that the app doesn't get a memory warning and then crash.
Most of the images are sized 4256x2832, which brings the memory usage to at least 40MB per image. While I'm only displaying one image at a time, image cropping (which is the main memory/crash problem at the moment) is creating a new cropped image, which in turn momentarily bumps the apps total RAM usage to about 120MB, causing a crash.
So in short: I'm looking for a way to manage very large images, have the ability to crop them and after cropping still have enough memory to send them as email attachments.
I've been thinking about implementing a singleton image manager, which all the views would use and it would only contain one big image at a time, but I'm not sure if that's the right way to go, or even if it'd help in any way.
One way to deal with this is to tile the image. You can save the large decompressed image to "disk" as a series of tiles, and as the user pans around pull out only the tiles you need to actually display. You only ever need 1 tile in memory at a time because you draw it to the screen, then throw it out and load the next tile. (You'll probably want to cache the visible tiles in memory, but that's an implementation detail. Even having the whole image as tiles may relieve memory pressure as you don't need one large contiguous block.) This is how applications like Photoshop deal with this situation.
I ended up sort of solving the problem. Since I couldn't resize the original files in Dropbox (the client has their reasons), I went ahead and used BOSImageResizeOperation, which is essentially just a fast, thread-safe library for quickly resizing images.
Using this library, I noticed that images that previously took 40-60MB of memory per image, now only seemed to take roughly half that. Additionally, the resizing is so quick that the original image gets released from memory so fast, that iOS doesn't execute a memory warning.
With this, I've gotten further with the app and I appreciate all the idea, suggestions and comments. I'm hoping this will get the app done and I can get as far away from large image handling as possible, heh.
I want to display a high resolution image in imageview. Here is what i do
Prepare UIImage in the background
When the file is loaded, switch to main thread
Display the image [ by using UIImageView's setImage: ]
The problem is there is a lag in the 3rd step. It takes few seconds and loads the file. And if its a large image, I get the memory warning and a crash. So is there a way by which i can draw images from top to bottom ( like how the browser does) ? Also I need to preserve the quality of the image.
Is there a way by which i can achieve my requirement. Thanks in advance
And if its a large image, I get the memory warning and a crash.
it seems you are hitting some "hard" (memory related) limit of your device trying to load and display the image into memory at once.
So is there a way by which i can draw images from top to bottom ( like how the browser does)?
You should try with CATiledLayer, which provides a way to draw very large images without incurring a memory hit.
Here you can find a tutorial about it.
You could also give a look at the PhotoScrollerNetwork project:
blazingly fast tile rendering - visually much much faster than Apple's code (which uses png files in the file system)
you supply a single jpeg file or URL and this code does all the tiling for you, quickly and painlessly
UIImage will not decode its underlying image data until it is actually requested, which will happen on the main thread when you assign it to an image view. So although you are trying to load the image in a background thread, the work is being delayed and actually occurs on the main thread.
The workarounds to this issue are pretty hacky and usually involve writing the image to a new graphics context to force the decoding, and then creating a CGImageRef or UIImage from that. This all takes place on the background thread. By the time you ship the new image to the main thread, all the decoding has already taken place and you shouldn't see a delay. This question has some answers which demonstrate this technique.
Drawing images from top-to-bottom is not possible with the standard APIs provided by Apple (as far as I know). You would have to write your own streaming image decoder which would be a significant task.
You can use SDWebImage framework which helps you for :
1.An asynchronous image downloader
2.Automatic image caching .
3.Avoid duplications .
You can download this from:https://github.com/rs/SDWebImage
About the memory warning it is not only due to your application its due to effective memory use from all the application running on the background so try to stop the background running applications.
I have a list of png images that I want them to show one after another to show an animation. In most of my cases I use a UIImageView with animationImages and it works fine. But in a couple of cases my pngs are 1280*768 (full screen iPad) animations with 100+ frames. I see that using the UIImageView is quite slow on the emulator (too long to load for the first time) and I believe that if I put it on the device it will be even slower.
Is there any alternative that can make show an image sequence quite smoothly? Maybe Core Animation? Is there any working example I can see?
Core Animation can be used for vector/key-frame based animation - not image sequences. Loading over a hundred full-screen PNGs on an iPad is a really bad idea, you'll almost certainly get a memory warning if not outright termination.
You should be using a video to display these kind of animations. Performance will be considerably better. Is there any reason why you couldn't use a H.264 video for your animation?
Make a video of your pictures. It is the simplest and probably most reasonable approach.
If you want really good performance and full control over your animation, you can convert the pictures to pvrtc4 format and draw them as billboards (textured sprites) with OpenGL. This can be a lot of work if you don't know how to do it.
Look at the second example
http://www.modejong.com/iPhone/
Extracts from http://www.modejong.com/iPhone/
There is also the UIImageView.animationImages API, but it quickly sucks up all the system memory when using more than a couple of decent size images.
I wanted to show a full screen animation that lasts 2 seconds, at 15 FPS that is a total of 30 PNG images of size 480x320. This example implements an animation oriented view controller that simply waits to read the PNG image data for a frame until it is needed.
Instead of alllocating many megabytes, this class run in about a half a meg of memory with about a 5-10% CPU utilization on a 2nd gen iPhone. This example has also been updated to include the ability to optionally play an audio file via AVAudioPlayer as the animation is displayed.