compresión de imágenes por tamaño – iPhone SDK

Me gustaría comprimir imágenes (cámara / biblioteca de fotos) y luego enviarlas al servidor. Sé que puedo comprimir por alto y ancho, pero me gustaría comprimir las imágenes por tamaño a un tamaño fijo (200 KB) solamente y mantener la altura y el ancho originales. El factor de escala en JPEGRepresentation no representa el tamaño y la calidad de compresión. ¿Cómo puedo lograr esto (comprimir a un tamaño fijo) sin utilizar ninguna biblioteca de terceros? Gracias por cualquier ayuda.

    Aquí hay un código de ejemplo que intentará comprimir una imagen para que no exceda la compresión máxima o el tamaño máximo de archivo

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

    Una forma de hacerlo es volver a comprimir el archivo en un bucle, hasta que encuentre el tamaño deseado. Primero puede encontrar el alto y el ancho, y adivinar el factor de compresión (imagen más grande más compresión) luego de comprimirlo, verificar el tamaño y dividir la diferencia nuevamente.

    Sé que esto no es muy eficiente, pero no creo que haya una sola llamada para lograr una imagen de un tamaño específico.

    Aquí, JPEGRepresentation consume bastante memoria y si lo usamos en Loop, consume mucha memoria. Por lo tanto, use el código siguiente e ImageSize no será más de 200 KB.

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

    Después de hacer algunas pruebas, pude encontrar una relación entre el tamaño de la imagen y el valor de compresión . Como esta relación es lineal para todos los valores en los que la compresión es menor que 1, creé un algoritmo para tratar de comprimir siempre las imágenes a un valor determinado.

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

    Tomé la respuesta de @kgutteridge e hice una solución similar para Swift 3.0 usando recursivo:

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