2012-10-31 7 views
6

Sto cercando di trovare un modo per leggere e scrivere immagini JPEG nella galleria utente (rullino fotografico) senza ricomprimerlo da iOS. UIImage sembra essere il collo di bottiglia qui. L'unico metodo per salvare nella galleria utente che ho trovato è UIImageWriteToSavedPhotosAlbum(). C'è un modo per aggirare questo?Salvataggio/recupero di JPEG dalla galleria utente senza ricompressione

Per ora la mia routine assomiglia a questo

-Chiedere UIImagePickerController una foto. E quando didFinishPickingMediaWithInfo, fare:

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

-Process JPEG senza perdita di qualità su disco.

-Allora salvarlo di nuovo:

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

Ecco una piccola animazione di ciò che il degrado della qualità assomiglia dopo 3 passaggi:

JPEG quality degradation

C'è di peggio, ovviamente, ogni volta che faccio questo , ma non ho potuto automatizzare la parte di selezione delle immagini per testarla completamente per 50/100/1000 cicli.

risposta

10

UIImage decodifica i dati di immagine in modo che possa essere modificato e visualizzato, quindi

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

sarebbe prima decodificare l'immagine, e di codificare indietro dal metodo UIImageWriteToSavedPhotosAlbum.

Invece, si dovrebbe usare ALAssetsLibrary/writeImageDataToSavedPhotosAlbum:metadata:completionBlock:, qualcosa di simile:

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

Si può anche passare i metadati e il blocco di completamento alla chiamata.

EDIT:

Per ottenere l'immagine:

[info objectForKey:@"UIImagePickerControllerOriginalImage"] contiene il decodificato UIImage selezionato dalla UIImagePickerController. Si dovrebbe invece usare

NSURL *assetURL = [info objectForKey:UIImagePickerControllerReferenceURL]; 

Utilizzando il assetURL ora è possibile ottenere il ALAsset per esso con il metodo ALAssetsLibrary/assetForURL:resultBlock:failureBlock::

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

È ora possibile ottenere l'inalterata NSData di quell'immagine:

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

Potrei aver commesso alcuni errori nel codice, ma i passaggi sono elencati sopra. Nel caso in cui qualcosa non funzioni correttamente o se vuoi renderlo un po 'più efficiente, ci sono molti esempi di cose come leggere NSData da un ALAsset su stackoverflow o altri siti.

+0

Sì, grazie, ho già scoperto il trucco con AssetsLibrary. Spero che la tua risposta sarà utile per gli altri. – Kai