2011年8月23日火曜日

wpf : 論理ピクセル座標ではなくデバイス座標を使う

wpfは色々なデバイスでできるだけレイアウトが崩れないように論理ピクセル座標が標準になっています。 デバイス座標を使うには論理ピクセル座標 ⇔ デバイス座標の変換が必要になります。

dpiを使って変換するコードは検索するといくつか見つかります。 基準をdpi=96と決めうちしているものが多いようです。 それがいつまでも通用するという保障はありません。 変換はwpfに任せたほうがよいでしょう。 (wpf内部でも固定値を使ってそうですが、それでも自前でコードをチビチビ書くよりマシかと。)

試した環境は、

  • Windows7 Home Premium 64bit
  • Visual C# 2010 Express (x86プラットフォーム)

変換のコードはこんな感じです。

2011年8月21日日曜日

Visual C#でAny CPUはダメなんだそうで

2014/07/03 追記) Visual Studio 2012 Expressだと「プロジェクトのプロパティ - ビルド」でプラットフォームターゲットを Any CPU にすると、すぐ下の「32ビットの優先」を選ぶことができるようになっています。それをふまえて、昔の情報として読んでください。


Visual C# 2010 Expressを使い始めてから1~2ヶ月経ちました。 で、使い始めたころから気になっていたけど放置していたこと、「x86」について調べてみました。 ここでいうx86っていうのはプラットフォームのことです。 Visual C# 2010 Expressでは次のプラットフォームを対象にした実行ファイルを作成できます。

  • x86
  • Any CPU
  • Itanium
  • x64

64bit版のOSを使っていたとしても、Visual C#のデフォルトはx86です。 作ったx86版のアプリケーションを実行しタスクマネージャでプロセスを見ると*32が付いているので確認できます。 x86以外のプラットフォームを選択するには構成マネージャを開いてプラットフォームの新規作成をしなければなりません。 ちょいと面倒です。

wpf : Imageをピクセルスナップさせるプロパティはあった

前の投稿、「wpf : WriteableBitmapをピクセルスナップさせて等倍表示 」にあたる機能は標準のプロパティにありました。 UseLayoutRoundingプロパティです。

<Image Name="mainImage" UseLayoutRounding="True" Stretch="None"/>

と書けば自前コードでのピクセルスナップは必要ありませんでした。 見逃してた。 車輪の再発明でお恥ずかしい限りです。

ただ、完全に無駄足だったわけではないかもしれません。 こちらのブログに「RenderTransformとLayoutTransformの違いを見るに,パフォーマンス的には恐らくSnapToDevicePixelsが有利,ということになるんでしょうか・・・?」との記述があります。

「パフォーマンス的には」ってところを調べるのは私には荷が重いですね。 ホントにそうか確認するのは必要に迫られたとき、つまりはパフォーマンス的にギリギリのソフトを作ったときにだけなんだろうけど、そんなソフト作ることはなさそうです。

そんなこんなで、部分的にでも前の投稿のコードが要る人が出てくる可能性はあるので、前の投稿は残しておきますか。

2011年8月17日水曜日

wpf : WriteableBitmapをピクセルスナップさせて等倍表示

後日、追加情報を書きました。

-----------------------------------------------------

自分の環境でちょこっと試しただけなので汎用性については全く調べてないんですが、抱えてても仕方がないのでとりあえず投稿します。

wpfは座標が論理ピクセル単位です。 画像やシェイプをキリのいい座標に置いたつもりでも、実行環境のdpiしだいではズレて配置 → アンチエイリアスされにじんだ表示になってしまいます。 普通のアプリケーションならそれでも良いんでしょうけど、画像処理のソフトなど、デバイスピクセルにスナップさせないと使い物にならないものもあります。 そんなソフトを作るときのために、画像(System.Windows.Controls.Image)をピクセルスナップさせて表示する方法を探してみました。

手順はこんな感じです。

  1. Imageコントロールの左上のレンダリング座標をデバイスピクセルにスナップさせる。
  2. Imageコントロールのサイズをデバイスピクセルにあわせて調整する。

SnapsToDevicePixelsが効かないようなのでこういう手順になります。