2

測定単位としてミリメートルのメタファイルを使用する WinForms アプリケーションで、一貫したスケーリングを得るのに問題があります。この問題を説明するために、小さなサンプル アプリケーションを作成しました。

これは、アプリケーションが Windows 7 デスクトップ マシンでどのように見えるかです。 ここに画像の説明を入力

これは、アプリケーションが Windows 8 ラップトップ マシンでどのように見えるかです。 ここに画像の説明を入力

ソースコード:

private void MainForm_Paint(object sender, PaintEventArgs e)
{
   var g = e.Graphics;
   var blueBrush = new SolidBrush(Color.Blue);
   var bluePen = new Pen(blueBrush);
   g.DrawRectangle(bluePen, 0, 0, 200, 200);
   g.DrawLine(bluePen, 100, 0, 100, 200);
   g.DrawLine(bluePen, 0, 100, 200, 100);
   g.DrawString(g.DpiX+" dpi", new Font("Arial", 10), blueBrush, 0, 205);

   Metafile metafile;
   var size = new Size(200, 200);
   using (var stream = new MemoryStream())
   {
      using (Graphics offScreenBufferGraphics = Graphics.FromHwndInternal(IntPtr.Zero))
      {
         IntPtr deviceContextHandle = offScreenBufferGraphics.GetHdc();
         metafile = new Metafile(stream, deviceContextHandle, new RectangleF(0, 0, size.Width, size.Height), MetafileFrameUnit.Millimeter, EmfType.EmfPlusOnly);
         offScreenBufferGraphics.ReleaseHdc();

         using (Graphics mg = Graphics.FromImage(metafile))
         {
            mg.PageUnit = GraphicsUnit.Millimeter;

            var redPen = new Pen(new SolidBrush(Color.Red));
            const float scaleFactor = 0.75f;
            mg.ScaleTransform(scaleFactor, scaleFactor);
            mg.DrawLine(redPen, 0, 0, 200, 200);
            mg.DrawLine(redPen, 0, 200, 200, 0);
         }
      }
   }

   g.DrawImage(metafile, 0, 0, 200, 200);
}

どちらのマシンも 96dpi に設定されていますが、Win8 マシンはメタファイル (赤い十字) を小さくレンダリングします。

倍率 0.75 は、標準の 72 dpi と現在の 96 dpi の差、72/96 = 0.75 から計算されますが、これは正しいですか? 編集:これが機能しない理由については、以下の回答を参照してください。

しかし、ほとんどの場合、Win8 マシンでスケーリングが異なるのはなぜですか? また、どの設定を取得して補正できますか? Win8 マシンでは、赤い十字を青い四角形に揃えるために約 1.25 の倍率が必要なようです。

ありがとう!

4

1 に答える 1

2

このコードプロジェクトの記事を読んだ後、自分で答えを見つけました。マシンの画面サイズ (デスクトップでは 1920x1200、ラップトップでは 1600x900) がメタファイルの解像度に影響することがわかりました。スケール ファクター 0.75 の計算に使用された 72dpi の仮定は、私のデスクトップ マシンではある程度正確でしたが、Win8 ラップトップでは正しくありませんでした。

メタファイルの解像度は、メタファイル ヘッダーから取得して、正しい倍率を計算するために使用できます。

var metafileHeader = metafile.GetMetafileHeader();
float sx = metafileHeader.DpiX/g.DpiX;
float sy = metafileHeader.DpiY/g.DpiY;
mg.ScaleTransform(sx, sy);

完全なコードはここにあります。

次に、両方のマシンで正しいスケーリングを取得します。

ここに画像の説明を入力

于 2014-11-10T10:37:18.540 に答える