2

CGImageDestination を使用して、インデックス付きの色とアルファ値 (RGBA) を持つ PNG ファイルを書き込もうとしています。カラータイプ3とtRNSチャンクの画像であるPNG仕様に関して。プログラムの別の部分から、インデックスのマトリックスと添付されたパレットを取得しています。

インデックス付きの画像をアルファ値なしで (つまり、不透明な色のみ) 書き込むことに成功しました。ドキュメントに従ってアルファ値を追加すると、生成された画像はカラー タイプ 3 (パレット) を使用しなくなりますが、完全な RGBA 画像 (カラー タイプ 6) になります。実際の PNG ファイルでは、アルファ値は基本的にパレット エントリに関連付けられています。明示的な RGBA 色空間を作成する方法はないようです。

libpng または他の PNG ライブラリを直接使用して、目的のエンコーディングを実現できます。ただし、可能であればCGImageとその友達だけを使用したいと思います。

TL;DR: CGImage/CGImageDestination を使用してアルファ値を持つインデックス付き PNG ファイルを作成するにはどうすればよいですか?

非常によく似た質問が 2 年前に既に寄せられていました ( Create and write paletted RGBA PNG using NSImage ) が、Cocoa に関するものであり、解決策はありませんでした。

私のテストコードは次のとおりです。USE_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 を使用したアルファ値付きの説明:

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

1 に答える 1