Out of Memory

ごめん、忘れてた。

目次

Blog 利用状況

ニュース

2008年7月1日
Microsoft MVP for Developer Tools - Visual C++ を再受賞しました。
2008年2月某日
MVPアワードがVisual C++に変更になりました。
2007年10月23日
blogタイトルを変更しました。
2007年7月1日
Microsoft MVP for Windows - SDKを受賞しました!
2007年6月20日
スキル「ニュース欄ハック」を覚えた!
2006年12月14日
記念すべき初エントリ
2006年12月3日
わんくま同盟に加盟しました。

カレンダー

中の人

aetos

顔写真

埼玉を馬鹿にする奴は俺が許さん。

基本的に知ったかぶり。興味を持った技術に手を出して、ちょっと齧りはするものの、それを応用して何か形にするまでは及ばずに飽きて放り出す人。

Microsoft MVP for Windows SDK July 2007 - February 2008, Microsoft MVP for Visual C++ February 2008 - June 2009
Microsoft MVP for Windows SDK
July 2007 - February 2008
Microsoft MVP for Visual C++
February 2008 - June 2009

アクセサリ

あわせて読みたい

e-Words

アフィリエイト

記事カテゴリ

書庫

日記カテゴリ

【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】

まず、解像度という言葉の説明から始めよう。

解像度とは、読んで字の如く「画『像』をどれだけ細かく分『解』するかという『度』合い」である。
一般に、「画面解像度は1024×768」と言ったりするが、これは正しくない。1024も768も、単位はピクセル、言い換えればドットだが、解像度の本来の単位はDPI(Dots Per Inch)、すなわち「1インチあたり何ドットか」、言い換えれば「1インチを何ドットで描画するか」というものだからだ。
1インチを1ドットで描画すると、1.5インチは表現できない。1インチを10ドットで描画すると、1.5インチは15ドットで表せるが、1.25インチは正確には描画できない。1インチが100ドットなら、1.25インチは125ドットで描けばいい。要するに、解像度が高いほど、画像を精密に描画することができる。
解像度とは、分解の度合い、精緻さの度合いであって、画像の大きさではない。これは重要だ。

ところが、デジカメで撮影したり、スキャナで取り込んだりした画像は、解像度が高いほど大きくなる。何故か? それは、ドットの大きさが固定だからだ。

当然だが、カメラやスキャナの解像度が変わっても、被写体や原稿の大きさは変わらない。繰り返すが、カメラやスキャナの解像度とは、被写体や原稿を、どれだけ細部まで緻密に取り込むかという度合いだ。
しかし、それをパソコン上で表示すると、解像度の高い画像は大きく表示されてしまう。

紙に絵を描いて、それをバラバラに切って、ジグソーパズルを作ることを想像してほしい。
紙のサイズは固定なのだから、ピース数を増やすには、1つのピースを小さくする必要がある。
これがパソコンでは、ピース(ドット)の大きさが固定なため、ピース数を増やすには、元々の紙を大きいものにするしかない。
そういう理屈である。

さて、本題。画面に10cm×10cmぴったりの正方形を描く方法だ。これを実現するには、「マッピングモード」というのを使う。

画面に正方形を描くのには、FillRectという関数を使うことにしよう。第2引数で、描画したい正方形の4隅の座標を指定する。
第2引数の説明には、「論理座標」という言葉が出てくる。これがキモだ。

GDI系の関数だと、度々「論理座標」と「物理座標」という言葉に遭遇する。これは一体何なんだ。
先程の解像度の説明と混同しないように注意してほしい。解像度の本来の意味では、解像度がいくつだろうが1インチは1インチで、解像度が高くなるとドットが小さくなるというほうが正しい理解だった。だから、1インチが物理座標のような気がする。
だが、今いるのはコンピュータの世界だ。コンピュータの世界では立場が逆になる。
ドットの大きさは変わらないから、これが一番の基準になる。1ドットを単位にするのが「物理座標」だ(またの名を「デバイス座標」とも言う。モニタとプリンタの1ドットのサイズは違うので、デバイスに依存する座標系という意味だ)。
そして、1センチとか1インチとか、一見して「物理座標」に思えるものが、コンピュータ内では「論理座標」になる。画面に対する描画指令はドット単位で行われ、論理単位での指定は、それを何ドットで描くべきかに変換してから描画しているからだ。言わば仮想的な単位なのだ。

