NSImage + NSBitmapImageRep =将RAW图像文件从一种格式转换为另一种格式

时间:2013-03-17 07:36:39

标签: cocoa tiff nsimage nsbitmapimagerep

我正在尝试编写一个原型来证明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讲述的第二种方法。这给出了有趣的结果。它的效果与在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];
    }
}

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

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

  1. 您创建了一个NSImage,我假设来自源文件。
  2. 您向NSImage询问其TIFFRepresentation(TIFF转换#1)。
  3. 您可以从第一个TIFF数据创建NSBitmapImageRep。
  4. 您要求NSBitmapImageRep生成第二个TIFF表示(TIFF转换#2)。
  5. 考虑直接从源数据创建NSBitmapImageRep,而根本不使用NSImage。然后,您将直接跳到第4步以生成输出数据。

    (但我仍然会首先尝试CGImageDestinationAddImageFromSource。)

答案 2 :(得分:0)

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

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

相关问题