このエントリー
をはてなブックマークに追加
published on in PNG
tags: PNG ImageMagick Format

ImageMagick で PNG の形式を変換

ImageMagick で PNG の形式を変換

PNG は見た目が同じ画像でも、バイナリ的に色んな形式で表現できます。ImageMagick でそれらの形式に変換する方法を並べてみます。

カラータイプ

PNG は以下の5種類のカラータイプがあります。仕様書からコピペします。

Color Type Allowed Bit Depths Interpretation
0 1,2,4,8,16 Each pixel is a grayscale sample.
2 8,16 Each pixel is an R,G,B triple.
3 1,2,4,8 Each pixel is a palette index; a PLTE chunk must appear.
4 8,16 Each pixel is a grayscale sample, followed by an alpha sample.
6 8,16 Each pixel is an R,G,B triple, followed by an alpha sample.

日本語に訳しつつ、いくつか情報を追記してみます。

カラー型 ビット
深度
PLTE tRNS ピクセル値の解釈
0 1,2,4,8,16 × グレースケール
2 8,16 R,G,B (PNG24)
3 1,2,4,8 必須○ インデックスカラー。(PNG8)
4 8,16 × × グレースケールの後ろにアルファ値。つまり YA
6 8,16 × R,G,B の後ろにアルファ値。つまり RGBA (PNG32)

Type:0 グレースケール

黒:0〜白:2^(bit数)-1 の範囲の値を並べるだけの形式です。 bit数は 1,2,4,8,16 から選択できて、例えば、bit数が 1 であれば白黒2値の 1 or 0。bit 数が 8 であれば、0〜255=(2^8-1) の階調を持ちます。

$ convert Opaopa.png -type Grayscale Opaopa-type0.png
  • 尚、tRNS チャンクをつける事で透明ピクセルも表現できます。

Type:2 RGB (PNG24)

ピクセルの R,G,B をそのまま展開します。

$ convert Opaopa.png png24:Opaopa-png24.png

PNG32 から PNG24 に変換しても透明度は消えますが、tRNS 付きの PNG8 からは tRNS を引き継げます。但し半透明は表現できず透明か不透明かのどちらかに割り当てられます。

$ convert Opaopa-png8-trns.png png24:Opaopa-png24-trns.png
  • tRNS チャンクをつける事で透明ピクセルも表現できます。但し、どの色を透明にするかを指定する方式なので、透明か不透明のどちらかで半透明は表現できません。大人しく Type 6 の RGBA 形式を使いましょう。
  • PLTE チャンクをつける事で擬似カラー端末で表示する時のパレットを指定できます。今時レアですが。(sPLT とおなじ?)

Type:3 パレット (PNG8)

色のパレットを持ち、そこへのインデックス値を並べて画像を表現します。

$ convert Opaopa.png  png8:Opaopa-png8.png

tRNS チャンクをつける事で透明度も表現できます。

パレット形式 の Bit Depth について

Type:3 パレットの Bit Depth は特殊で、RGB 値の Bit Depth ではありません。 RGB の色パレットを指すインデックスの Bit 幅を示します。 具体的な影響としては、Bit Depth によりパレット数が制限されます。

Bit Depths Max Palette Number
1 2^1 = 2
2 2^2 = 4
4 2^4 = 16
8 2^8 = 256

Bit Depth に何を指定しても RGB 色パレットは 8bit 固定の色深度を持つ事に注意して下さい。

Type:4 透明度つきグレースケール

グレースケールの値と透明度のセットで表現します。

$ convert Opaopa.png -type GrayscaleMatte  Opaopa-type4.png

Type:6 RGBA (PNG32)

ピクセルの R,G,B,A を展開します。

$ convert Opaopa.png  png32:Opaopa-png32.png

インターレース

PNG のインターレースは独特で、Adam7 アルゴリズムを使います。

インターレース方式 Adam7

$ convert Opaopa.png -interlace PNG Opaopa-adam7.png

ピクセルの並ぶ順番

  • 8x8 のブロックで左上のを1つ
  • 4x4 のブロックで左上を1つ
  • 2x2 のブロックで左上を1つ
  • 残り全部

という順でピクセルを保存します。

ピクセル 実際の表示

ちなみに上記画像は ImageMagick で以下のように生成できます。(-fx オプション便利!)

  • インターレースのフェーズ別画像
$ convert Opaopa-dot1.png -filter Point -fx "!(i%8)*!(j%8)*u" Opaopa-dot1-adam7-1.png
$ convert Opaopa-dot1.png -filter Point -fx "!(i%4)*!(j%4)*u" Opaopa-dot1-adam7-2.png
$ convert Opaopa-dot1.png -filter Point -fx "!(i%2)*!(j%2)*u" Opaopa-dot1-adam7-3.png
  • フェーズ別画像ピクセル補完あり
$ convert  Opaopa-dot1.png -filter Point -fx "p{i-i%8,j-j%8}" Opaopa-dot1-adam7-1-cmpl.png
$ convert  Opaopa-dot1.png -filter Point -fx "p{i-i%4,j-j%4}" Opaopa-dot1-adam7-2-cmpl.png
$ convert  Opaopa-dot1.png -filter Point -fx "p{i-i%2,j-j%2}" Opaopa-dot1-adam7-3-cmpl.png
  • ドット絵風の拡大画像
$ convert Opaopa-dot1-adam7-1.png -filter Point -resize 800% -fx "(i%8>0)*(j%8>0)*u" Opaopa-dot8-adam7-1.png
<略>

メタデータ

gAMA (ガンマ補正)

単純にガンマ値を指定します。BigEndian の4byteで表現していて、ガンマ値を100000倍した値を格納します。逆にいうと、バイナリを整数として読み出し、1/100000 した値がガンマ値です。

cHRM (基本色度)

基本色度やホワイトバランスを指定します。 尚、sRGB 又は iCPP チャンクがある場合、cHRM チャンクは無効です。

iCPP (ICC プロファイル)

ICC プロファイルを埋め込めます。 (JPEG と同じ要領です)

$ convert Opaopa.png -profile sRGB.icc Opaopa-sRGB.png
$ convert Opaopa.png -profile GBR.icc Opaopa-GBR.png
$ convert Opaopa-sRGB.png -profile GBR.icc Opaopa-sRGB-GBR.png
$ convert Opaopa-sRGB-GBR.png -strip Opaopa-sRGB-GBR-strip.png

JPEG の時と同じのようです。

  • 元画像ファイルに ICC プロファイルがない場合
    • => 単に ICC プロファイルを付けるだけ
  • ICC プロファイルがあった場合
    • => ICCプロファイルを上書きしつつ、それで見た目の色が変わらないよう画像データのRGBも書き換える

bKGD (背景色)

背景色を指定します。 画像が貼られた時に埋まらなかったピクセルを埋める色です。

メタデータ (おまけ)

pHYs

DPI ならぬ DPM (インチでなくメートル単位) で物理的な解像度を指定します。印刷に影響するかもしれません。 単位がインチでなくメートルなので少し計算が面倒です。

sBIT

元画像データの Bit深度を記録します。 例えば医療画像で見かける12ビット画像を記録したくても、PNG はそのままでは対応していません。仮に16ビットに変換して保存するとビット深度の相互変換で誤差が生じます。 この sBIT チャンクがあると、16ビットのうち上位12ビットだけ有効といった意味付けが可能で、ビットシフトで値を劣化させずに保存、取り出しができます。 ただし、残念なが ImageMagick は対応していません。。

参考 URL