多次调用imageWithData:UIImageJPEGRepresentation()只会在第一次压缩图像

时间:2013-06-09 01:07:40

标签: ios objective-c uiimage uiimagepickercontroller image-compression

为了防止我的应用程序滞后,我正在尝试压缩大于1 MB的图像(主要用于从iphone普通相机拍摄的照片。

UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
NSData *imageSize = UIImageJPEGRepresentation(image, 1);
NSLog(@"original size %u", [imageSize length]);

 UIImage *image2 = [UIImage imageWithData:UIImageJPEGRepresentation(image, 0)];
    NSData *newImageSize = UIImageJPEGRepresentation(image2, 1);
    NSLog(@"new size %u", [newImageSize length]);
    UIImage *image3 = [UIImage imageWithData:UIImageJPEGRepresentation(image2, 0)];
    NSData *newImageSize2 = UIImageJPEGRepresentation(image3, 1);
    NSLog(@"new size %u", [newImageSize2 length]);

picView = [[UIImageView alloc] initWithImage:image3] ;

然而,NSLog我得到的东西是

 original size 3649058
 new size 1835251
 new size 1834884

第一次和第二次压缩之间的差异几乎可以忽略不计。我的目标是使图像大小低于1 MB。我是否忽视了某些事情/有没有其他方法来实现这一目标?

编辑:如果可能的话,我想避免缩放图像的高度和宽度。

3 个答案:

答案 0 :(得分:16)

有几点想法:

  1. UIImageJPEGRepresentation功能不会返回“原始”图像。例如,如果您使用compressionQuality 1.0,从技术上讲,它不返回“原始”图像,而是返回图像的JPEG再现,其中compressionQuality为最大值。这实际上可以产生比原始资产更大的对象(至少如果原始图像是JPEG)。您还要在此过程中丢弃所有元数据(有关拍摄图像的位置,相机设置等的信息)。

  2. 如果您需要原始资源,则应使用PHImageManager

    NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
    
    PHFetchResult *result = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil];
    PHAsset *asset = [result firstObject];
    
    PHImageManager *manager = [PHImageManager defaultManager];
    [manager requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
        NSString *filename = [(NSURL *)info[@"PHImageFileURLKey"] lastPathComponent];
        // do what you want with the `imageData`
    }];
    

    在8之前的iOS版本中,您必须使用assetForURL类的ALAssetsLibrary

    NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    [library assetForURL:url resultBlock:^(ALAsset *asset) {
        ALAssetRepresentation *representation = [asset defaultRepresentation];
    
        NSLog(@"size of original asset %llu", [representation size]);
    
        // I generally would write directly to a `NSOutputStream`, but if you want it in a
        // NSData, it would be something like:
    
        NSMutableData *data = [NSMutableData data];
    
        // now loop, reading data into buffer and writing that to our data strea
        NSError *error;
        long long bufferOffset = 0ll;
        NSInteger bufferSize = 10000;
        long long bytesRemaining = [representation size];
        uint8_t buffer[bufferSize];
        NSUInteger bytesRead;
        while (bytesRemaining > 0) {
            bytesRead = [representation getBytes:buffer fromOffset:bufferOffset length:bufferSize error:&error];
            if (bytesRead == 0) {
                NSLog(@"error reading asset representation: %@", error);
                return;
            }
            bytesRemaining -= bytesRead;
            bufferOffset   += bytesRead;
            [data appendBytes:buffer length:bytesRead];
        }
    
        // ok, successfully read original asset; 
        // do whatever you want with it here
    
    } failureBlock:^(NSError *error) {
        NSLog(@"error=%@", error);
    }];
    

    请注意,此assetForURL以异步方式运行。

  3. 如果您想要NSData进行压缩,则可以UIImageJPEGRepresentation使用compressionQuality小于1.0。您的代码实际上使用compressionQuality 0.0执行此操作,该代码应提供最大压缩。但是你不保存NSData,而是用它来创建UIImage,然后你得到UIImageJPEGRepresentation compressionQuality 1.0的新// a UIImage of the original asset (discarding meta data) UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; // this may well be larger than the original asset NSData *jpgDataHighestCompressionQuality = UIImageJPEGRepresentation(image, 1.0); [jpgDataHighestCompressionQuality writeToFile:[docsPath stringByAppendingPathComponent:@"imageDataFromJpeg.jpg"] atomically:YES]; NSLog(@"compressionQuality = 1.0; length = %u", [jpgDataHighestCompressionQuality length]); // this will be smaller, but with some loss of data NSData *jpgDataLowestCompressionQuality = UIImageJPEGRepresentation(image, 0.0); NSLog(@"compressionQuality = 0.0; length = %u", [jpgDataLowestCompressionQuality length]); UIImage *image2 = [UIImage imageWithData:jpgDataLowestCompressionQuality]; // ironically, this will be larger than jpgDataLowestCompressionQuality NSData *newImageSize = UIImageJPEGRepresentation(image2, 1.0); NSLog(@"new size %u", [newImageSize length]); ,因此失去了你最初实现的大部分压缩。

    请考虑以下代码:

    compressionQuality
  4. 除了前面提到的JPEG压缩质量之外,您还可以resize the image。您也可以将其与JPEG {{1}}结合使用。

答案 1 :(得分:1)

您无法反复压缩图像。如果是这样,一切都可以一次又一次地压缩。那么你认为它会有多小?

使图像变小的一种方法是改变图像的大小。例如,将640X960更改为320X480。但是你会失去品质。

答案 2 :(得分:-1)

我是第一个实现UIImageJPEGRepresentation(图像,0.75),然后改变大小。也许是图像的宽度和高度的三分之二或一半。