我正试图写一个原型来证明从一种格式到另一种格式的RAW转换是可能的。我必须将尼康的。nef格式的原始文件转换为佳能的。cr2格式。在各种帖子的帮助下,我创建了原始图像TIFF表示的BitmapImageRep,并使用它来编写具有。cr2扩展名的输出文件。
它确实工作,但对我来说唯一的问题是,输入文件是21.5 MB,但我得到的输出是144.4 MB。而使用NSTIFFCompressionPackBits
给我142.1 MB。
我想知道发生了什么,我尝试了各种可用的压缩枚举,但都没有成功。
请帮我理解一下。这是源代码:
@interface NSImage(RawConversion)
- (void) saveAsCR2WithName:(NSString*) fileName;
@end
@implementation NSImage(RawConversion)
- (void) saveAsCR2WithName:(NSString*) fileName
{
// Cache the reduced image
NSData *imageData = [self TIFFRepresentation];
NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageData];
// http://www.cocoabuilder.com/archive/cocoa/151789-nsbitmapimagerep-compressed-tiff-large-files.html
NSDictionary *imageProps = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:NSTIFFCompressionJPEG],NSImageCompressionMethod,
[NSNumber numberWithFloat: 1.0], NSImageCompressionFactor,
nil];
imageData = [imageRep representationUsingType:NSTIFFFileType properties:imageProps];
[imageData writeToFile:fileName atomically:NO];
}
@end
我怎么能得到的输出文件,这是在CR2格式,但几乎周围的输入文件的大小变化不大,需要一个CR2文件?
编辑1:根据Peter使用CGImageDestinationAddImageFromSource
方法的建议进行了更改,但我仍然得到相同的结果。输入源NEF文件大小为21.5 MB,转换后的目标文件大小为144.4 MB。
请查看代码:
-(void)saveAsCR2WithCGImageMethodUsingName:(NSString*)inDestinationfileName withSourceFile:(NSString*)inSourceFileName
{
CGImageSourceRef sourceFile = MyCreateCGImageSourceRefFromFile(inSourceFileName);
CGImageDestinationRef destinationFile = createCGImageDestinationRefFromFile(inDestinationfileName);
CGImageDestinationAddImageFromSource(destinationFile, sourceFile, 0, NULL);
//https://developer.apple.com/library/mac/#documentation/graphicsimaging/Conceptual/ImageIOGuide/ikpg_dest/ikpg_dest.html
CGImageDestinationFinalize(destinationFile);
}
CGImageSourceRef MyCreateCGImageSourceRefFromFile (NSString* path)
{
// Get the URL for the pathname passed to the function.
NSURL *url = [NSURL fileURLWithPath:path];
CGImageSourceRef myImageSource;
CFDictionaryRef myOptions = NULL;
CFStringRef myKeys[2];
CFTypeRef myValues[2];
// Set up options if you want them. The options here are for
// caching the image in a decoded form and for using floating-point
// values if the image format supports them.
myKeys[0] = kCGImageSourceShouldCache;
myValues[0] = (CFTypeRef)kCFBooleanTrue;
myKeys[1] = kCGImageSourceShouldAllowFloat;
myValues[1] = (CFTypeRef)kCFBooleanTrue;
// Create the dictionary
myOptions = CFDictionaryCreate(NULL, (const void **) myKeys,
(const void **) myValues, 2,
&kCFTypeDictionaryKeyCallBacks,
& kCFTypeDictionaryValueCallBacks);
// Create an image source from the URL.
myImageSource = CGImageSourceCreateWithURL((CFURLRef)url, myOptions);
CFRelease(myOptions);
// Make sure the image source exists before continuing
if (myImageSource == NULL){
fprintf(stderr, "Image source is NULL.");
return NULL;
}
return myImageSource;
}
CGImageDestinationRef createCGImageDestinationRefFromFile (NSString *path)
{
NSURL *url = [NSURL fileURLWithPath:path];
CGImageDestinationRef myImageDestination;
//https://developer.apple.com/library/mac/#documentation/graphicsimaging/Conceptual/ImageIOGuide/ikpg_dest/ikpg_dest.html
float compression = 1.0; // Lossless compression if available.
int orientation = 4; // Origin is at bottom, left.
CFStringRef myKeys[3];
CFTypeRef myValues[3];
CFDictionaryRef myOptions = NULL;
myKeys[0] = kCGImagePropertyOrientation;
myValues[0] = CFNumberCreate(NULL, kCFNumberIntType, &orientation);
myKeys[1] = kCGImagePropertyHasAlpha;
myValues[1] = kCFBooleanTrue;
myKeys[2] = kCGImageDestinationLossyCompressionQuality;
myValues[2] = CFNumberCreate(NULL, kCFNumberFloatType, &compression);
myOptions = CFDictionaryCreate( NULL, (const void **)myKeys, (const void **)myValues, 3,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
//https://developer.apple.com/library/mac/#documentation/graphicsimaging/Conceptual/ImageIOGuide/imageio_basics/ikpg_basics.html#//apple_ref/doc/uid/TP40005462-CH216-SW3
CFStringRef destFileType = CFSTR("public.tiff");
// CFStringRef destFileType = kUTTypeJPEG;
CFArrayRef types = CGImageDestinationCopyTypeIdentifiers(); CFShow(types);
myImageDestination = CGImageDestinationCreateWithURL((CFURLRef)url, destFileType, 1, myOptions);
return myImageDestination;
}
编辑2:使用了@Peter告诉的第二种方法。这给出了有趣的结果。它的效果与在查找器中将文件重命名为"example_image"相同。NEF"到"example_image.CR2"。令人惊讶的是,在程序转换和finder转换时,21.5 MB的源文件将变成59 KB。这在代码中没有任何压缩设置。请参阅代码并提出建议:
-(void)convertNEFWithTiffIntermediate:(NSString*)inNEFFile toCR2:(NSString*)inCR2File
{
NSData *fileData = [[NSData alloc] initWithContentsOfFile:inNEFFile];
if (fileData)
{
NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:fileData];
// [imageRep setCompression:NSTIFFCompressionNone
// factor:1.0];
NSDictionary *imageProps = nil;
NSData *destinationImageData = [imageRep representationUsingType:NSTIFFFileType properties:imageProps];
[destinationImageData writeToFile:inCR2File atomically:NO];
}
}
我要尝试的第一件事根本不涉及NSImage或NSBitmapImageRep。相反,我会为源文件创建CGImageSource,为目标文件创建CGImageDestination,并使用CGImageDestinationAddImageFromSource
将所有图像从a传输到b。
在此代码中,您将两次转换为TIFF:
- 你创建一个NSImage,我假设从源文件。
- 你问NSImage的
TIFFRepresentation
(TIFF转换#1)。 - 从第一个TIFF数据创建一个NSBitmapImageRep。
- 你要求NSBitmapImageRep生成第二个TIFF表示(TIFF转换#2)。
考虑直接从源数据创建一个NSBitmapImageRep,而不使用NSImage。然后直接跳到步骤4,生成输出数据。
(但我仍然会尝试CGImageDestinationAddImageFromSource
第一)
原始图像文件有自己的(专有的)表示。例如,它们可能每个组件使用14位,以及马赛克模式,这是您的代码不支持的。我认为你应该使用较低级别的API,并对你想保存的RAW格式进行反向工程。
我会从DNG开始,这相对容易,因为Adobe提供了一个SDK来编写它。