【问题标题】:Mac OS X/iOS: How to write indexed PNG image using RGBA colours through CGImage?Mac OS X/iOS:如何通过 CGImage 使用 RGBA 颜色编写索引 PNG 图像?
【发布时间】:2013-08-12 01:28:16
【问题描述】:

我正在尝试使用 CGImageDestination 编写具有索引颜色和 alpha 值 (RGBA) 的 PNG 文件。就PNG specification 而言,它是颜色类型为 3 和 tRNS 块的图像。我从程序的一个单独部分得到一个索引矩阵和一个附加的调色板。

我已经成功地编写了没有 alpha 值的索引图像(即只有不透明的颜色)。如果我按照文档添加 alpha 值,则生成的图像不再使用颜色类型 3(调色板),而是变成完整的 RGBA 图像(颜色类型 6)。在实际的 PNG 文件中,alpha 值基本上附加到调色板条目。似乎没有办法创建明确的 RGBA 颜色空间。

我可以直接使用 libpng 或其他 PNG 库来实现所需的编码。但是,如果可能的话,我宁愿只使用 CGImage 和朋友。

TL;DR:如何使用 CGImage/CGImageDestination 生成具有 alpha 值的索引 PNG 文件?

两年前已经提出了一个非常相似的问题 (Create and write paletted RGBA PNG using NSImage),但它谈到了 Cocoa,并没有得到解决方案。

我的测试代码如下。如果在编译时定义了USE_ALPHA,则生成的图像使用 alpha 值。否则不会。

/* Compilation command (tested with Xcode 4.6.3 on Mac OS X 10.8.4):
 *
 * clang++ -std=c++11 -stdlib=libc++ -framework ApplicationServices -DUSE_ALPHA -o demo demo.cpp
 */

#include <utility>
#include <vector>
#include <array>

#include <ApplicationServices/ApplicationServices.h>

/* R, G, B */
const std::vector<std::array<std::uint8_t, 3>> colortable = {
  { 0xF0, 0x10, 0x10 },
  { 0x20, 0xF0, 0x20 },
  { 0x30, 0x30, 0xF0 },
  { 0xF0, 0xF0, 0x40 },
  { 0x50, 0xF0, 0xF0 },
};

/* Colour index, alpha */
const std::vector<std::uint8_t> data = {
  3, 0x30,
  2, 0x20,
  1, 0x10,
  0, 0x00,

  4, 0x40,
  3, 0x30,
  2, 0x20,
  1, 0x10,
};

void safeCfRelease(const ::CFTypeRef ref) {
  if (ref != nullptr) {
    ::CFRelease(ref);
  }
}

int main() {
  const std::shared_ptr<const ::__CFURL>
      url(::CFURLCreateWithFileSystemPath(nullptr, CFSTR("out.png"),
                                          ::kCFURLPOSIXPathStyle, false),
          safeCfRelease);

  const std::shared_ptr<::CGDataProvider>
    prov_data(::CGDataProviderCreateWithData(nullptr, &data[0], data.size(), nullptr),
              safeCfRelease);

  const std::shared_ptr<::CGColorSpace>
    gray(::CGColorSpaceCreateDeviceGray(), safeCfRelease),
    rgb(::CGColorSpaceCreateDeviceRGB(), safeCfRelease),
    indexed(::CGColorSpaceCreateIndexed(rgb.get(), colortable.size(),
                  reinterpret_cast<const unsigned char *>(&colortable[0])),
            safeCfRelease);

  const auto bitmap_info =
#ifdef USE_ALPHA
    ::kCGImageAlphaLast |
#else
    ::kCGImageAlphaNoneSkipLast |
#endif
    ::kCGBitmapByteOrderDefault;

  const std::shared_ptr<::CGImage>
    image(::CGImageCreate(/* width */ 4,
                          /* height */ 2,
                          /* bitsPerComponent */ 8,
                          /* bitsPerPixel */ 16,
                          /* bytesPerRow */ 8,
                          indexed.get(),
                          bitmap_info,
                          prov_data.get(), nullptr, false,
                          ::kCGRenderingIntentDefault),
          safeCfRelease);

  const std::shared_ptr<::CGImageDestination>
    dest(::CGImageDestinationCreateWithURL(url.get(), ::kUTTypePNG, 1, nullptr),
         safeCfRelease);

  ::CGImageDestinationAddImage(dest.get(), image.get(), nullptr);
  ::CGImageDestinationFinalize(dest.get());
}

file 对不透明颜色的描述(这也适用于使用 ImageMagick 生成的具有 tRNS 块的图像):

PNG image data, 4 x 2, 8-bit colormap, non-interlaced

使用 CGImageDestination 的 alpha 值描述:

PNG image data, 4 x 2, 8-bit/color RGBA, non-interlaced

【问题讨论】:

    标签: macos cocoa png core-foundation cgimage


    【解决方案1】:

    不知道这是否可行,但您尝试过 UIImagePNGRepresentation() 吗?

    CGImage cgimg;   //initialize this with the CGImage that you want to be a PNG 
    UIImage* image = [UIImage imageWithCGImage:cgimg];
    NSData* pngData = UIImagePNGRepresentation(image);
    CGImageRelease(cgimg);
    

    希望这会有所帮助!

    【讨论】:

    • 不幸的是,我看不到如何使用 UIImagePNGRepresentation 指定调色板(并且 UIKit 与 Quartz 2D 不同,在 Mac OS X 上不可用)。从那以后我开始使用LodePNG 来编写图像。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 2011-06-22
    • 1970-01-01
    • 2016-07-12
    • 2018-07-25
    相关资源
    最近更新 更多