Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
784 views
in Technique[技术] by (71.8m points)

cocoa touch - UIImage to raw NSData / avoid compression

I have my own image downloader class, it holds a queue and downloads images one (or a certain amount) at a time, writes them to the cache folder and retrieves them from the cache folder when necessary. I also have a UIImageView subclass to which I can pass a URL, through the image downloader class it will look if the image already exists on the device and show it if it does, or download and show it after it finished.

After an image finishes downloading I do the following. I create a UIImage from the downloaded NSData, save the downloaded NSData to disk and return the UIImage.

// This is executed in a background thread
downloadedImage = [UIImage imageWithData:downloadedData];
BOOL saved = [fileManager createFileAtPath:filePath contents:downloadedData attributes:attributes];
// Send downloadedImage to the main thread and do something with it

To retrieve an existing image I do this.

// This is executed in a background thread
if ([fileManager fileExistsAtPath:filePath])
{
    NSData* imageData = [fileManager contentsAtPath:filePath];
    retrievedImage = [UIImage imageWithData:imageData];
    // Send retrievedImage to the main thread and do something with it
}

As you can see, I always create a UIImage directly from the downloaded NSData, I never create NSData using UIImagePNGRepresentation so the image never gets compressed. When you create a UIImage from compressed NSData, UIImage will decompress it right before rendering on the main thread and thus block the UI. Since I'm now having a UITableView with a ton of small images in it that have to be downloaded or retrieved from disk, this would be unacceptable as it would slow down my scrolling immensely.

Now my problem. The user is also able to select a photo from the camera roll, save it and it also has to appear in my UITableView. But I can't seem to find a way to turn the UIImage from the camera roll into NSData without using UIImagePNGRepresentation. So here's my question.

How can I convert a UIImage into uncompressed NSData so I can convert it back to a UIImage later using imageWithData so that it doesn't have to be decompressed before rendering?

or

Is there any way I can do the decompression before sending the UIImage to the main thread and cache it so it only has to be decompressed once?

Thanks in advance.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

How can I convert a UIImage into uncompressed NSData so I can convert it back to a UIImage later using imageWithData so that it doesn't have to be decompressed before rendering?

What you're really asking here, I take it, is how to store the UIImage on disk in such a way that you can later read the UIImage from disk as fast as possible. You don't really care whether it is stored as NSData; you just want to be able to read it quickly. I suggest you use the ImageIO framework. Save by way of an image destination and fetch later by way of an image source.

http://developer.apple.com/library/ios/#documentation/GraphicsImaging/Conceptual/ImageIOGuide/ikpg_dest/ikpg_dest.html

Is there any way I can do the decompression before sending the UIImage to the main thread and cache it so it only has to be decompressed once?

Yes, good question. That was going to be my second suggestion: use threading. This is what people have to do with tables all the time. When the table asks for the image, you either have the image already or you don't. If you don't, you supply a filler image and, in the background, fetch the real image. When the real image is ready, you have arranged to get a notification. Back on the main thread, you tell the table view to ask for the data for that row again; this time you've got the image and you supply it. The user will thus see a slight delay before the image appears. I'm sure you've seen lots of apps that behave this way (New York Times is a good example).

I have one further suggestion, and it may be the best of all. You speak of it taking time to decompress the image from disk. But this should take no time at all if the image is small. But the image should be small, because it's going to go into a small place - a table cell. In other words, you should shrink the images beforehand, when you first receive them, so that you are ready with the small version of each image when asked. It is a huge waste of time and memory to supply a large image that is to go into a small space.

ADDED LATER: Of course you do understand that a lot of this worry would be unnecessary if you weren't saving the images to disk. I'm not at all clear on why you need to do that. I hope you have a good reason for it; but it's a heck of a lot faster, obviously, if you just hold the images ready in memory.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...