对于这个问题,我只询问在没有外部库的情况下使用 Xcode 和 iOS 的可能性。我已经在探索在另一个 question 中使用 libtiff
的可能性.
问题
数周以来,我一直在筛选堆栈溢出,并为我的每一个问题找到了可行的解决方案。我有 4 件事需要工作:
- 我需要来自相机的 RGBA 数据,没有任何压缩
- 我需要尽可能多的元数据,尤其是 EXIF
- 我需要以 TIFF 格式保存以与其他软件兼容和无损
- 我需要通过保存在文件而不是照片库中来防止随意查看
我可以使用 JPEG 得到 2 和 4。 我可以将 1、3 和 4 与从相机缓冲区制作的原始数据(分别为 NSData)一起使用。 我可以通过 Xcode 和 iOS 满足所有 4 个先决条件吗?我即将放弃并寻找您的意见作为最后的手段。
虽然仍在探索这个问题,但我也停留在我尝试过的另一条途径上,libtiff .不过我还在努力……
这是我尝试过的重要建议的列表,我自己的代码只是从这些堆栈溢出源中拼凑而成:
- How to write exif metadata to an image (not the camera roll, just a UIImage or JPEG) (让我希望我可以使用 JPEG 格式,做 Apple 喜欢的事情时它是如此轻松)
- Raw image data from camera like “645 PRO” (这将是使用的重点,例如 libtiff )
- Saving CGImageRef to a png file? (也适用于
kUTTypeTIFF
,但没有元数据)
解决方案
captureStillImageAsynchronouslyFromConnection
的完整操作序列:
[[self myAVCaptureStillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error)
{
//get all the metadata in the image
CFDictionaryRef metadata = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, imageSampleBuffer, kCMAttachmentMode_ShouldPropagate);
// get image reference
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(imageSampleBuffer);
// >>>>>>>>>> lock buffer address
CVPixelBufferLockBaseAddress(imageBuffer, 0);
//Get information about the image
uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
// create suitable color space
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
//Create suitable context (suitable for camera output setting kCVPixelFormatType_32BGRA)
CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
// <<<<<<<<<< unlock buffer address
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
// release color space
CGColorSpaceRelease(colorSpace);
//Create a CGImageRef from the CVImageBufferRef
CGImageRef newImage = CGBitmapContextCreateImage(newContext);
// release context
CGContextRelease(newContext);
// create destination and write image with metadata
CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:filePath isDirectory:NO];
CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypeTIFF, 1, NULL);
CGImageDestinationAddImage(destination, imageRef, metadata);
// finalize and release destination
CGImageDestinationFinalize(destination);
CFRelease(destination);
}
静态图像输出相关的相机设置是:
[[self myAVCaptureSession] setSessionPreset:AVCaptureSessionPresetPhoto];
和
NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], (id)kCVPixelBufferPixelFormatTypeKey, nil];
[myAVCaptureStillImageOutput setOutputSettings:outputSettings];
我得到了一张标称 TIFF 格式的标称未压缩图像,其中包含所有元数据。 (它在其他系统上有镜像,但现在我可以编写 EXIF 和其他元数据,我也可以对其进行微调,我确信)。
再次感谢 Wildaker感谢他的帮助!
最佳答案
由于您已经破解了 1、3 和 4,看来您缺少的唯一障碍是将数据和元数据保存在一起。试试这个(假设未处理的数据在名为 myImageDataSampleBuffer
的 CMSampleBufferRef
中,并且您已经完成了将图形数据放入 CGImageRef
的繁重工作称为 myImage
):
CFDictionaryRef metadata = CMCopyDictionaryOfAttachments(kCFAllocatorDefault,
myImageDataSampleBuffer,
kCMAttachmentMode_ShouldPropagate);
NSFileManager* fm = [[NSFileManager alloc] init];
NSURL* pathUrl = [fm URLForDirectory:saveDir
inDomain:NSUserDomainMask
appropriateForURL:nil
create:YES
error:nil];
NSURL* saveUrl = [pathUrl URLByAppendingPathComponent:@"myfilename.tif"];
CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)saveUrl,
(CFStringRef)@"public.tiff", 1, NULL);
CGImageDestinationAddImage(destination, myImage, metadata);
CGImageDestinationFinalize(destination);
CFRelease(destination);
关于avfoundation - 如何将来自 AVFoundations captureStillImageAsynchronouslyFromConnection 的 TIFF 照片保存到 iPhone (iOS) 上带有 EXIF 元数据的文件中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17361100/