2

为了防止我的应用程序滞后,我正在尝试压缩大于 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。我是否忽略了某些事情/是否有替代方法可以实现这一目标?

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

4

3 回答 3

17

几个想法:

  1. UIImageJPEGRepresentation函数不返回“原始”图像。例如,如果您使用compressionQualityof 1.0,从技术上讲,它不会返回“原始”图像,而是返回具有compressionQuality最大值的图像的 JPEG 再现。这实际上可以产生比原始资源更大的对象(至少如果原始图像是 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. 如果你想要一个NSDatawith 压缩,你可以使用UIImageJPEGRepresentationwith a compressionQualityless than 1.0。您的代码实际上使用compressionQualityof来执行此操作0.0,它应该提供最大的压缩。但是您不保存它NSData,而是使用它来创建 a UIImage,然后您会得到一个UIImageJPEGRepresentation带有 a的新compressionQuality1.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]);
    
  4. 除了前面提到的 JPEG 压缩质量外,您还可以调整图像大小。您也可以将它与 JPEG 结合使用compressionQuality

于 2013-06-09T10:47:22.203 回答
1

您不能一次又一次地压缩图像。如果是这样,一切都可以一次又一次地压缩。那你觉得它会小到什么程度呢?

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

于 2013-06-09T01:57:45.313 回答
-1

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

于 2013-06-09T02:42:56.107 回答