2012-02-29 93 views
24

我想壓縮圖像(相機/照片庫),然後將其發送到服務器。我知道我可以按高度和寬度進行壓縮,但我想按大小將圖像壓縮到固定大小(200 KB),並保持原始高度和寬度。 JPEGRepresentation中的比例因子不代表大小,僅代表壓縮質量。如何在不使用任何第三方庫的情況下實現這一點(壓縮到固定大小)? 感謝您的幫助。圖像壓縮的大小 - iPhone SDK

+0

有一個在SDK中沒有它的API。正如你發現的那樣,你可以通過分辨率或質量來調整大小。我們遇到了同樣的問題,最終我們決定調整屏幕顯示並縮小85%,這極大地縮小了文件大小,但卻提供了非常好的圖像質量。 – 2012-02-29 22:20:33

回答

62

繼承人一些示例代碼,將嘗試壓縮您的圖像,使其不超過或者是最大壓力或最大文件大小

CGFloat compression = 0.9f; 
CGFloat maxCompression = 0.1f; 
int maxFileSize = 250*1024; 

NSData *imageData = UIImageJPEGRepresentation(yourImage, compression); 

while ([imageData length] > maxFileSize && compression > maxCompression) 
{ 
    compression -= 0.1; 
    imageData = UIImageJPEGRepresentation(yourImage, compression); 
} 
+2

上面的書面代碼很棒:)。但我希望我的圖像壓縮到20 kb,我試着玩你的代碼。但只能得到200 kb左右的大小,你能指導我怎樣才能達到20 kb。 – 2013-08-12 10:17:43

+0

@DeepK上面的解決方案是壓縮原始圖像。最大壓縮可能不會讓您期待的解決方案。因此,從壓縮數據創建圖像,然後再次壓縮圖像,直到獲得所需的圖像。只是一個想法。 – CodetrixStudio 2015-02-17 14:01:40

+0

@Codetrix感謝您提出解決方案。 – 2015-02-18 04:34:56

3

做到這一點的一種方法是在循環中重新壓縮文件,直到找到所需的大小。您可以先查找高度和寬度,然後猜測壓縮因子(更大圖像更多壓縮),然後在壓縮它之後,檢查大小並再次分割差異。

我知道這不是超高效的,但我不相信有一個電話來實現特定大小的圖像。

1

這裏,JPEGRepresentation是相當耗費內存,如果我們使用在循環中,所以它是非常高的內存消耗。因此,使用下面的代碼& ImageSize不會超過200KB。

UIImage* newImage = [self captureView:yourUIView]; 


- (UIImage*)captureView:(UIView *)view { 
CGRect rect = view.bounds; 
UIGraphicsBeginImageContext(rect.size); 
CGContextRef context = UIGraphicsGetCurrentContext(); 

[view.layer renderInContext:context]; 
UIImage* img = [UIImage alloc]init]; 
img = UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 
NSLog(@"img=%@",img); 
return img; 
} 
-1
- (UIImage *)resizeImageToSize:(CGSize)targetSize 
{ 
    UIImage *sourceImage = captureImage; 
    UIImage *newImage = nil; 

    CGSize imageSize = sourceImage.size; 
    CGFloat width = imageSize.width; 
    CGFloat height = imageSize.height; 

    CGFloat targetWidth = targetSize.width; 
    CGFloat targetHeight = targetSize.height; 

    CGFloat scaleFactor = 0.0; 
    CGFloat scaledWidth = targetWidth; 
    CGFloat scaledHeight = targetHeight; 

    CGPoint thumbnailPoint = CGPointMake(0.0,0.0); 

    if (CGSizeEqualToSize(imageSize, targetSize) == NO) { 

     CGFloat widthFactor = targetWidth/width; 
     CGFloat heightFactor = targetHeight/height; 

     if (widthFactor < heightFactor) 
      scaleFactor = widthFactor; 
     else 
      scaleFactor = heightFactor; 

     scaledWidth = width * scaleFactor; 
     scaledHeight = height * scaleFactor; 

     // make image center aligned 
     if (widthFactor < heightFactor) 
     { 
      thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
     } 
     else if (widthFactor > heightFactor) 
     { 
      thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5; 
     } 
    } 

    UIGraphicsBeginImageContext(targetSize); 
    CGRect thumbnailRect = CGRectZero; 
    thumbnailRect.origin = thumbnailPoint; 
    thumbnailRect.size.width = scaledWidth; 
    thumbnailRect.size.height = scaledHeight; 

    [sourceImage drawInRect:thumbnailRect]; 
    newImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    if(newImage == nil) 
     NSLog(@"could not scale image"); 

    return newImage ; 
} 
+0

問題是特別要求_file size_,而不是圖像尺寸 – bengoesboom 2016-03-23 22:16:32

0

做了一些測試後,我能找到 A relationship between image size and compression value。由於這種關係對於壓縮小於1的所有值都是線性的,因此我創建了一種算法來嘗試將圖像壓縮到某個值。

//Use 0.99 because at 1, the relationship between the compression and the file size is not linear 
NSData *image = UIImageJPEGRepresentation(currentImage, 0.99); 
float maxFileSize = MAX_IMAGE_SIZE * 1024; 

//If the image is bigger than the max file size, try to bring it down to the max file size 
if ([image length] > maxFileSize) { 
    image = UIImageJPEGRepresentation(currentImage, maxFileSize/[image length]); 
} 
+2

這個答案是不正確和誤導。請考慮刪除它 – ikbal 2017-06-16 09:06:42

0

我把@kgutteridge的答案,並提出了用遞歸雨燕3.0類似的解決方案:

extension UIImage { 
    static func compress(image: UIImage, maxFileSize: Int, compression: CGFloat = 1.0, maxCompression: CGFloat = 0.4) -> Data? { 

     if let data = UIImageJPEGRepresentation(image, compression) { 

      let bcf = ByteCountFormatter() 
      bcf.allowedUnits = [.useMB] // optional: restricts the units to MB only 
      bcf.countStyle = .file 
      let string = bcf.string(fromByteCount: Int64(data.count)) 
      print("Data size is: \(string)") 

      if data.count > (maxFileSize * 1024 * 1024) && (compression > maxCompression) { 
       let newCompression = compression - 0.1 
       let compressedData = self.compress(image: image, maxFileSize: maxFileSize, compression: newCompression, maxCompression: maxCompression) 
       return compressedData 
      } 

      return data 
     } 

     return nil 
    } 
}