web-dev-qa-db-ja.com

UIImagePngrepresentationまたはUIImageJpegRepresentationを使用せずにUIImageをNSDataに変換する

UIImageNSDataに変換する必要がありますが、UIImagePngRepresentationまたはUIImageJpegRepresentationを使用せずに、photolibの画像の場合、ここで説明したようにassetlibメソッドを使用できます ALAssetsLibraryとALAssetを使用すると、画像がNSData として取り出されますが、キャプチャされた画像の場合、assset urlが存在しないため、UIImageをexifデータを含むバイトに直接変換する必要があります。これを行うにはどうすればよいですか?助けてください

22
H Bastan

Hバスタン、

あなたのコメントに基づいて:

...キャプチャした画像をデバイスのカメラで返して、UIImagepickerデリゲートメソッドを介してドキュメントディレクトリに保存したい...

あなたのreal目標は、EXIFデータを含む画像をドキュメントディレクトリに保存することであり、UIImageをEXIFデータを含むNSDataオブジェクトとして具体的に取得することではありません。その場合、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);

私のテストから、実行時間は実行時間とほぼ同じかそれよりも高速でした:

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

...そしてあなたはEXIFデータを保持するようになります!

UIの応答性を維持したい場合は、バックグラウンドキューにディスパッチすることもできます。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{

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

重要な注意:ImageIO.frameworkMobileCoreServices.frameworkをターゲットのビルドフェーズに追加し、イメージの保存を行うクラスにインポートする必要があります。

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

その他の注意事項この例では、例で提案されているように画像を保存するときに世代損失が発生しないことを理解しています。 UIImageのCGImageプロパティを使用しており、ドキュメントには次のように記載されています。

基本となるQuartz画像データ

17
Wes

私も同様の問題を抱えていましたが、セキュリティ上の理由から、Wesの提案に従ってデフォルトのファイルシステムにデータを書き込みたくありませんでした。また、画像にメタデータを追加できるようにしたいと思っていました。私の解決策は次のとおりです:

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

これを使用するには、次のようにします。

- (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

このようなものを試すことができます。それが最善の方法かどうかはわかりません。しかし、一撃の価値があります。画像のURLが利用できる場合は、initWithContentsOfUrlを試すことができます

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