将 NSData 转换为 CGImage 然后再转换回 NSData 会使文件太大 [英] Converting NSData to CGImage and then back to NSData makes the file too big

查看:118
本文介绍了将 NSData 转换为 CGImage 然后再转换回 NSData 会使文件太大的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have built a camera using AVFoundation.

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

Once my AVCaptureStillImageOutput has completed its captureStillImageAsynchronouslyFromConnection:completionHandler: method, I create a NSData object like this:

         NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];

一旦我有了 NSData 对象,我想旋转图像 - 无需 - 转换为 UIImage.我发现我可以转换为 CGImage 来这样做.

Once I have the NSData object, I would like to rotate the image -without- converting to a UIImage. I have found out that I can convert to a CGImage to do so.

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

After I have the imageData, I start the process of converting to CGImage, but I have found that the CGImageRef ends up being THIRTY times larger than the NSData object.

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

Here is the code I use to convert to CGImage from NSData:

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

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

If I try to NSLog out the size of the image, it comes to 30 megabytes when the NSData was a 1.5-2 megabyte image!

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

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

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

I thought that maybe when you go from NSData to CGImage, the image decompresses, and then maybe if I converted back to NSData, that it might go back to the right file size.

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

上面的NSDataCGImageRef 对象具有相同的length.

The above NSData has the same length as the CGImageRef object.

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

If I try to save the image, the image is a 30mb image that cannot be opened.

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

I am totally new to using CGImage, so I am not sure if I am converting from NSData to CGImage and back incorrectly, or if I need to call some method to decompress again.

提前致谢,

推荐答案

我在做一些图像处理时遇到了你关于 SO 的问题.似乎没有其他人想出答案,所以这是我的理论.

I was doing some image manipulation and came across your question on SO. Seems like no one else came up with an answer, so here's my theory.

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

While it's theoretically possible to convert a CGImageRef back to NSData in the manner that you described, the data itself is invalid and not a real JPEG or PNG, as you discovered by it not being readable. So I don't think that the NSData.length is correct. You have to actually jump through a number of steps to recreate an NSData representation of a CGImageRef:

// 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 相同.我没有测试,因为我实际上在输入和输出之间进行了裁剪,但是根据裁剪,大小大致是我的预期(输出大约是输入像素的一半,因此输出长度大约是大小的一半输入长度).

With these steps, the newImage.length should be the same as image.length. I haven't tested since I actually do cropping between the input and the output, but based on the crop, the size is roughly what I expected (the output is roughly half the pixels of the input and thus the output length roughly half the size of the input length).

这篇关于将 NSData 转换为 CGImage 然后再转换回 NSData 会使文件太大的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