[C#,VB.NET]Graphics.DrawImage(image,0,0)の落とし穴
サブタイトル:単に女の子の画像を張りたかっ(ry
12:00 すみません若干認識がずれていたようですので赤で修正しました
Graphics.DrawImage(image,0,0)は等倍表示を意味します。しかしこの等倍表示には2通りの意味があります。
●確認プログラム
確認のために以下のプログラムをダウンロードして実行してください。
これはDrawImage(image,0,0)で実装された単なる画像ビュアーです。
C#とVB.NETを用意してます。
http://myugaru.wankuma.com/DrawImageCheck_src.zip
実行形式も用意しました。実行には.Net Framework3.5が必要です。
http://myugaru.wankuma.com/DrawImageCheck_bin.zip
●確認手順
プログラムを実行すると単なるフォームが表示されます。↓の画像をドラッグ&ドロップしてみてください。
(c)elouai.com - Candybar 4 Doll Maker http://elouai.com/candybar4/dollmakergirl.php
ブラウザで表示されているものより拡大されましたか?手持ちの画像でもこの確認プログラムとブラウザにドラッグ&ドロップして確認してみてください。両者で見た目のサイズが違っているものはありませんか?
●原因
DrawImage(イメージ, 0, 0)は「物理サイズで等倍表示する」事を意味しています。
ですから「論理サイズでの等倍表示」を期待する人にとっては等倍と見えません。
すなわち
確認プログラムは「物理サイズ等倍表示」
ブラウザなどは「論理サイズ等倍表示」だという違いがこの現象を起こしています。
●解説
1.解像度
イメージには解像度と呼ばれるプロパティが存在しています。
水平方向の解像度=イメージ.HorizontalResolution
垂直方向の解像度=イメージ.VerticalResolution
ディスプレイにも解像度があります。例えば私の17インチディスプレイで1024×768表示時には解像度96dpiになっています。解像度は1024×768などを800×600に変えても変わるものではなくディスプレイそのものの能力値として機能しているようです。
2.画像に解像度が設定されるタイミング
画像の解像度の決まるタイミングはブラウザのような画像解像度を無視するアプリによって画像ストリームとしてファイルに保存される瞬間です。
ほとんどの場合は使っているディスプレイの解像度がその画像に設定されます。
以下のリンクを右クリックから「対象をファイルに保存」でPCへ保存してください。
http://myugaru.wankuma.com/image/20080309_50.bmp
この場合は画像ではなく単にファイルとして保存されるので本来の画像に設定された解像度が維持されます。
保存した画像ファイルをExplorer上で右クリックしてプロパティを確認してみてください。
この画像が解像度50dpiで作成されているのだというのが確認できます。
次に先ほどの女の子の画像上を右クリックして「名前を付けて画像を保存」でPCへ保存してみてください。
お使いのディスプレイに合わせてその解像度が設定されるかと思います。
先ほど同様に保存した画像ファイルのプロパティを確認してみてください。
(ブラウザによっては50dpiのままのものもあるかもしれません。IEはディスプレイ解像度に変わりました)
※ディスプレイ解像度はコントロールパネルの画面などから確認ができます。
2.物理サイズでの等倍
物理サイズというのは画像のインチ数でのサイズの事を指します。
上の確認プログラムの動作はこの物理サイズを等倍とするプログラムになっています。
先ほどの女の子の画像の論理サイズ(ピクセルサイズ)は横150×縦290です。
物理サイズ横=150÷50=3インチ
物理サイズ縦=290÷50=5.8インチ
の画像だといえます。
それを96dpiのディスプレイに物理サイズで等倍表示するとどういう事が起こるかというと、
横ピクセル=3×96=288
縦ピクセル=5.8×96=556.8
つまりディスプレイ上で288×556ピクセルで表示される事を意味します。
これは論理サイズでは拡大表示となります。
物理サイズでの等倍のシンプルな確認方法はディスプレイ解像度を変えてみる事です。
試しにディスプレイを1024×768や800×600などに変えてみてください。
物理サイズでの等倍を行うプログラムではその見た目のサイズは変わりません。
ディスプレイの能力によって96dpiが決まるので1024×768を800×600にする行為はこの能力の変更には直結していません。したがってこの場合見た目のサイズも変わってしまうという結果になります。確認が不足しておりました。すみません。
3.論理サイズでの等倍
論理サイズというのは画像のピクセル数でのサイズの事を指します。
ブラウザの動作は論理サイズを等倍とするプログラムになっています。
DrawImageのサイズ指定バージョンは画像の解像度を無視しディスプレイ解像度で表示することを意味しています。
DrawImage(image,0,0,image.Width,image.Height)は論理サイズでの等倍に利用できます。(可能な人は先ほどのプログラムを修正して確認してください)
論理サイズでの等倍の場合はディスプレイ解像度で表示されるわけですから、当然ディスプレイの解像度を1024×768や800×600に変えるとその物理サイズであるインチ数でのサイズは変わる事になります。これは前述の通り論理サイズ等倍だけの話ではありませんでした。すみません。
先の画像のように意図的に50dpiを設定している画像だったなら50dpiのディスプレイというのは見かけませんので、ほとんどの場合は製作者の意図したサイズで表示されていないという事を意味しています。この意味は多少あっていると思われます。
●対策
1.画像の解像度を変更する方法
残念ながら通常のWindows付属ペイントだとこれは出来ません。
画像解像度を簡単に変えることが出来るフリーのペイントツールがあります。
http://www.getpaint.net/
以下のように解像度のみ修正できます。
・[イメージ]→[キャンバスサイズ]の解像度の数値をかえる
2.とりあえず論理サイズの方が一般的?
一般に普及しているブラウザやペイントツールの動作を見てもディスプレイへの表示時はほとんどが画像の解像度を無視しているようです。
なので画像を単純にブラウジングするような場合にはDrawImage(image,0,0,image.Width,image.Height)とサイズ指定して論理サイズ等倍を意識したつくりにする方が良いように思います。
あまり需要は無いのかもですが、何かのプログラムでディスプレイ解像度に依存しない(つまり物理サイズが必要な)局面が出てきた場合にはこのエントリーの事を思い出して欲しいと思います。
物理サイズ等倍というのは見た目での等倍実現に寄与していないようです。現在のディスプレイの能力に見合ったサイズとしてそのサイズを表現するという意味合いで使われているように思います。不確かな記述をしてしまい申し訳ありませんでした。
最後に・・・ここまで書いてからふっと見ると・・・ほとんどここに書いてました。ヘルプも空気も嫁てません。。→http://msdn2.microsoft.com/ja-jp/library/558kfzex(VS.80).aspx
・・・開き直って私なりにまとめたのはこれで良しとしときます。