3

私は独自の画像ダウンローダ クラスを持っています。キューを保持し、一度に 1 つ (または一定量) の画像をダウンロードし、それらをキャッシュ フォルダに書き込み、必要に応じてキャッシュ フォルダから取得します。また、URL を渡すことができる UIImageView サブクラスもあります。イメージ ダウンローダー クラスを介して、イメージがデバイスに既に存在するかどうかを確認し、存在する場合は表示するか、終了後にダウンロードして表示します。

画像のダウンロードが完了したら、次のことを行います。ダウンロードした NSData から UIImage を作成し、ダウンロードした NSData をディスクに保存して、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

既存の画像を取得するには、これを行います。

// 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
}

ご覧のとおり、私は常にダウンロードした NSData から直接 UIImage を作成します。UIImagePNGRepresentation を使用して NSData を作成することはないので、画像は圧縮されません。圧縮された NSData から UIImage を作成すると、UIImage はメイン スレッドでレンダリングする直前にそれを解凍し、UI をブロックします。私は現在、ディスクからダウンロードまたは取得する必要がある大量の小さな画像を含む UITableView を持っているため、スクロールが非常に遅くなるため、これは受け入れられません。

今私の問題。ユーザーはカメラロールから写真を選択して保存することもでき、UITableView にも表示する必要があります。しかし、UIImagePNGRepresentationを使用せずに、カメラロールからUIImageをNSDataに変換する方法を見つけることができないようです。だからここに私の質問があります。

UIImage を圧縮されていない NSData に変換して、後で imageWithData を使用して UIImage に変換し、レンダリング前に解凍する必要がないようにするにはどうすればよいですか?

また

UIImage をメインスレッドに送信してキャッシュする前に解凍を実行して、一度だけ解凍する必要がある方法はありますか?

前もって感謝します。

4

3 に答える 3

3

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.

于 2013-03-29T00:34:15.063 に答える
1

私は解決策を見つけました:

CGImageRef downloadedImageRef = downloadedImage.CGImage;
CGDataProviderRef provider = CGImageGetDataProvider(downloadedImageRef);
NSData *data = CFBridgingRelease(CGDataProviderCopyData(provider));
// Then you can save the data
于 2015-04-24T10:43:41.753 に答える
0

データをダウンロードしてディスクに保存すると、データは PNG、JPEG、または GIF 形式で圧縮されます。非圧縮の画像データをダウンロードするつもりはありません。したがって、ファイルをディスクに保存する前に、まず解凍を行うことに関する質問の根本に対処する必要があります。保存する前に解凍するとファイルがかなり大きくなりますが、データが CGImageRef または UIImage に読み込まれる前に解凍する必要がないことを意味します。CPU の速度を低下させ、スクロールを遅くするのは、一連の画像を読み込んでから解凍することです。ただし、解凍済みのメモリにすべてを保持するだけでは解決策ではありません。これは、アプリのメモリをすべて使い果たし、やがて電話がクラッシュするためです。いくつかの少数の画像については、それでうまくいくかもしれませんが、ただし、これは基本的な設計上の欠陥であり、最初にコードを記述するときに対処する必要があります。必要に応じて、このトピックに関する私のブログ投稿をご覧ください。video-and-memory-usage-on-ios-devices、投稿はビデオを扱っていますが、多くの異なる画像を扱うときにまったく同じ問題があります。小さな画像を TIFF や BMP などの非圧縮形式でディスクに書き込むことをお勧めします。そうすれば、ImageIO がその特定の形式をサポートしている限り、簡単に読み込むことができます。

于 2013-06-18T23:57:58.527 に答える