多次调用imageWithData:UIImageJPEGRepresentation()仅在第一次压缩图像 [英] Calling imageWithData:UIImageJPEGRepresentation() multiple times only compresses image the first time

查看:116
本文介绍了多次调用imageWithData:UIImageJPEGRepresentation()仅在第一次压缩图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In order to prevent lagging in my app, I'm trying to compress images larger than 1 MB (mostly for pics taken from iphone's normal camera.

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输出类似于

However, the NSLog I get outputs something along the lines of

 original size 3649058
 new size 1835251
 new size 1834884

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

The difference between the 1st and 2nd compression is almost negligible. My goal is to get the image size below 1 MB. Did I overlook something/is there an alternative approach to achieve this?

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

I want to avoid scaling the image's height and width, if possible.

推荐答案

一些想法:

  1. UIImageJPEGRepresentation函数不返回原始"图像.例如,如果使用compressionQuality1.0,则从技术上讲,它不会返回原始"图像,而是会返回最大值为compressionQuality的图像的JPEG格式.实际上,这可以产生大于原始资源的对象(至少在原始图像为JPEG的情况下).您还将在此过程中丢弃所有元数据(有关拍摄图像的位置,相机设置等的信息).

  1. The UIImageJPEGRepresentation function does not return the "original" image. For example, if you employ a compressionQuality of 1.0, it does not, technically, return the "original" image, but rather it returns a JPEG rendition of the image with compressionQuality at its maximum value. This can actually yield an object that is larger than the original asset (at least if the original image is a JPEG). You're also discarding all of the metadata (information about where the image was taken, the camera settings, etc.) in the process.

如果要使用原始资产,则应使用PHImageManager:

If you want the original asset, you should use 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版本中,您必须使用ALAssetsLibrary类的assetForURL:

In iOS versions prior to 8, you'd have to use assetForURL of the ALAssetsLibrary class:

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是异步运行的.

Please note that this assetForURL runs asynchronously.

如果要使用压缩的NSData,则可以将UIImageJPEGRepresentation与小于1.0compressionQuality一起使用.您的代码实际上使用0.0compressionQuality执行此操作,这应该提供最大的压缩率.但是,您不必保存该NSData,而是使用它创建一个UIImage,然后获得一个新的UIImageJPEGRepresentation,其compressionQuality1.0,从而失去了最初获得的大部分压缩率.

If you want a NSData with compression, you can use UIImageJPEGRepresentation with a compressionQuality less than 1.0. Your code actually does this with a compressionQuality of 0.0, which should offer maximum compression. But you don't save that NSData, but rather use it to create a UIImage and you then get a new UIImageJPEGRepresentation with a compressionQuality of 1.0, thus losing much of the compression you originally achieved.

考虑以下代码:

// 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]);

  • 除了前面提到的JPEG压缩质量外,您还可以调整图像大小.您也可以将其与JPEG compressionQuality结合使用.

  • In addition to the JPEG compression quality outlined the prior point, you could also just resize the image. You can also marry this with the JPEG compressionQuality, too.

    这篇关于多次调用imageWithData:UIImageJPEGRepresentation()仅在第一次压缩图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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