FillRectの座標は論理座標で指定するから、10cm×10cmという指定もできる。それを画面上に何ドットで描画するのかを決めるのがマッピングモードだ。

マッピングモードの設定にはSetMapMode関数を使う。ここらでサンプルコードを出そう。


  case WM_PAINT:
  {
   hdc = BeginPaint(hWnd, &ps);
   SaveDC( hdc );
   SetMapMode( hdc, MM_LOMETRIC );
   RECT rect = { 100, -100, 1100, -1100 };
   FillRect( hdc, &rect, ( HBRUSH )GetStockObject( BLACK_BRUSH ) );
   RestoreDC( hdc, -1 );
   EndPaint(hWnd, &ps);
   break;
  }

ネイティブWin32アプリケーションのWndProcの抜粋だ。
SetMapModeで、マッピングモードをMM_LOMETRICにしている。これは、論理単位を0.1mmとするものだ。この座標系は、x座標は普通なのだが、y座標が変だ。数値が増えるほど、y座標が表す点は上に行く。だから、y座標は負の数にしている。(実のところ、変なのはこっちではなく、通常使うMM_TEXT座標系だ。数学でグラフを書く時は、右上へ行くほど大きくなったでしょ?)
論理単位が0.1mmなので、10cmは1000単位だ。だからこのプログラムは、画面左上隅から1cm, 1cmの位置から、10cm×10cmの正方形を描くはずだ。

ところが、これじゃうまく行かない。環境にもよるが、実際に画面上に表示された正方形を定規で測ってみたら、9cm×9cmしかなかった。どうしてだろう?

ここに、Windowsの変な癖がある。
今、俺の目の前にあるパソコンの画面の横幅は、定規で測ってみたところ、28.5cmだった。28.5cmは約11.22インチで、解像度(と呼ばれているモノ)は1024×768ドットなので、(本当の意味での)解像度は1024/11.22≒91DPIのはずだ。が、Windowsはこれを96DPIだと勝手に決め付ける
1インチ=96ドットだから、1024ドットは約10.67インチ。約27.1cmだ。
実際には28.5cmなのに、Windowsが27.1cmと勘違いすることで誤差が生じるため、プログラムは思い通りに動かない。

さて、どうしよう?

Windowsが勝手に解像度を96DPIだと決めつけるのがいけないので、ここは、実際の画面サイズから正しい解像度を求めたいところだ。が、プログラムから実際の画面サイズを取得する方法がわからない(ご存知の方は教えてください)。GetDeviceCapsにHORZSIZE、VERTSIZEを渡せば取得できそうに見えるが、これはデタラメな値しか返さないので使えない。
そこで今回は、実際に画面のサイズを測り、それに基づいてプログラミングした

先にも言ったように、俺のPCの画面の横幅は28.5cmだった。高さは21.5cmだ。これが今回の論理座標の手掛かりとなる。
SetMapModeで使えるマッピングモードはいくつかあるが、今回使うのはMM_ANISOTROPICだ。
こいつを使うと、解像度を好きな値にすることができる。解像度の設定に使うのはSetWindowExtExSetViewportExtExだ。

ここらでコードを紹介しよう。


 case WM_PAINT:
  {
   static const unsigned int logicalWidth = 285;
   static const unsigned int logicalHeight = 215;
   static const unsigned int physicalWidth = GetSystemMetrics( SM_CXSCREEN );
   static const unsigned int physicalHeight = GetSystemMetrics( SM_CYSCREEN );
   hdc = BeginPaint(hWnd, &ps);
   SaveDC( hdc );
   SetMapMode( hdc, MM_ANISOTROPIC );
   SetWindowExtEx( hdc, logicalWidth, logicalHeight, NULL );
   SetViewportExtEx( hdc, physicalWidth, physicalHeight, NULL );
   RECT rect = { 10, 10, 110, 110 };
   FillRect( hdc, &rect, ( HBRUSH )GetStockObject( BLACK_BRUSH ) );
   RestoreDC( hdc, -1 );
   EndPaint(hWnd, &ps);
   break;
  }

