2

我正在尝试编写一个原型来证明从一种格式到另一种格式的 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: 根据彼得对使用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 告诉的第二种方法。这给出了有趣的结果。它的效果与将finder中的文件重命名为“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];
    }
}
4

3 回答 3

1

我要尝试的第一件事根本不涉及 NSImage 或 NSBitmapImageRep。相反,我会为源文件创建一个 CGImageSource 并为目标文件创建一个 CGImageDestination,并用于CGImageDestinationAddImageFromSource将所有图像从 A 传输到 B。

于 2013-03-17T09:10:15.740 回答
1

您在此代码中两次转换为 TIFF:

  1. 你创建一个 NSImage,我假设来自源文件。
  2. 你向 NSImage 索要它的TIFFRepresentation(TIFF 转换 #1)。
  3. 您从第一个 TIFF 数据创建一个 NSBitmapImageRep。
  4. 您要求 NSBitmapImageRep 生成第二个 TIFF 表示(TIFF 转换 #2)。

考虑直接从源数据创建一个 NSBitmapImageRep,而不是使用 NSImage。然后,您将直接跳到步骤 4 以生成输出数据。

(但我还是会CGImageDestinationAddImageFromSource先尝试。)

于 2013-03-17T09:13:43.503 回答
0

原始图像文件有自己的(专有的)表示。例如,它们可能使用每个组件 14 位和马赛克图案,您的代码不支持这些。我认为您应该使用较低级别的 API 并对您尝试保存的 RAW 格式进行真正的逆向工程。

我将从 DNG 开始,这相对容易,因为 Adob​​e 提供了一个 SDK 来编写它。

于 2014-04-29T21:52:53.480 回答