モブ沢工房

プログラミングとかLinux関連(特にOSSのグラフィックツール関連)とかレトロゲームとか3Dプリンタやら日曜大工等、色々。

続:gimpのpngエクスポートとAzDrawingについて(解決編) & ccacheもおまけ

さてAzDrawingのソースにあたって見ましたが、IDAT関連も全く問題ないのでありました。 結論から申しますとAzDrawingのバグではなく、 まったくの濡れ衣でありました。恥ずかしい限りです。

しかし結果は相変わらず… gimpからエクスポートしたpngは、まったくの真っ黒を表示してしまいます。

f:id:dothiko:20141202170054j:plain

ちなみに、この画像です。(はてなフォトライフにアップロードした段階で中身が変換されていなければいいのですが…) 

f:id:dothiko:20141202170129p:plain

何故だ。

と思ってAzDrawingのソースを駆け巡り、いじって遊んでいたら発見しました。 オイラの想定通りの表示を行える処理が…

それはimg/CTileImg.cppの376行目あたりでした。

    for(iy = h; iy > 0; iy--, pd += 64 - w, ps += sw - w)
    {
        for(ix = w; ix > 0; ix--, pd++, ps++)
        {
            if(bAlpha)
                *pd = ps->a;
            else
                *pd = 255 - ((ps->r * 77 + ps->g * 150 + ps->b * 29) >> 8);
        }
    }

ここのbAlphaフラグによるアルファピクセル値での置換処理をコメントアウトすると、「ちゃんと」表示されます。

f:id:dothiko:20141202170108j:plain

ではこの処理が間違いなのか…といえば、この処理は正しいのです。

何もいじらない状態、真っ黒で表示されるのが正しい処理、ということです。

オイラの考え方がそもそも間違っていたのですね。

なぜかというと、AzDrawingには白という概念がないからです。*1

AzDrawingは8bitモノクロ用画像描画ソフトですが、このモノクロというのは白〜黒ではなく、透明〜黒なのです!白く見えているのは最下段のキャンバスであり、レイヤの色ではないのですね。

当たり前ですね…そうでないと8bitでは、レイヤの下が見れませんからね。白で見えません。 一方、白・黒・透明だと、それはもう16bitとかになってしまいます。

そしてgimpからエクスポートしたpngはアルファチャネル8ビット付きの24ビットカラー、合計32ビットの画像なわけですが…この最大の問題点は「アルファチャネルがあるのに全領域が不透明」であったことです。

不透明な部分は黒で表現されるべきなので、全てのピクセルは黒で表現されるべきとなり、全部が黒で塗りつぶされるのは当たり前なのですね。論理的に考えて。もしそうしないと、今度は透明な部分があるpngが正常に認識されないということになります。

一方、これがアルファチャネルのない不透明なpngであるならば、白→黒を透明→黒に変換するのは理にかなっています。不透明なpngには再現すべきアルファチャネルがそもそもないのですから…

この現象は、一見同じに見える、「全域不透明の24bitモノクロ風png」と「アルファチャネルはあるけど全域不透明に描いた32bitモノクロ風png」によって起きた正しい挙動であり、オイラの錯誤でした…orz

おまけ:ccacheについて

そんなわけでAzDrawingをいじるのにMakefileのg++のところをccache g++にしてみましたが、これは速くて実に快適でした。今までC++コンパイルが遅いからイヤーンとか思ってましたがこれなら十分使えますね!

ccacheでデバッグオプションは使えないとする過去記事もヒットしましたが、少なくともubuntu 14.04上では問題なくデバッグできました。

これでなんか面白い機能を付けられないか、じわじわやっていきたい…

*1:厳密に言うと1つのレイヤの不透明部分の色を白に変更するという方法で可能だけど、1レイヤに共存はない