やはりWndProcの抜粋である。ポイントは先の2つの関数。
logicalWidthとlogicalHeightは、実際の画面の大きさを測ってmm単位にしたもの。physicalWidthとphysicalHeightは、画面の解像度(と呼ばれているもの)で、今回は1024と768だ。

ウィンドウとは何か、ビューポートとは何かということを説明するのは面倒くさいので、上のプログラムを極めて直感的に説明すると、「(1論理単位=1mmとして)横は285単位を1024ドット、縦は215単位を768ドットとみなして、ウィンドウ左上隅から10単位, 10単位の位置から100単位×100単位の正方形を描く」というものだ。このように、「1論理単位を何ドットで描画するのか」、すなわち解像度(ここでは Dots Per Inch ではなく Dots Per Millimeter だが)をカスタマイズできるのが、このマッピングモードの特徴である(ちなみに、これを応用すると、画像の拡大・縮小ができる)。

投稿日時 : 2007年4月25日 1:56

Feedback

# re: 【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】 2007/04/25 2:00 ちゃっぴ

全然関係ないけど、「疑いのある Web サイト」になっちゃってますよ~。

# re: 【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】 2007/04/25 2:04 シャノン

何故ー!?

# re: 【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】 2007/04/25 2:05 シャノン

あ、直った。

# re: 【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】 2007/04/25 11:33 とっちゃん

画像処理の最難関キタ━━━━━━(゚∀゚)━━━━━━ !!!!!

詳細もトム<トムって何!

いや、冗談抜きで難しい世界ですw
何度説明してもわかんねー奴にはわかんねーという...w
#うちはこれをクリアできないと仕事にならんのですけどねw

これがちゃんと理解できないと WYSING はできませんw

# re: 【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】 2007/04/25 14:23 シャノン

> 詳細もトム<トムって何!

ど、どのへんを詳細やりましょう?

# re: 【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】 2007/04/25 15:10 とっちゃん

>ど、どのへんを詳細やりましょう?

もう、最初から最後までどっぷりとww

あんまり知られてないですよ。このマッピングモードの問題は...w
ラスタ系出力デバイスを扱っていく上では必須のネタなんですが...w

ポイントで行くと
・マッピングモードの種類と違い(とくに座標軸の向きとかw)
・単位系と座標系の混同
・Windowport/Viewport のお話
・ワールド座標系のお話(まぁ、ここはパスでもOKw)
・単位変換とWYSING
・デバイスによる違い
というあたりかなぁw
#なんかすげー濃い気がする...きっと気のせいだwそうに違いないww

実践よりなネタを混ぜるとこれに
メタファイル(WMF/EMF)とマッピングモードの関係w
データ管理としてのマッピングモード
MM_TEXT を過信してはいけないw
というのが入ってきますけどwまぁそこはパスでもよいかとww
#すんません。9割仕事直結ネタです。もう数年講釈たれてませんがw

なんなら、Codezine に紹介しましょうか?
いい小遣い稼ぎにはなるとww
#Native系でも出してくれるところってそこくらいしかないのでw

# re: 【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】 2007/04/25 15:30 シャノン

う…わははははは。
いや、自分ではタイトルにもある通り、SetWindowExtEx と SetViewportExtEx の使い方の備忘録のつもりだったのですよ。
それに、昔mixiで書いた「解像度」という言葉の誤解を絡めてみただけの代物。
あまり突っ込まれると、↑の文章からも間違いがボロボロ出てきそうで怖いw

というか、
> もう数年講釈たれてませんがw
たれてくださいw

ところで、
> WYSING
WYSIWYGですよね(What's you see is what's you get だっけ)?

> いい小遣い稼ぎにはなるとww

Codezineって金もらえたのか…

# re: 【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】 2007/04/25 15:34 シャノン

とっちゃん、インストーラ屋さんかと思ってたら、本業は画像処理屋さん…?

# re: 【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】 2007/04/25 21:33 Jitta

