web-dev-qa-db-fra.com

Convertir UIImage en NSData sans utiliser UIImagePngrepresentation ou UIImageJpegRepresentation

J'ai besoin de convertir UIImage en NSData mais sans utiliser UIImagePngRepresentation ni UIImageJpegRepresentation, pour les images de photolib, je peux utiliser la méthode assetlib comme mentionné ici Utilisation de ALAssetsLibrary et ALAsset prennent Image comme NSData , mais pour l'image capturée, assset url n'y figure Par conséquent, dans ce cas, j'ai besoin de convertir UIImage directement en octets avec des données EXIF, comment puis-je accomplir cela? s'il vous plaît aider

21
H Bastan

H Bastan,

Basé sur votre commentaire:

... Je souhaite enregistrer le retour d'image capturée par la caméra du périphérique, via la méthode de délégation UIImagepicker dans le répertoire du document ...

Il semble que votre objectif real consiste à enregistrer l'image avec les données EXIF ​​dans le répertoire de documents et à ne pas obtenir spécifiquement UIImage en tant qu'objet NSData avec les données EXIF. Dans ce cas, vous pouvez effectuer les opérations suivantes dans votre implémentation de imagePickerController:didFinishPickingMediaWithInfo:

// Get your image.
UIImage *capturedImage = [info objectForKey:UIImagePickerControllerOriginalImage];

// Get your metadata (includes the EXIF data).
NSDictionary *metadata = [info objectForKey:UIImagePickerControllerMediaMetadata];

// Create your file URL.
NSFileManager *defaultManager = [NSFileManager defaultManager];
NSURL *docsURL = [[defaultManager URLsForDirectory:NSDocumentDirectory
                                         inDomains:NSUserDomainMask] lastObject];
NSURL *outputURL = [docsURL URLByAppendingPathComponent:@"imageWithEXIFData.jpg"];

// Set your compression quuality (0.0 to 1.0).
NSMutableDictionary *mutableMetadata = [metadata mutableCopy];
[mutableMetadata setObject:@(1.0) forKey:(__bridge NSString *)kCGImageDestinationLossyCompressionQuality];

// Create an image destination.
CGImageDestinationRef imageDestination = CGImageDestinationCreateWithURL((__bridge CFURLRef)outputURL, kUTTypeJPEG , 1, NULL);
if (imageDestination == NULL ) {

    // Handle failure.
    NSLog(@"Error -> failed to create image destination.");
    return;
}

// Add your image to the destination.
CGImageDestinationAddImage(imageDestination, capturedImage.CGImage, (__bridge CFDictionaryRef)mutableMetadata);

// Finalize the destination.
if (CGImageDestinationFinalize(imageDestination) == NO) {

    // Handle failure.
    NSLog(@"Error -> failed to finalize the image.");
}

CFRelease(imageDestination);

D'après mes tests, le temps d'exécution était à peu près identique ou plus rapide que celui effectué:

NSData *data = UIImageJPEGRepresentation(capturedImage, 1.0);
[data writeToURL:outputURL atomically:YES];

... et vous gardez les données EXIF!

Vous pouvez également l'envoyer dans une file d'attente en arrière-plan si vous voulez vous assurer que votre interface utilisateur reste sensible:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{

    // Do the image saving here...
});

Remarque importante: Vous devrez ajouter le ImageIO.framework et le MobileCoreServices.framework aux phases de construction de votre cible, puis les importer dans la classe dans laquelle vous enregistrez les images:

#import <ImageIO/ImageIO.h>
#import <MobileCoreServices/MobileCoreServices.h>

Autres remarques .__ Je crois comprendre que dans ce cas, nous ne créons pas de perte de génération lors de l’enregistrement de l’image proposée dans l’exemple. Nous utilisons la propriété CGImage de UIImage et, comme l'indique la documentation:

Les données d'image sous-jacentes à Quartz

17
Wes

J'ai eu un problème similaire, mais pour des raisons de sécurité, je ne voulais pas écrire les données dans le système de fichiers par défaut, comme suggéré par Wes. Je voulais aussi pouvoir ajouter des métadonnées à mon image. Ma solution était la suivante:

- (NSData *)dataFromImage:(UIImage *)image metadata:(NSDictionary *)metadata mimetype:(NSString *)mimetype
{
    NSMutableData *imageData = [NSMutableData data];
    CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef)mimetype, NULL);
    CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, uti, 1, NULL);

    if (imageDestination == NULL)
    {
        NSLog(@"Failed to create image destination");
        imageData = nil;
    }
    else
    {
        CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)metadata);

        if (CGImageDestinationFinalize(imageDestination) == NO)
        {
            NSLog(@"Failed to finalise");
            imageData = nil;
        }
        CFRelease(imageDestination);
    }

    CFRelease(uti);

    return imageData;
}

Pour l'utiliser, vous feriez ce qui suit:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
    NSDictionary *metadata = [info objectForKey:UIImagePickerControllerMediaMetadata];
    NSString *mimeType = @"image/jpeg"; // ideally this would be dynamically set. Not defaulted to a jpeg!

    // you could add to the metadata dictionary (after converting it to a mutable copy) if you needed to.

    // convert to NSData
    NSData *imageData = [self dataFromImage:image metadata:metadata mimetype:mimeType];

    // ...
}
21
Taz

Vous pouvez essayer quelque chose comme ça. Pas sûr que ce soit la meilleure méthode. Mais ça vaut le coup. Si l'URL de l'image est disponible, vous pouvez essayer initWithContentsOfUrl

NSData *data = [[NSData alloc]initWithContentsOfFile:@"/Users/test/isajf/isajf/test.jpg"];
0
Anil