Updating saved images for Retina Display - iphone

I have an iPhone app that, among other things, allows users to store photos. When a new photo is added to the app's data store, I cache a thumbnail version of the image so that the photo thumbnail grids load in a reasonable amount of time.
The problem is that these thumbnails look great on a pre-Retina Display screen, but they look a little blurry on RD displays. It's not so bad that the images are unusable, but I would really like to be able to get the full benefit of Retina Display for images users saved with older versions of my app.
The problem is that re-creating all these thumbnails takes way too long. In my tests, it took about a minute and a half to re-encode a sample database to high-res thumbnails (admittedly a large one) on my iPhone 4. It will be even worse on older hardware.
How can I get around this? Doing a one-time migration seems out of the question, given the performance results above. Other options are shrinking the thumbnails lazily (i.e. as they're displayed on-screen) and then saving them to the database at that point. Screens full of old images will be sluggish the first time they're viewed, and then snappier after that.
Are there other approaches to consider? Anyone else faced this problem?

I dont like the idea that you try and convert the images.
User will quickly get impatient and say you app is buggy and takes ages to load.
I think you solve the situation without any re-processing of full sized images.
On older hardware you would not have a retina display (so no need to upsize the images). If they have a retina display then they have a fast iPhone iPod.
I would suggest you graphically solve the problem by how you display the thumbnail images. so instead of fullscreen put a border around this image and show it at its true resolution (dont upscale it). Or show 4 images where you normally show 1 (since iPhone screen is 4x the resolution).
Instead of resampling the original massive image, you could do a bicubic upsample of the thumbnail making it 4x the size. This will make it slightly blurry but it should look better than the iPhone scaling which will look really bad. The upsample would be ultra fast as its working with a small image.
I cannot help you out on upsampling but there will be some code somewhere.
Cheers, John.

Screens full of old images will be sluggish the first time they're viewed, and then snappier after that.
It doesn't have to be sluggish.
It's a bit of a pain, but you can do most of your processing in a background thread. Set the thread priority to something low (like 0.1) to avoid making the UI too slow. The easiest way to do this is to set up an NSOperation for each image you need to convert and add them to a NSOperationQueue with maxConcurrentOperationCount=1.
If writes are not atomic, in -applicationDidEnterBackground: or -applicationWillTerminate: (or in something listening for the corresponding notifications notifications), do something like [queue cancelAllOperations]; for (NSOperation * operation in queue) { [operation setThreadPriority:1]; } [queue waitUntilAllOperationsAreFinished];; you get about 10 seconds or so which should be enough for the image conversion to finish writing to disk (and thus avoid half-written files). For added protection, check [operation isCancelled] immediately before the write if it might take longer than 10 seconds. Obviously, in -applicationWillEnterForeground:, you should restart the conversion (remembering that some of the images have already been converted).
Concurrency issues are fun to track down...
(Note that [data writeToFile:path atomically:YES] isn't sufficient — it's likely to leave temporary files lying around if the app is killed during the write. I'd recommend storing thumbnails in Core Data if you can, but that might be out of the question for existing apps.)

Related

iphone best practice, how to load multiple high quality images

I have about 20-ish high quality images (~3840x5800 px) that I need to load in a simple gallery type app. The user clicks a button and the next image is loaded into the UIImageView.
I currently use [UIImage imageWithContentsOfFile:] which takes about 6 seconds to load each image in the simulator :(
if I use [UIImage imageNamed:] it takes even longer to load but caches the images which means its quicker if the user wishes to see the same images again. But it may cause memory problems later with all that caching crashing my app.
I want to know whats the best practice for loading these? I'm experimenting with reducing image file size as much as is possible but I really need them to be high quality image for the purpose of the app (zoomable, etc.).
Thanks for any advice
[EDIT]
Hey again guys,
Thanks for all ye're advice. The project's spec's have changed a little. Now as well as displaying the images they firstly have to be zoomed in to a particular spot and when the user taps next it zooms out and then displays the next image. So I'm not sure if the proposed solutions fits?
Apple's docs recommend against trying to load single images that are larger than 1024x1024. You should look into using CATiledLayer instead, to load pieces of the images as needed.
You can have a look at this Apple sample:
http://developer.apple.com/library/ios/#samplecode/PhotoScroller/Introduction/Intro.html#//apple_ref/doc/uid/DTS40010080
It shows how to load big images, breaking them in tiles for different zoom levels.
You can't see all those pixels at any given time, so there is no need to load them all. Load lower-res copies ("big-thumbnails") to view the complete image, then selected sub-tiles, maybe of 2 or more different resolution sets, after the user zooms in.
The CATiledLayer API may be able to handle some of the latter for you.

Seeing malloc allocating large chunks of memory - trying to track down why (iPhone)

I'm seeing my app being killed by iOS with an out of memory message, however, while tracing the progress of the app in the Allocations Instrument, I see lots of mallocs that seem to be occurring outside of the code I've written.
I'm not seeing any leaks being caught, so I assume these allocations are supposed to be there. Thing is, because I'm not sure about why they have been allocated, I'm not sure what I can do to optimize the app and prevent the OS from jettisoning my app.
Does anyone know why the memory is being allocated, or is there any way for me to find out?
Here are a couple of shots from Instruments showing the mallocs. In the second shot, all of the allocations have the same stack trace.
EDIT
I' displaying a single large image as the UIView background (1024x768), then overlaying a smaller (600px square) UIView with some custom drawing and a third UIView (550px square) over the top of those that contains two 550px square images overlayed.
I'm guessing that this is not appropriate, and there is probably a better way of achieving the composition of views I need for the app to work.
Should this be possible on the iPad?
I think there's not really much information to go on here - if you add a bit more information about what this view in your app is doing you might get some more informed suggestions.
From the screenshot, it would appears large blocks are being allocated to display an image.
Given that I'd hazard a guess that either you're trying to display some very large images, or you UIView is large, or you have more UIViews in memory that you need to display the current screen.
I guess the easiest way to track down exactly where they're coming from would be to disable the part of the application you suspect then run again and see if the allocations still occur.
EDIT
Are all the images the same size as you're displaying them? (ie. are you trying to display a 5M photo as the 1024x768 background?) If not you probably need to scale them down to the size you are display them, or at least closer.
If you're not needing transparency, make sure to make all the views opaque.
I figured out the source of the problem - I was using
[UIImage imageNamed:#'Someimage']
to load in my images. This, as I'm sure many people are aware, caches the image data. I had enough images of sufficient size to cause my app to be jettisoned.
The problem was apparent not because of the size of the image but because of both the size and number of images I was using. The lesson here is be careful with [UIImage imageNamed:].
Thanks for all of the help, chaps!
Mallocs can occur inside of other API's that your app calls (such as loading images, views, playing long sounds, etc.) You can try changing the size of your images, views, sounds and other objects by various amounts as a test, and see if the size of the malloc'd memory changes track one of the changes that you've made.

Handling many image files in scrollview on iPhone similar to photos app

So I've seen this question asked before and in fact I asked it last night but I thought I'd give it another go just to see if I could get any other unique views on the problem.
The Problem — I have an app with a large number of uiimageviews (with image downloaded to disk) in a scrollview which of course has two large problems facing it: Memory use, and performance. In my app memory use isn't so much a problem because I am employing techniques such as dequeuing and reusing imageviews and such. But performance is another thing entirely. Right now, as a memory saving procedure, I only store image filepaths in memory because it would be ridiculous to store images in memory. But the problem with this is that reading from the disk takes more time than from memory and slows down scrolling on the scrollview immensely.
So, what kind of techniques do any of you suggest for something like this? I've seen three20 but don't want to use it because I need high customizability in my view and that just won't do. Image files are not large, but just thumbnail size so there is no scaling or excess size. There's got to be an intuitive way to handle this. The built in photos app handles up to thousands of photos perfectly with low memory and slick and smooth scrolling performance.
Fundamentally, the problem is that you're probably doing a bunch of disk I/O on your UI thread, which is basically guaranteed to cause performance problems.
You should consider loading your images on a background thread and updating the image views on the main thread when the images are loaded. Depending on your use case you can get more or less clever about how far you preload in advance, etc, so you can have images ready. (There might be some usable source code or even Apple sample code out there that does something like this, but I don't know of it off the top of my head.)
You may notice that some applications (not sure about the Photos app) have an intermediate stage where they load a very small thumb size image for all images, and scale it up to the render size, which acts as a placeholder until the full size version is loaded-- if the user scrolls past that image before the full size is loaded, the visible effect is nearly the same as if the image was there all along.

iPhone: Reading many images quickly

I've got an app I'm working on where we handle a LOT of images at once in a scrollview. (Here's how it looks, each blue block being in image on a scrollview expanding to the right: http://i.stack.imgur.com/o7lFx.png) So to be able to handle the large strain doing this puts on memory. So I've implemented a bunch of techniques such as reusing imageviews etc which have all worked quite successfully in keeping my memory usage down. Another thing I do is instead of keeping the actual image in memory (which I of course couldn't do for all of them because that would run out of memory very quickly) I only keep the image's filepath in memory and then read the image when the user scrolls to an area of the scroll view near that image. However, although this is memory efficient, it's causing a LOT of lag in the scrollview because of the fact that it has to constantly read images from the disk. I can't think of a good solution on how to fix this. Basically right now the app draws to the screen only the visible uiimageviews and while the user scrolls the app will look to see if it can dequeue another imageview so it doesn't have to allocate another one and at that point it reads the image into memory, but as I said it's causing the scrolling action to be very slow. Any ideas on a strategy to use to fix this? Does anyone know what the native photos app does to handle this kind of thing? Thanks so much!
I can suggest you a simple solution to balance both the memory and the computer processing. You only keep small images like thumbnails in memory and only keep about 20 of them. One project that I am doing, I keep 20 thumbnail images (100 x 100) recently accessed, which doesn't cost a lot of memory. I believe that it costs about 200 kb all the time but comparing to a general available memory. I think it is good enough.
It also depends on your use case : if user scroll really fast and you don't know when will they go. You can have even smaller images than the thumnail and when you show it on the UIImageView, you resize it to fit. When user stops scrolling for a while. You can start loading bigger images and then you have a nicer images. User may not even notice about the process
I don't think there is a solution that can be fast and using as less memory as possible. Because we have memory, maybe not big but have enough if we use it smartly.
Slow scrolling performance might mean that you're blocking the main thread while loading images. In that case, the scrolling animation won't continue until the images are loaded, which would indeed cause pretty choppy scrolling performance.
It would be better to lazily load requested images in the background, while the main thread continues to handle the scrolling animation. A library that provides this functionality (among other things) is the 'three20' library. See the Tidbits document, and scroll down to the bottom where the 'TTImageView' class is described.
I had a similar issue with a PDF viewer, The recommended way to do this is to have as low a res image as you can get away with and if you are allowing the user to blow the image up/zoom, then have two versions or three versions of that image increasing the res as you go.
Put as much code as you can get away with in the didDecelerate method (like loading in higher res images like vodkhang talks about), rather than processing loads in didScroll. Recycle Views out of scope as you have said. and beware of autoreleased Context based Image Creation functions.
Load images in on background threads intelligently (based on the scrollView Offset position and zoom level), and think about using CALayer/Tiled Layer drawing for larger images.
Three20 (an open source iOs lib) has a great Photo Viewer that can be subclassed, it has thumbnail navigation, large image paging, caching and gestures right out of the box.

iPhone short animation: video or image sequence?

I have read several post on both matters but I haven't seen anyone comparing so far.
Suppose I just want full screen animation without any transparency etc, just a couple of seconds animation (1''-2'') when an app starts. Does anyone know how "video" compares to "sequence of images" (320x480 # 30) on the iPhone, regarding performance etc?
I think there are a few points to think about here.
Size of animation as pointed out above. You could try a framerate of 15 images per second so that could be 45 images for 3s. That is quite a lot data.
The video would be compressed as mentioned before in H.264 (Baseline Profile Level 3.0) format or MPEG-4 Part 2 video (Simple Profile) format. Which means its going to be reasonably small.
I think you will need to go for video because,
1. 45 full screen PNG images is going to require a lot of ram. I don't think this is going to work that well.
Lastly you will need to ad the Media Player Framework which will have to be loaded into memory and this going to increase your load times.
MY ADVICE: Sounds like the animation is a bit superfluous to the app, I hate apps that take ages to load and this is only going to increase you app startup times. If you can avoid doing this, then dont do it. Make you app fast. If you could do this at some other time after load then that is cool.
The video will be a lot more compressed than a sequence of images, because video compression takes previous frame data into account to reduce bitrate. It will take more power to decode, however the iPhone has hardware for that, and the OS has APIs that use this hardware, so I wouldn't feel bad about making use of them.
do not overlook the possibility of rendering the sequence in real-time.