Guardar / get JPEG de la galería de usuarios sin recompression

Estoy tratando de encontrar una manera de leer y escribir imágenes JPEG en la galería de usuarios (rollo de camera) sin que iOS las vuelva a comprimir. UIImage parece ser el cuello de botella aquí. El único método para save en la galería de usuarios que encontré es UIImageWriteToSavedPhotosAlbum (). ¿Hay alguna forma de evitar esto?

Por ahora mi rutina se parece a esto

-Ask UIImagePickerController para una foto. Y cuando didFinishPickingMediaWithInfo, haz lo siguiente:

NSData *imgdata = [NSData dataWithData:UIImageJPEGRepresentation([info objectForKey:@"UIImagePickerControllerOriginalImage"], 1)]; [imgdata writeToFile:filePath atomically:NO]; 

-Procesar JPEG sin pérdida en el disco.

-Entonces guárdelo de nuevo:

 UIImageWriteToSavedPhotosAlbum([UIImage imageWithContentsOfFile:[self getImagePath]], self, @selector(image:didFinishSavingWithError:contextInfo:), nil); 

Aquí hay una pequeña animation de cómo se ve la degradación de la calidad después de 3 pases:

Degradación de calidad JPEG

Obviamente empeora cada vez que hago esto, pero no pude automatizar la parte de selección de imágenes para probarlas por completo durante ciclos de 50/100/1000.

UIImage decodifica los datos de la image para que pueda editarse y mostrarse, por lo que

 UIImageWriteToSavedPhotosAlbum([UIImage imageWithContentsOfFile:[NSData dataWithContentsOfFile:[self getImagePath]]], self, @selector(image:didFinishSavingWithError:contextInfo:), nil); 

decodificaría primero la image y la codificaría de nuevo mediante el método UIImageWriteToSavedPhotosAlbum .

En su lugar, debe usar ALAssetsLibrary / writeImageDataToSavedPhotosAlbum: metadata: completionBlock: algo como esto:

 ALAssetsLibrary *assetLib = [[[ALAssetsLibrary alloc] init] autorelease]; [assetLib writeImageDataToSavedPhotosAlbum:[self getImagePath] metadata:nil completionBlock:nil]; 

También puede pasar los metadatos y el bloque de finalización a la llamada.

EDITAR:

Para get la image:

[info objectForKey:@"UIImagePickerControllerOriginalImage"] contiene el UIImagePickerController decodificado seleccionado de UIImagePickerController . En su lugar, deberías usar

 NSURL *assetURL = [info objectForKey:UIImagePickerControllerReferenceURL]; 

Usando el assetURL ahora puede get el ALAsset para él usando ALAssetsLibrary / assetForURL: resultBlock: failureBlock: method:

 ALAssetsLibrary *assetLib = [[[ALAssetsLibrary alloc] init] autorelease]; [assetLib assetForURL:assetURL resultBlock:resultBlock failureBlock:failureBlock]; 

Ahora puede get NSData inalterada de esa image:

 ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *asset){ ALAssetRepresentation *assetRep = [asset defaultRepresentation]; long long imageDataSize = [assetRepresentation size]; uint8_t* imageDataBytes = malloc(imageDataSize); [assetRepresentation getBytes:imageDataBytes fromOffset:0 length:imageDataSize error:nil]; NSData *imageData = [NSData dataWithBytesNoCopy:imageDataBytes length:imageDataSize freeWhenDone:YES]; // you could for instance read data in smaller buffers and append them to your file instead of reading it all at once // save it [imgdata writeToFile:filePath atomically:NO]; }; ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror){ NSLog(@"Cannot get image - %@",[myerror localizedDescription]); // }; 

Es posible que haya cometido algunos errores en el código, pero los pasos son los enumerados anteriormente. En caso de que algo no funcione bien, o si desea hacer esto un poco más eficiente, hay muchos ejemplos de cosas como leer NSData desde un ALAsset en stackoverflow u otros sitios.