para - compresión de imágenes por tamaño-iPhone SDK
app para comprimir videos iphone gratis (6)
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);
}
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
}
}
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.
- (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 ;
}