某「プリンタに1ドットの線を引きたい」スレを思い出したよ(--;
JPEG だと、内部に DPI 情報を持たせることができるのですが、古いデジカメだと固定ですね。

> Windowsはこれを96DPIだと勝手に決め付ける。
デフォルトが、ですね。もちろん変更することもできますが、管理特権が必要。
[画面のプロパティ][設定][詳細設定][全般][DPI設定]
です。これを[カスタム設定]にして、メモリの "1" が "2.54cm" になるようにドラッグする、と。
Vista でも管理特権が必要で、再起動まで必要(--;
そんなわけで、これをプログラムから変えることはできないと思う。

# re: 【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】 2007/04/26 12:45 とっちゃん

>WYSIWYGですよね(What's you see is what's you get だっけ)?
あーそうだwww
どうも横文字は苦手で<おい!

じつは、MSDN/VSUG でマルチ進行(ポスト&進行w)で、まさにこのネタが...w
#VBから、API ってまぁあんたなにやりたいの?なネタだったけどw

本人的には解決したそうですがw
#評価になるかは不明...評価ポイントわかんねーしw

スレでは、説明するのも面倒だったので、Programming Windows 第5版の下巻を読めとw
#数少ないマッピングモードを説明した良質の文書があるんですよw

限りなく絶版状態なので、今も入手できるかは分らんのですがw
#Vista 対応の第6版でないかなぁ?


>Codezineって金もらえたのか…
編集部から依頼の形ならw
#ただし、相場的にはwそのへんはεπιστημηさんが詳しいw


>とっちゃん、インストーラ屋さんかと思ってたら、本業は画像処理屋さん…?
本業は、なんでも屋です。
コーディング方面では、おもに、DIBとして扱えるものを中心にそれにまつわる諸々w
画像処理は、表示周りだけです(必然、拡大縮小はやることになるけどw)。
それ以外の加工系はおいらじゃない人がやってますw

あとは、プリンタドライバドライバも作ってますよw<DOSの頃からww
DOSの頃よりはましだけど、各社の仕様(NDA)をシームレスに使えるようにとコード書いてますw
#メーカーごとの剥離が激しくて、破たん寸前ですが...orz


一応、受け持ちアプリもあるけど(1本丸ごと)、数年間ほとんど変わってませんw
#行きつくとこまで行っちゃったので、やることなくなってるwww
#コンセプト変えれば、あれですが、おまけソフトなんで、労力は割かない方向にww

インストーラは、副業ですよw本業だったらこんなに表に書けないものww
ま、こっちは好き勝手やれる分、社内でもとんがったコードになってますがw
#実コード出さずに、ノウハウだけ出すのって難しいですよw

>そんなわけで、これをプログラムから変えることはできないと思う。
DPIの変更は、アプリ内部でやるですよ。
Windows上の設定との差分は個体差なので(本当は、インストール時に、ユーザーが調整してくれればいいんですがww)
本気できちっと出す必要がある場合は、DPIの調整を複数持たせますw

うちのアプリではやってないですが、昔のフォトショップとかは設定できるようになってました。
#今はわからんです

一度やるとかいわれて、ああだこうだ説明してたら、やめようってwww
#それだけ面倒なんですけどねw

# re: 【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】 2007/04/26 15:15 シャノン

> そんなわけで、これをプログラムから変えることはできないと思う。

プログラムから変えられなくていいというか、ユーザにも変えられなくていいから、自動で適切な値になってください。

# re: 【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】 2007/04/26 15:16 シャノン

> スレでは、説明するのも面倒だったので、Programming Windows 第5版の下巻を読めとw
> #数少ないマッピングモードを説明した良質の文書があるんですよw

手放しちゃったよ。
買い戻そうか、第6版を待とうか…
#Advanced Windows の第5版もいつ出ますかね?

>> Codezineって金もらえたのか…
> 編集部から依頼の形ならw

無理だからやめてーw

# re: 【備忘録】画面にピッタリ10cm×10cmの正方形を描く方法【Win32】 2007/04/26 16:45 とっちゃん

>自動で適切な値になってください
マッキントッシュなら、やってくれますよw
マックじゃないですよwww<ちがうのかよ!

「ヤツ」は、ディスプレイコネクタが双方向だったのよねぇw(なんか、専用のコネクタだったw)
で、自分が出力できるサイズ(INCH)を返してくれたらしいです。
#もちろん、出力可能ピクセル数とかもw
で、本体がいい塩梅に調整して、つねにリアルに72dpi(POINT相当)で表示できるようになってるんですよ。

いまの、≠パソコンな「奴」はどうだか知りませんけどww

# re: Major な Measure 2008/01/08 16:05 囚人のジレンマな日々

re: Major な Measure

タイトル  
名前  
Url
コメント