【问题标题】:NSImage + NSBitmapImageRep = Converting RAW image file from one format to anotherNSImage + NSBitmapImageRep = 将 RAW 图像文件从一种格式转换为另一种格式
【发布时间】:2013-03-17 07:36:38
【问题描述】:

我正在尝试编写一个原型来证明从一种格式到另一种格式的 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];
    }
}

【问题讨论】:

  • 如果您使用的是 NSImage 和 NSBitmapImageRep,为什么要将此标记为 [cocoa-touch]?
  • 抱歉,感谢指正。我是一名 iOS 开发人员,习惯于这样标记它。现在将尝试您提到的两种方法。
  • 在 Finder 中重命名文件会将其大小更改为 59 K?这不可能。
  • 令人惊讶的是正在发生的事情。
  • NSImage 可以读取几乎所有类型的文件,包括 NEF 和 CR2,但 NSBitmapImageRep 只能为我们提供以下文件类型之一:NSTIFFFileType、NSBMPFileType、NSGIFFileType、NSJPEGFileType、NSPNGFileType、NSJPEG2000FileType。这是否意味着无法从 BitmapImageRep 中写入 CR2 文件?

标签: cocoa tiff nsimage nsbitmapimagerep


【解决方案1】:

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

【讨论】:

  • 我已经采用了这种方法,但还没有成功 :( 请查看我编辑的问题,其中包含最近的代码。现在尝试下一个方法。
  • @Raj:你使用了相同的输出格式,所以你当然得到了相同的结果。如果您想要 CR2 数据,请询问,而不是 TIFF。
  • 但是我们如何从以下可用中获取 CR2 数据? NSTIFFFileType、NSBMPFileType、NSGIFFileType、NSJPEGFileType、NSPNGFileType、NSJPEG2000FileType
  • @Raj:注意我们评论的是哪个答案。这些类型用于 NSBitmapImageRep,而不是 CGImageDestination。
  • @Raj:UTI 比这多得多,但那些是 CGImageDestination 支持的。我不知道相机供应商提供或不提供什么。但是,您似乎无法使用 CGImageDestination 或 NSBitmapImageRep 来执行此操作;假设你不能使用 Core Image 来做到这一点(我知道它可以 read 原始图像,但这也是其他两个 API 中已解决的问题),你将不得不获取其他人的库来做这个或者写你自己的代码来做。
【解决方案2】:

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

  1. 我假设您从源文件创建了一个 NSImage。
  2. 您向 NSImage 询问其 TIFFRepresentation(TIFF 转换 #1)。
  3. 您从第一个 TIFF 数据创建一个 NSBitmapImageRep。
  4. 您要求 NSBitmapImageRep 生成第二个 TIFF 表示(TIFF 转换 #2)。

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

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

【讨论】:

  • 如您所说,请查看我的问题中的“编辑 2”,有什么遗漏吗?有没有其他方法可以达到同样的效果?
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-20
    • 2016-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-26
    • 1970-01-01
    相关资源
    最近更新 更多