【问题标题】:Convert UIImage to NSData without using UIImagePngrepresentation or UIImageJpegRepresentation不使用 UIImagePngrepresentation 或 UIImageJpegRepresentation 将 UIImage 转换为 NSData
【发布时间】:2013-02-20 19:02:55
【问题描述】:

我需要将UIImage 转换为NSData,但不使用UIImagePngRepresentationUIImageJpegRepresentation,对于来自photolib 的图像,我可以使用此处提到的assetlib 方法Using ALAssetsLibrary and ALAsset take out Image as NSData,但对于捕获的图像,资产URL 不是因此,在这种情况下,我需要将UIImage 直接转换为带有 exif 数据的字节,我该如何做到这一点?请帮忙

【问题讨论】:

  • 为什么?多平台原因?这是我能想到的唯一原因...好吧,如果是这种情况,请尝试使用 LodePNG lodev.org/lodepng
  • 通过使用 uiimage png 和 jpeg 表示,图像的大小会发生变化,即使压缩质量为 1.0,jpeg 的图像质量也会降低。我需要一种将 UIImage 直接转换为字节的方法。
  • 当然图片的大小是不同的……这就是压缩的本质。否则所有图片都会有一个巨大的文件大小(wxhx4 字节)。此外,您的大小将根据文件的尺寸而有所不同。我认为你需要比现在更好地描述你的问题。
  • 存储在 photolib 中的文件已经是压缩格式了,现在当我们使用 uipngrepresentation 时,然后 1. 解压缩文件并重新压缩它(如果我可以直接转换存储的压缩图像,这是一个开销在 photolib 到数据中,则可以避免此过程) 2. 使用 png 表示 EXIF 数据丢失,因为该图像显示 90 roated
  • 你说的是 UIImage。如果你有一个 UIImage,那么你已经解压缩了数据。故事结局。不过,您似乎不想使用 UIImage 。您只想更改现有 PNG 上的 EXIF 数据?

标签: ios uiimage nsdata assets uiimagepngrepresentation


【解决方案1】:

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

    // ...
}

【讨论】:

  • 使用 UIImageJpegRepresentation 的 5% 左右的执行时间要好得多。但它使用大致相同的内存。但至少它会在很短的时间内保留该内存。
【解决方案2】:

H 巴斯坦,

根据您的评论:

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

看起来您的真正目标是将带有 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 图像数据

【讨论】:

  • 感谢它真的很有帮助,这样,如果我不设置压缩质量,它会使用原始图像压缩质量保存,这对我来说很好,图像数据大小也与 photolib 相同,因此这是做到这一点的完美方式,谢谢。
  • sry cmets 用于以下解决方案 :) 没有尝试你的
  • 我已经被困了很长一段时间了。但是由于您的解决方案,我可以继续前进。谢谢
【解决方案3】:

你可以试试这样的。不确定它是否是最好的方法。但值得一试。如果有图片地址,可以试试initWithContentsOfUrl

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

【讨论】:

  • 嗨,谢谢,但我使用 uiimagepicker 来捕获图像,这里它只返回 uiimage n 而不是图像的 url,因此上述方法没有用
猜你喜欢
  • 1970-01-01
  • 2015-08-17
  • 2011-09-22
  • 1970-01-01
  • 2010-12-21
  • 2013-11-29
  • 2015-06-13
  • 1970-01-01
相关资源
最近更新 更多