私はこれについて広範囲に検索し、部分的な答えを見つけたと言うことから始めましょう。
スケーリングされていないビットマップ イメージを WPF アプリケーションに表示する必要があります。ビットマップの 1 ピクセルをディスプレイの 1 ピクセルにマップしたい。ビットマップの複数のバージョンを出荷することで、複数の解像度をサポートするつもりです。しかし、特定のビットマップが選択されると、設計どおりに正確にレンダリングされることを知りたいです。
WPF で発生する自動スケーリングを克服するための私の戦略は、(OS DPI 設定によって) 自動的に適用されているものを確認し、逆の LayoutTransform をウィンドウの最も外側のコンテナーに適用することです。
これにより、ユーザーの DPI 設定に関係なく、アプリはウィンドウのコンテンツを WPF ピクセルとハードウェア ピクセルの 1:1 の比率でレンダリングします。ここまでは順調ですね。
そのコードは次のようになります。(これが 1.0 の引数で呼び出されると仮定します)。
private void SetScale(double factor)
{
// First note the current window transform factor.
// This is the factor being applied to the entire window due to OS DPI settings.
Matrix m = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;
double currentWindowTransformFactorX = m.M11;
double currentWindowTransformFactorY = m.M22;
// Now calculate the inverse.
double currentWindowTransformInverseX = (1 / m.M11);
double currentWindowTransformInverseY = (1 / m.M22);
// This factor will put us "back to 1.0" in terms of a device-independent-pixel to physical pixel mapping.
// On top of this, we can apply our caller-specified factor.
double transformFactorX = currentWindowTransformInverseX * factor;
double transformFactorY = currentWindowTransformInverseY * factor;
// Apply the transform to the registered target container
ScaleTransform dpiTransform = new ScaleTransform(transformFactorX, transformFactorY);
if (dpiTransform.CanFreeze)
dpiTransform.Freeze();
this.pnlOutermost.LayoutTransform = dpiTransform;
}
ここまでは、すべてがうまく機能しています。Windows DPI を何に設定しても、そのメイン コンテナーのコンテンツは常にまったく同じサイズであり、ビットマップは正確にレンダリングされます。
ここからは楽しい部分です。解像度固有のアートワークを提供し、UI 全体を適切にスケーリングすることで、さまざまな画面解像度をサポートしたいと考えています。
これには LayoutTransform が非常にうまく機能することがわかりました。したがって、上記のメソッドを 1.25 または 1.5 などで呼び出すと、UI 全体がスケーリングされ、すべてが完璧に見えます。新しいスケーリングされた寸法にぴったりのサイズ。
たとえば、XAML で 100x100 の画像があるとします。私のアートワークには、100x100、125x125、150x150 の 3 種類があります。画像を格納するコンテナーをスケーリングするときは、その画像のソースも適切なものに変更します。
興味深いことに、画像オブジェクトが係数でスケーリングされたときに積分結果が得られる位置にある場合、スケーリングされた画像はきれいに見えます。つまり、画像に次のプロパティがあるとします。
Canvas.Left = 12
Canvas.Top = 100
係数 1.25 を適用すると、結果は 15 と 125 になり、画像は見栄えがよくなります。しかし、画像が 1 ピクセル移動すると、次のようになります。
Canvas.Left = 13
Canvas.Top = 100
ここで係数 1.25 を適用すると、15.25 と 125 が得られ、結果はお粗末に見えます。
明らかに、これはある種の丸めの問題またはそのようなもののように見えます。だから私は試しました:
UseLayoutRounding="True"
SnapsToDevicePixels="True"
RenderOptions.EdgeMode="Aliased"
RenderOptions.BitmapScalingMode="NearestNeighbor"
ウィンドウ、スケーリングされているコンテナ、および画像オブジェクトでこれらを試しました。そして、何も機能しません。画像はまったくスケーリングされるべきではないため、 BitmapScalingMode はとにかく意味がありません。
これに光を当てることができる人には永遠に感謝します。