【问题标题】:Producing CCITT compressed TIFF from CGImage从 CGImage 生成 CCITT 压缩的 TIFF
【发布时间】:2009-04-16 22:14:04
【问题描述】:

我有一个 CGImage(核心图形,C/C++)。是灰度。好吧,原来是黑白的,但CGImage可能是RGB的。那应该没关系。我想创建一个 CCITT-Group 4 TIFF。

我可以通过使用正确的字典创建目标并添加图像来创建 LZW TIFF(灰度或彩色)。没问题。

但是,似乎没有等效的 kCGImagePropertyTIFFCompression 值来表示 CCITT-4。它应该是 4,但这会产生未压缩。

我有一个手动 CCITT 压缩例程,所以如果我能获得二进制(每像素 1 位)数据,我就准备好了。但我似乎无法从 CGImage 中获取 1 个 BPP 数据。我有代码应该将 CGImage 放入 CGBitmapContext 然后给我数据,但它似乎给了我全黑。

我今天问了几个问题试图解决这个问题,但我只是想,让我们问我真正想回答的问题,看看是否有人可以回答。

必须有办法做到这一点。我必须错过一些愚蠢的东西。这是什么?

【问题讨论】:

    标签: c++ macos core-graphics cgimage


    【解决方案1】:

    这似乎有效并产生了非全黑输出。可能有一种方法可以做到这一点,不涉及首先手动转换为灰度,但至少它有效!

    static void WriteCCITTTiffWithCGImage_URL_(CGImageRef im, CFURLRef url) {
        // produce grayscale image
        CGImageRef grayscaleImage;
        {
            CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
            CGContextRef bitmapCtx = CGBitmapContextCreate(NULL, CGImageGetWidth(im), CGImageGetHeight(im), 8, 0, colorSpace, kCGImageAlphaNone);
            CGContextDrawImage(bitmapCtx, CGRectMake(0,0,CGImageGetWidth(im), CGImageGetHeight(im)), im);
            grayscaleImage = CGBitmapContextCreateImage(bitmapCtx);
            CFRelease(bitmapCtx);
            CFRelease(colorSpace);
        }
    
        // generate options for ImageIO. Man this sucks in C.
        CFMutableDictionaryRef options = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
        {
            {
                CFMutableDictionaryRef tiffOptions = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
                int fourInt = 4;
                CFNumberRef fourNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &fourInt);
                CFDictionarySetValue(tiffOptions, kCGImagePropertyTIFFCompression, fourNumber);
                CFRelease(fourNumber);
    
                CFDictionarySetValue(options, kCGImagePropertyTIFFDictionary, tiffOptions);
    
                CFRelease(tiffOptions);                
            }
    
            {
                int oneInt = 1;
                CFNumberRef oneNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &oneInt);
    
                CFDictionarySetValue(options, kCGImagePropertyDepth, oneNumber);
    
                CFRelease(oneNumber);
            }
        }
    
        // write file
        CGImageDestinationRef idst = CGImageDestinationCreateWithURL(url, kUTTypeTIFF, 1, NULL);
        CGImageDestinationAddImage(idst, grayscaleImage, options);
        CGImageDestinationFinalize(idst);
    
        // clean up
        CFRelease(idst);
        CFRelease(options);
        CFRelease(grayscaleImage);
    }
    
    
    Nepheli:tmp ken$ tiffutil -info /tmp/output.tiff 
    Directory at 0x1200
      Image Width: 842 Image Length: 562
      Bits/Sample: 1
      Sample Format: unsigned integer
      Compression Scheme: CCITT Group 4 facsimile encoding
      Photometric Interpretation: "min-is-black"
      Orientation: row 0 top, col 0 lhs
      Samples/Pixel: 1
      Number of Strips: 1
      Planar Configuration: Not planar
    

    【讨论】:

    • 是 Objective C 还是 C++?它看起来像一个奇怪的组合。在 C++ 中,我认为压缩 4 不起作用。它提供未压缩的...
    • 您编写的语言不会影响 API 的行为。这是Objective-C。我会把它重写为纯 C 给你。
    • 好的,编辑为纯 C。它应该编译为 C++。 CGImageDestination 覆盖 libtiff 并通过 unmolested 进行压缩。我发现我必须明确传递 depth == 1 和灰度图像才能使其工作。如果您在 Google 上搜索 libtiff 和“CCITT Group 4”,您会看到有人提出相关问题。
    • intfourInt = 4;我会将其更改为类似 int comprType = NSTIFFCompressionLZW;它更具可读性。
    • Matthieu Cormier:如果提问者没有使用 Cocoa,那么该常量不可用。
    【解决方案2】:

    ImageMagick 几乎可以转换为任何图像格式。由于它是开源的,您可以阅读source code 来找到您问题的答案。

    如果您使用 C++,您甚至可以在您的应用中使用 ImageMagick API

    编辑:
    如果您可以以任何格式从 CGImage 获取数据(听起来您可以),您可以使用 ImageMagick 将其从您从 CGImage 获得的任何格式转换为 ImageMagick 支持的任何其他格式(您想要的 TIFF 格式)。

    编辑: Technical Q&A QA1509 Getting the pixel data from a CGImage object 状态:

    在 Mac OS X 10.5 或更高版本上,添加了一个新调用,允许您从 CGImage 对象获取实际像素数据。此调用 CGDataProviderCopyData 返回一个 CFData 对象,其中包含来自相关图像的像素数据。

    获得像素数据后,您可以使用 ImageMagick 对其进行转换。

    【讨论】:

    • 这无济于事,因为它实际上根本不显示图像。因此,它不处理 CGImage 对象。假设我有 1Bit 数据,我已经有了读取第 4 组文件并编写它们的代码。我需要以可以编写 TIFF 的方式从 CGImage 中获取数据...
    • 如果你能以任何格式从 CGImage 获取数据(听起来你可以),你可以使用 ImageMagick 将它从你从 CGImage 获取的任何格式转换为任何其他格式支持ImageMagick(您想要的 TIFF 格式)。
    • 好吧,我似乎无法从 CGImage 中获取二进制数据...我可以将文档保存为其他格式,但我宁愿不保存,然后再转换...
    • @Brian Postow 从 CGImage 获取数据的格式并不重要。任何格式都可以,因为 ImageMagick 非常灵活,可以将其转换为许多其他格式。这就是图书馆的目的。
    • 问题是我无法以任何格式获得它,除了 CGImage。如果我能正确地得到位图,我已经完成了......我可以使用 macs 保存例程保存图像,但它们不会保存 CCITT....
    【解决方案3】:

    NSBitmapImageRep 声称能够生成 CCITT FAX Group 4 压缩 TIFF。所以这样的事情可能会奏效(未经测试):

    CFDataRef tiffFaxG4DataForCGImage(CGImageRef cgImage) {
      NSBitmapImageRep *imageRep =
          [[[NSBitmapImageRep alloc] initWithCGImage:cgImage] autorelease];
      NSData *tiffData =
          [imageRep TIFFRepresentationUsingCompression:NSTIFFCompressionCCITTFAX4
                                                factor:0.0f];
      return (CFDataRef) tiffData;
    }
    

    这个函数应该返回你寻找的数据。

    【讨论】:

    • 我认为那是 Objective C,而不是 C++。
    • 是的 - 但为什么会有这样的问题? Objective-C 是 C 的严格超集,如您所见,您可以轻松地将 Objective-C 代码包装在 C 函数中,然后从 C 代码中使用它。事实上,Apple 为他们的一些 C API 这样做 - 将 C 函数包装在 Objective-C 实现周围。
    • 在没有自动释放池的情况下,自动释放对象会导致控制台垃圾邮件和内存泄漏(在这种情况下非常严重)。
    猜你喜欢
    • 1970-01-01
    • 2020-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多