ios 不使用 UIImagePngrepresentation 或 UIImageJpegRepresentation 将 UIImage 转换为 NSData

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15239719/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:35:57  来源:igfitidea点击:

Convert UIImage to NSData without using UIImagePngrepresentation or UIImageJpegRepresentation

iosuiimagensdataassetsuiimagepngrepresentation

提问by H Bastan

I Need to convert UIImageto NSDatabut without using UIImagePngRepresentationor UIImageJpegRepresentation, for images from photolib i can use assetlib method as mentioned here Using ALAssetsLibrary and ALAsset take out Image as NSData, but for captured image , assset url is not there hence in that case i need to convert UIImagedirectly to bytes with exif data , how can i accomplish this ? please help

我需要转换UIImageNSData但不使用UIImagePngRepresentationor UIImageJpegRepresentation,对于来自 photolib 的图像,我可以使用这里提到的 assetlib 方法使用 ALAssetsLibrary 和 ALAsset 取出图像作为 NSData,但是对于捕获的图像,资产 url 不存在,因此在这种情况下我需要转换UIImage直接到带有 exif 数据的字节,我怎样才能做到这一点?请帮忙

采纳答案by Wes

H Bastan,

H巴斯坦,

Based on your comment:

根据您的评论:

...I want to save the captured image return by device camera, through UIImagepicker delegate method in document directory...

...我想通过文档目录中的 UIImagepicker 委托方法保存设备相机返回的捕获图像...

It looks like your realgoal is to save the image with EXIF data to the documents directory and not specifically getting the UIImage as an NSData object with the EXIF data. In that case, you can do the following in your implementation of imagePickerController:didFinishPickingMediaWithInfo:

看起来您的真正目标是将带有 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);

From my tests the execution time was about the same or faster than doing:

从我的测试来看,执行时间与执行时间大致相同或更快:

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

...and you get to keep the EXIF data!

...您可以保留 EXIF 数据!

You could also dispatch it to a background queue if you want to make sure your UI stays responsive:

如果你想确保你的 UI 保持响应,你也可以将它分派到后台队列:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{

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

Important Note:You will need to add the ImageIO.frameworkand the MobileCoreServices.frameworkto your target's build phases and import them in the class where you do the image saving:

重要说明:您需要将ImageIO.framework和添加MobileCoreServices.framework到目标的构建阶段,并将它们导入到您保存图像的类中:

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

Other notesIt is my understanding that in this case we're not creating a generation loss when saving the image as proposed in the example. We are using UIImage's CGImage property and as the documentation states:

其他说明根据我的理解,在这种情况下,我们不会按照示例中的建议保存图像时产生代损失。我们正在使用 UIImage 的 CGImage 属性,并且如文档所述:

The underlying Quartz image data

底层 Quartz 图像数据

回答by Taz

I had a similar problem, but for security reasons I didn't want to write the data to the default file system as suggested by Wes. I also wanted to be able to add metadata to my image. My solution was as follows:

我遇到了类似的问题,但出于安全原因,我不想按照 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;
}

To use it, you would do the following:

要使用它,您将执行以下操作:

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

    // ...
}

回答by Anil

You can try something like this. Not sure if its the best method. But worth a shot. Incase the image URL is available, you can try initWithContentsOfUrl

你可以尝试这样的事情。不确定它是否是最好的方法。但值得一试。如果图片网址可用,您可以尝试initWithContentsOfUrl

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