【问题标题】:Converting NSData to CGImage and then back to NSData makes the file too big将 NSData 转换为 CGImage 然后再转换回 NSData 会使文件太大
【发布时间】:2013-10-22 20:41:03
【问题描述】:

我使用AVFoundation 构建了一个相机。

一旦我的AVCaptureStillImageOutput 完成了它的captureStillImageAsynchronouslyFromConnection:completionHandler: 方法,我就会创建一个这样的NSData 对象:

         NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];

一旦我有了NSData 对象,我想旋转图像而不转换为UIImage。我发现我可以转换为 CGImage 来这样做。

获得 imageData 后,我开始转换为 CGImage 的过程,但我发现 CGImageRef 最终比 NSData 对象大 30 倍。

这是我用来从NSData 转换为CGImage 的代码:

CGDataProviderRef imgDataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)(imageData));
CGImageRef imageRef = CGImageCreateWithJPEGDataProvider(imgDataProvider, NULL, true, kCGRenderingIntentDefault);

如果我尝试将NSLog 缩小图像的大小,当NSData 是1.5-2 兆字节的图像时,它会达到30 兆字节!

size_t imageSize = CGImageGetBytesPerRow(imageRef) * CGImageGetHeight(imageRef);

    NSLog(@"cgimage size = %zu",imageSize);

我想也许当你从 NSData 转到 CGImage 时,图像会解压缩,然后如果我转换回 NSData,它可能会恢复到正确的文件大小。

imageData = (NSData *) CFBridgingRelease(CGDataProviderCopyData(CGImageGetDataProvider(imageRef)));

上述NSDataCGImageRef 对象具有相同的length

如果我尝试保存图像,该图像是无法打开的 30mb 图像。

我对使用 CGImage 完全陌生,所以我不确定我是否在从 NSData 转换为 CGImage 并错误地转换回来,或者我是否需要调用一些方法再次解压缩。

提前致谢,

【问题讨论】:

  • 您是否尝试过使用CGImageCreateWithJPEGDataProvider() 的参数?例如不插值或不同的渲染意图?这些可能会影响压缩。例如,插值可以很容易地增加文件大小,因为颜色混合会增加图像中表示的颜色数量。
  • @RyanPoolos 将 shouldInterpolate 设置为 No 似乎对文件大小没有影响。我想尽可能地保留原始图像,但似乎其他东西正在影响我的代码......即使图像是 30 兆,我是否仍然能够保存和查看它,我不能现在?

标签: ios objective-c nsdata cgimage cgimageref


【解决方案1】:

我正在做一些图像处理,并在 SO 上遇到了您的问题。似乎没有其他人想出答案,所以这是我的理论。

虽然理论上可以按照您描述的方式将 CGImageRef 转换回 NSData,但数据本身是无效的,而不是真正的 JPEGPNG,正如您发现的那样不可读。所以我不认为NSData.length 是正确的。您实际上必须跳过许多步骤才能重新创建 CGImageRefNSData 表示:

// incoming image data
NSData *image;

// create the image ref
CGDataProviderRef imgDataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef) image);
CGImageRef imageRef = CGImageCreateWithJPEGDataProvider(imgDataProvider, NULL, true, kCGRenderingIntentDefault);

// image metadata properties (EXIF, GPS, TIFF, etc)
NSDictionary *properties;

// create the new output data
CFMutableDataRef newImageData = CFDataCreateMutable(NULL, 0);
// my code assumes JPEG type since the input is from the iOS device camera
CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef) @"image/jpg", kUTTypeImage);
// create the destination
CGImageDestinationRef destination = CGImageDestinationCreateWithData(newImageData, type, 1, NULL);
// add the image to the destination
CGImageDestinationAddImage(destination, imageRef, (__bridge CFDictionaryRef) properties);
// finalize the write
CGImageDestinationFinalize(destination);

// memory cleanup
CGDataProviderRelease(imgDataProvider);
CGImageRelease(imageRef);
CFRelease(type);
CFRelease(destination);

NSData *newImage = (__bridge_transfer NSData *)newImageData;

通过这些步骤,newImage.length 应该与image.length 相同。我没有测试,因为我实际上在输入和输出之间进行裁剪,但是根据裁剪,大小大致是我预期的(输出大约是输入像素的一半,因此输出长度大约是大小的一半输入长度)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    • 2019-02-15
    • 1970-01-01
    • 1970-01-01
    • 2016-09-14
    • 1970-01-01
    • 2018-07-17
    相关资源
    最近更新 更多