按大小压缩图像 – iPhone SDK

我想压缩图像(相机/照片库),然后将其发送到服务器。 我知道我可以按高度和宽度进行压缩,但是我想按大小将图像压缩到固定大小(200 KB),并保持原始高度和宽度。 JPEGRepresentation中的比例因子不代表大小,仅代表压缩质量。 我怎样才能达到这个(压缩到一个固定的大小),而不使用任何第三方库? 谢谢你的帮助。

下面是一些示例代码,它们将尝试为您压缩图像,以使其不超过最大压缩或最大文件大小

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); } 

一种方法是在循环中重新压缩文件,直到find所需的大小。 您可以先查找高度和宽度,然后猜测压缩因子(更大图像更多压缩),然后在压缩它之后,检查大小并再次分割差异。

我知道这不是超高效,但我不相信有一个单一的电话来实现一个特定的大小的图像。

在这里,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; } 

在做了一些testing后,我能够find图像大小和压缩值之间的关系 。 由于这种关系对于压缩小于1的所有值是线性的,所以我创build了一个algorithm来总是将图像压缩到某个值。

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

我采取了@kgutteridge的答案,并使用recursion为Swift 3.0做了类似的解决scheme:

 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 } } 
 - (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 ; }