@IT会議室は、ITエンジニアに特化した質問・回答コミュニティ「QA@IT」に生まれ変わりました。ぜひご利用ください。
- PR -

透過GIFのリサイズ

1
投稿者投稿内容
ssk
会議室デビュー日: 2006/02/14
投稿数: 10
投稿日時: 2006-02-15 21:49
お世話になります。

ファイルから読み込んだGIFをリサイズして保存するアプリを制作したいのですが、下記方法ですと透過色がうまく処理されません。一旦bitmapとして読み込んでるせいだと思うのですが、GIFのまま扱う方法がわからずにいます。良い方法がありましたらご教授おねがいします。

Bitmap image1 = new Bitmap("./test.gif");

int w = src.Width * (倍率);
int h = src.Height * (倍率);

Bitmap image2 = new Bitmap(w, h);
Graphics g = Graphics.FromImage(image2);

g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

g.DrawImage(image1, 0, 0, w, h);
image2.Save("./out.gif", ImageFormat.Gif);
ssk
会議室デビュー日: 2006/02/14
投稿数: 10
投稿日時: 2006-02-15 21:51
すみません、コードに誤りありました。修正します。
これでもうまくいきません。宜しくお願いします。


Bitmap image1 = new Bitmap("./test.gif");

int w = image1.Width * (倍率);
int h = image1.Height * (倍率);

Bitmap image2 = new Bitmap(w, h);
Graphics g = Graphics.FromImage(image2);

g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

g.DrawImage(image1, 0, 0, w, h);
image2.Save("./out.gif", ImageFormat.Gif);
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-02-15 22:44
Bitmap(int, int) のコンストラクタを使用した場合、カラーデータ形式は PixelFormat.Format24bppRgb が使われます。
当然透明色は使えません。
明示的に PixelFormat.Format32bppArgb を指定して作成してください。
ssk
会議室デビュー日: 2006/02/14
投稿数: 10
投稿日時: 2006-02-16 13:08
Hongliang様前回に引き続きご回答ありがとうございます。

PixelFormat.Format32bppArgbを指定しようと思ったのですが、BitmapコンストラクタではBitmap(Int32,Int32,PixelFormat)かBitmap(Int32,Int32,Int32,PixelFormat,IntPtr)どちらかしかないようで、GIFを読み込む時点でPixelFormatをうまく指定することができません。
読み込み方法についてさらにお知恵を貸して下さい。
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-02-16 14:10
いやいやいや。
gifファイルから読み込んだBitmapには問題なく透過色がついています。
透過色がサポートできていないのは、その読み込んだBitmapを書き込む新しく倍サイズで作ったBitmapの方です。

[ メッセージ編集済み 編集者: Hongliang 編集日時 2006-02-16 14:12 ]
ssk
会議室デビュー日: 2006/02/14
投稿数: 10
投稿日時: 2006-02-16 23:01
Bitmapに読み込んだ段階で透過色の情報が欠落するものと思ってました。
さっそく、書き込み先のBitmapで

Bitmap image2 = new Bitmap(w, h, PixelFormat.Format32bppArgb);

として MakeTransparent()メソッドで元画像と同じ透過色にしたいのですが、
元のBitmapから透過色を取得する方法がわかりません。Bitmapクラスには
それらしきメソッドが見当たらないように思いますが、どのようにすればよいのでしょうか。
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-02-17 07:35
……テストと知識の双方が不十分なままでした。すいません。

一通りテストして、以下のことが分かりました。
  • 透過GIFを読み込むのは問題ない。読み込んだ透過GIFを表示させた場合透過される。この画像の PixelFormat は 8bbpIndexed である。
  • この画像をそのまま GIF を指定して Bitmap.Save した場合、全く同じファイルになる。
  • PixelFormat.Format24bppRgb の新しく作成した Bitmap に対して DrawImage でこの透過GIFを描画すると、透明色は失われ、黒(Color [A=255, R=0, G=0, B=0] )で描かれる。
  • PixelFormat.Format32bppArgb の新しく作成した Bitmap に対して DrawImage でこの透過GIFを描画すると、透明部分は Color [A=0, R=0, G=0, B=0] として描画される。
  • 上記の 32bppArgb に描画した画像をGIF形式でSaveした場合、GIFは24ビットでしか色を扱わないため当然の事ながらアルファ成分が失われ、黒として扱われてしまう。結果、透明色は失われる。
  • PixelFormat.Format8bppIndexed に対しては Graphics オブジェクトを作成できない。
  • PixelFormat.Format8bppIndexed に対して BitmapData を利用して直接色を置いていった場合、透過色にするには MakeTransparent を実行するのであるが、MakeTranskparent は内部で「新しく作成した Format32bppArgb の Bitmap に DrawImage し、その結果を返す」動作を行っているらしく、PixelFormat が Format32bppArgb に変更されている。よってこの画像を保存すると前述のように透過色が失われ、ただの黒になる。
  • なお一応 MakeTransparent などして Argb になった画像を GIF に保存した場合、透過色は有効で、基本的にパレットの16番目が透過色に指定されている。しかしこの色が使われていることはなさそうで、開きなおしても黒は黒である。

以上のことから、どうやら PixelFormat.Format32bppArgb を経由する限り(そして恐らく必ず経由しなければならない)透過色を再現するのは無理っぽい、です。

.NET(というかGDI+)に頼らない 外部のGIFコンポーネントを使うか(あるかどうかも分かりませんが。GIFは特許問題もありましたし)、自力でヘッダ/LZW圧縮を実装してどうにかするか。手軽な解決は思いつきませんね……。
ssk
会議室デビュー日: 2006/02/14
投稿数: 10
投稿日時: 2006-02-17 10:35
Hongliang様。詳細に教えていただき恐れ入ります。

たしかにそのまま保存するだけだと透過色が保持されることを確認しました。
が、加工後のBitmapをGIFとしてSaveする時点で、MakeTransparentの指定色が正しくGIFフォーマットの Transparent Color Index に反映されないようですね。真黒になります。

私の技術レベル、アプリの規模からいって、自力の実装はできそうもありませんので、透過GIFは処理対象外と割り切ります。まずは透過かどうかの判定方法について調査することにします。簡単な判別方法がなければ、直接GIFのTransparent Color Flagを読むしかないかとも思います。

大変勉強になりました。ありがとうございました。



1

アイティメディアの提供サービス

ホワイトペーパー(TechTargetジャパン/閲覧には会員登録が必要です)

スキルアップ/キャリアアップ(JOB@IT)