大多数内存有效的方法将照片保存到iPhone上的磁盘? [英] Most memory efficient way to save a photo to disk on iPhone?

查看:188
本文介绍了大多数内存有效的方法将照片保存到iPhone上的磁盘?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 Instruments 进行分析我了解到将图像保存到磁盘的方式导致内存峰值 ~60MB 。这会导致应用程序发出低内存警告,这会导致 iPhone4S 运行<$ c $>导致崩溃c> iOS7 。



我需要最有效的方法将图像保存到磁盘。



我目前正在使用此代码

  +(void)saveImage:(UIImage *)image withName:(NSString * )name {
NSData * data = UIImageJPEGRepresentation(image,1.0);
DLog(@*** SIZE ***:保存大小为%lu的文件,(无符号长)[数据长度]);
NSFileManager * fileManager = [NSFileManager defaultManager];
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString * documentsDirectory = [paths objectAtIndex:0];
NSString * fullPath = [documentsDirectory stringByAppendingPathComponent:name];
[fileManager createFileAtPath:fullPath contents:data attributes:nil];
}

注意:


  1. UIImageJPEGRepresentation compressionQuality 参数的值$ c>不会显着减少内存峰值。
    ,例如
    compressionQuality = 0.8 ,平均超过 100减少内存峰值 3MB 写道。
    然而,它确实减少了磁盘上的数据大小(显然),但这对我没有帮助。


  2. UIImagePNGRepresentation 取代 UIImageJPEGRepresentation 对此更糟糕。它更慢并导致更高的峰值。


是否有可能。我不知道它的内存效率如何,但它有可能将图像直接传输到磁盘。

  +(void )writeImage:(UIImage *)inImage toURL:(NSURL *)inURL withQuality :( double)inQuality {
CGImageDestinationRef destination = CGImageDestinationCreateWithURL((CFURLRef)inURL,kUTTypeJPEG,1,NULL);
CFDictionaryRef properties =(CFDictionaryRef)[NSDictionary dictionaryWithObject:[NSNumber numberWithDouble:inQuality] forKey:kCGImageDestinationLossyCompressionQuality];
CGImageDestinationAddImage(destination,[inImage CGImage],properties);
CGImageDestinationFinalize(destination);
CFRelease(目的地);
}


From profiling with Instruments I have learned that the way I am saving images to disk is resulting in memory spikes to ~60MB. This results in the App emitting low memory warnings, which (inconsistently) leads crashes on the iPhone4S running iOS7.

I need the most efficient way to save an image to disk.

I am currently using this code

+ (void)saveImage:(UIImage *)image withName:(NSString *)name {
    NSData *data = UIImageJPEGRepresentation(image, 1.0);
    DLog(@"*** SIZE *** : Saving file of size %lu", (unsigned long)[data length]);
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
    [fileManager createFileAtPath:fullPath contents:data attributes:nil];
}

Notes:

  1. Reducing the value of the compressionQuality argument in UIImageJPEGRepresentation does not reduce the memory spike significantly enough. e.g. compressionQuality = 0.8, reduced the memory spike by 3MB on average over 100 writes. However, it does reduce the size of the data on disk (obviously)but this does not help me.

  2. UIImagePNGRepresentation in place of UIImageJPEGRepresentation is worse for this. It is slower and results in higher spikes.

Is it possible that this approach with ImageIO would be more efficient? If so why?

If anyone has any suggestions it would be great. Thanks

Edit:

Notes on some of the points outlined in the questions below.

a) Although I was saving multiple images, I was not saving them in a loop. I did a bit of reading around and testing and found that an autorelease pool wouldn't help me.

b) The photos were not 60Mb in size each. They were photos taken on the iPhone 4S.

With this in mind I went back to trying to overcome what I thought the problem was; the line NSData *data = UIImageJPEGRepresentation(image, 1.0);.

The memory spikes that were causing the crash can be seen in the screenshot below. They corresponded to when UIImageJPEGRepresentation was called. I also ran Time Profiler and System Usage which pointed me in the same direction.

Long story short, I moved over to AVFoundation and took the photo image data using

photoData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];

Which returns an object of type NSData, I then used this as the data to write using NSFileManager.

This removes the spikes in memory completely.

i.e

[self saveImageWithData:photoData];

where

+ (void)saveImageWithData:(NSData *)imageData withName:(NSString *)name {
    NSData *data = imageData;
    DLog(@"*** SIZE *** : Saving file of size %lu", (unsigned long)[data length]);
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
    [fileManager createFileAtPath:fullPath contents:data attributes:nil];
}

PS: I have not put this as an answer to the question incase people feel it does not answer the Title "Most memory efficient way to save a photo to disk on iPhone?". However, if the consensus is that it should be I can update it.

Thanks.

解决方案

Using UIImageJPEGRepresentation requires that you have the original and final image in memory at the same time. It may also cache the fully rendered image for a while, which would use a lot of memory.

You could try using a CGImageDestination. I do not know how memory efficient it is, but it has the potential to stream the image directly to disk.

+(void) writeImage:(UIImage *)inImage toURL:(NSURL *)inURL withQuality:(double)inQuality {
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL( (CFURLRef)inURL , kUTTypeJPEG , 1 , NULL );
    CFDictionaryRef properties = (CFDictionaryRef)[NSDictionary dictionaryWithObject:[NSNumber numberWithDouble:inQuality] forKey:kCGImageDestinationLossyCompressionQuality];
    CGImageDestinationAddImage( destination , [inImage CGImage] , properties );
    CGImageDestinationFinalize( destination );
    CFRelease( destination );
}

这篇关于大多数内存有效的方法将照片保存到iPhone上的磁盘?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