2

http://bytes.com/topic/c-sharp/answers/572657-net-clipboard-metafilesから取得したC#コードがあり、次の2つの設定でセル範囲をコピーします。

  • 画面に表示されているように、
  • 印刷時に示されているように

結果のメタファイルの解像度(として文書化されていますGets the resolution, in pixels-per-inch, of this Image object)を見ると、コピー方法に応じて異なる値が得られます。

  • [印刷時に表示]オプションを使用すると、解像度は600になります。これは、Excelで使用しているDPI設定に対応していると思います。

  • 画面に表示されているように設定すると、Metafile.VerticalResolution = 72.08107とのようなものが吐き出されますMetafile.HorizontalResolution = 71.95952。他のマシンでは、この値が大きく異なることを確認しました(111、130などの値)。

ズームレベルはこれに影響を与えないようです。私が観察したところによると、値は1台のマシンで一貫していますが、マシンごとに異なる場合があります。

画面モードで表示されるようにメタファイルの解像度を計算するときにExcelが従うロジックを誰かが説明できますか?

Windowsの解像度を変更し、メタファイルの解像度を測定した後、これが私が生成したテーブルです(正しくフォーマットされているように見えることを願っています):

Width   Height  HorizontalResolution    VerticalResolution
1680    1050        71.95952                72.08107
1600    1024        72.05672                72.04874
1600    900         72.05672                71.88678
1360    768         71.96666                71.98228
1280    1024        71.9292                 72.04874
1280    960         71.9292                 71.9292
1280    800         71.9292                 72.05672
1280    768         71.9292                 71.98228
1280    720         71.9292                 71.99999
1152    864         72.07093                71.95278
1088    612         71.96666                71.96666
1024    768         72.04874                71.98228
960     600         71.9292                 71.88678
800     600         72.05672                71.88678

仮想マシン(同じ物理マシン)で同様の手順を実行した後、これらは結果です。物理マシン自体よりも少し揮発性があります。このデータは役に立たないかもしれませんが、とにかく提供したいと思いました。

Width   Height  HorizontalResolution    VerticalResolution
1680    1050    133.35                  111.125
1280    800     101.6                   84.66666
1024    768     81.27999                81.27999
800     600     63.5                    63.5
4

1 に答える 1

4

私の仮説

これは、LCD モニターで非ネイティブ解像度を実行することに関係していると思います。「昔」では、CRT 自体にはネイティブ解像度がありませんでした。そのため、コンピューターは、特定のモニター サイズまたはアスペクト比に適した解像度を認識していませんでした。新しいデジタル ディスプレイ (LCD) では、適切に取り付けられていれば、コンピューターはディスプレイの優先解像度と縦横比を認識するようになりました。Windows 7 マシンでは、LCD のネイティブ解像度の横に「推奨」と表示され、残りの「不一致」はラベル付けされていませんが選択可能であり、残りの 2 つの等しい縦横比の解像度が黒で表示されます (その結果、見たくない押しつぶされたまたは引き伸ばされた外観になります)。他の人のコンピュータで!)。

Windows のデフォルトの DPI である 96 と 120 は、CRT の時代に確立されました。私の Windows 7 マシンは DPI を表示しなくなり、「小」、「中」、「大」とだけ表示されます。

いずれにせよ、1920x1080 や 1920x1200 などの LCD モニターを購入し、ディスプレイの解像度をそれより小さいものに設定すると、変換係数が発生します。水平方向と垂直方向の解像度が 72 に近く一致しない場合、非ネイティブのディスプレイ解像度は、水平方向と垂直方向のスケーリング係数がまったく同じではない可能性があり、結果としてこの小さな不一致が生じます。

私の仮説を検証する方法

各テスト マシンで、オペレーティング システムで構成された解像度とディスプレイのネイティブ解像度を記録します。これら 2 つの比率が、メタファイルの「画面上」と 96 または 120 dpi の比率に近いかどうかを確認します。このテストは物理マシンで実施して、リモート デスクトップまたは仮想マシン ドライバーでさらにスケーリングする可能性を除外することをお勧めします。

解決策がすぐにわからない場合は、さらに一歩進んで、DPI または「小」、「中」、「大」の操作パネルとコントロール パネルの設定を記録します。Windows XP は、Windows Vista/Windows 7 とは動作が異なる場合があります。

同じ物理マシンでテストを数回再実行して、テスト間で構成されたディスプレイ解像度を調整し、変更を観察することもできます。私の仮説が正しければ、同じ物理マシン/ディスプレイの組み合わせで構成されたディスプレイ解像度ごとに異なるメタファイル解像度が表示され、この結果は予測可能で再現可能であるはずです (最初の解像度に戻ると、同じメタファイル解像度に戻るはずです)。

編集#1

物理 DPI と論理 DPI について説明している優れた記事を見つけました。これを読んでください: 96 DPI は Windows のどこから来たのですか?

そこで、次にお勧めするテストは、ディスプレイの変更です。テスト用に別のブランド/サイズ/解像度の LCD モニターを利用できますか? さまざまな解像度が同じディスプレイに対して非常に類似した DPI を生成する傾向があることを確立したため、上記の最初のテストほど多くの行は必要ありません。ディスプレイのネイティブ解像度と、比較のための「ベースライン」としての 1024x768 を含む、いくつかの一般的な解像度をテストしてください。

また、Windows 7 をいじっているときに、コントロール パネルの [カスタム テキスト サイズ (DPI) の設定] リンクを見つけました - >ディスプレイには、[Windows XP スタイルの DPI スケーリングを使用する] オプションが含まれていました。これが主な関心事ではないと思いますが、好奇心がその効果に興味を持っているので、言及したいと思いました.

編集#2 - 解決!

メタファイルに表示されている解像度は、モニターの物理 DPI です。自分でテストできるように、ここに C# コードをいくつか投稿します。

[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr hWnd);

[DllImport("user32.dll")]
static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);

[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

public enum DeviceCap
{
    /// <summary>
    /// Device driver version
    /// </summary>
    DRIVERVERSION = 0,
    /// <summary>
    /// Device classification
    /// </summary>
    TECHNOLOGY = 2,
    /// <summary>
    /// Horizontal size in millimeters
    /// </summary>
    HORZSIZE = 4,
    /// <summary>
    /// Vertical size in millimeters
    /// </summary>
    VERTSIZE = 6,
    /// <summary>
    /// Horizontal width in pixels
    /// </summary>
    HORZRES = 8,
    /// <summary>
    /// Vertical height in pixels
    /// </summary>
    VERTRES = 10,
    /// <summary>
    /// Number of bits per pixel
    /// </summary>
    BITSPIXEL = 12,
    /// <summary>
    /// Number of planes
    /// </summary>
    PLANES = 14,
    /// <summary>
    /// Number of brushes the device has
    /// </summary>
    NUMBRUSHES = 16,
    /// <summary>
    /// Number of pens the device has
    /// </summary>
    NUMPENS = 18,
    /// <summary>
    /// Number of markers the device has
    /// </summary>
    NUMMARKERS = 20,
    /// <summary>
    /// Number of fonts the device has
    /// </summary>
    NUMFONTS = 22,
    /// <summary>
    /// Number of colors the device supports
    /// </summary>
    NUMCOLORS = 24,
    /// <summary>
    /// Size required for device descriptor
    /// </summary>
    PDEVICESIZE = 26,
    /// <summary>
    /// Curve capabilities
    /// </summary>
    CURVECAPS = 28,
    /// <summary>
    /// Line capabilities
    /// </summary>
    LINECAPS = 30,
    /// <summary>
    /// Polygonal capabilities
    /// </summary>
    POLYGONALCAPS = 32,
    /// <summary>
    /// Text capabilities
    /// </summary>
    TEXTCAPS = 34,
    /// <summary>
    /// Clipping capabilities
    /// </summary>
    CLIPCAPS = 36,
    /// <summary>
    /// Bitblt capabilities
    /// </summary>
    RASTERCAPS = 38,
    /// <summary>
    /// Length of the X leg
    /// </summary>
    ASPECTX = 40,
    /// <summary>
    /// Length of the Y leg
    /// </summary>
    ASPECTY = 42,
    /// <summary>
    /// Length of the hypotenuse
    /// </summary>
    ASPECTXY = 44,
    /// <summary>
    /// Shading and Blending caps
    /// </summary>
    SHADEBLENDCAPS = 45,

    /// <summary>
    /// Logical pixels inch in X
    /// </summary>
    LOGPIXELSX = 88,
    /// <summary>
    /// Logical pixels inch in Y
    /// </summary>
    LOGPIXELSY = 90,

    /// <summary>
    /// Number of entries in physical palette
    /// </summary>
    SIZEPALETTE = 104,
    /// <summary>
    /// Number of reserved entries in palette
    /// </summary>
    NUMRESERVED = 106,
    /// <summary>
    /// Actual color resolution
    /// </summary>
    COLORRES = 108,

    // Printing related DeviceCaps. These replace the appropriate Escapes
    /// <summary>
    /// Physical Width in device units
    /// </summary>
    PHYSICALWIDTH = 110,
    /// <summary>
    /// Physical Height in device units
    /// </summary>
    PHYSICALHEIGHT = 111,
    /// <summary>
    /// Physical Printable Area x margin
    /// </summary>
    PHYSICALOFFSETX = 112,
    /// <summary>
    /// Physical Printable Area y margin
    /// </summary>
    PHYSICALOFFSETY = 113,
    /// <summary>
    /// Scaling factor x
    /// </summary>
    SCALINGFACTORX = 114,
    /// <summary>
    /// Scaling factor y
    /// </summary>
    SCALINGFACTORY = 115,

    /// <summary>
    /// Current vertical refresh rate of the display device (for displays only) in Hz
    /// </summary>
    VREFRESH = 116,
    /// <summary>
    /// Horizontal width of entire desktop in pixels
    /// </summary>
    DESKTOPVERTRES = 117,
    /// <summary>
    /// Vertical height of entire desktop in pixels
    /// </summary>
    DESKTOPHORZRES = 118,
    /// <summary>
    /// Preferred blt alignment
    /// </summary>
    BLTALIGNMENT = 119
}

private void GetScreenInfo()
{
    IntPtr sdc = IntPtr.Zero;
    try
    {
        //Get the Screen Device Context
        sdc = GetDC(IntPtr.Zero);

        // Get the Screen Devive Context Capabilities Information
        Console.WriteLine(string.Format("Size: {0} mm X {1} mm", GetDeviceCaps(sdc, (int)DeviceCap.HORZSIZE), GetDeviceCaps(sdc, (int)DeviceCap.VERTSIZE)));
        Console.WriteLine(string.Format("Desktop Resolution: {0}x{1}", GetDeviceCaps(sdc, (int)DeviceCap.DESKTOPHORZRES), GetDeviceCaps(sdc, (int)DeviceCap.DESKTOPVERTRES)));
        Console.WriteLine(string.Format("Logical DPI: {0}x{1}", GetDeviceCaps(sdc, (int)DeviceCap.LOGPIXELSX), GetDeviceCaps(sdc, (int)DeviceCap.LOGPIXELSY)));

        //Remember: Convert Millimeters to Inches 25.4mm = 1 inch
        double PhsyicalDPI_X = GetDeviceCaps(sdc, (int)DeviceCap.DESKTOPHORZRES) * 25.4 / GetDeviceCaps(sdc, (int)DeviceCap.HORZSIZE);
        double PhsyicalDPI_Y = GetDeviceCaps(sdc, (int)DeviceCap.DESKTOPVERTRES) * 25.4 / GetDeviceCaps(sdc, (int)DeviceCap.VERTSIZE);
        Console.WriteLine(string.Format("Physical DPI: {0}x{1}", PhsyicalDPI_X, PhsyicalDPI_Y));

    }
    finally
    {
        ReleaseDC(IntPtr.Zero, sdc);
    }
}

私のディスプレイ上のこのコードは、次を出力します。

  • サイズ:677mm×381mm
  • デスクトップの解像度: 1920x1080
  • 論理 DPI: 96x96
  • 物理 DPI: 72.0354505169867x72

論理 DPI と物理 DPI の両方に注目してください。その物理 DPI は見覚えがありますか? 1pt=1px を反映する 72dpi に関する記事を読んだ後、すべてが理にかなっています。このコードをさまざまなテスト マシンで試してみて、どうなるか教えてください。(参考までに、私はこのコードを C# winforms アプリで実行しました。コンソール アプリは画面デバイス コンテキストを取得できるはずですが、そうでない可能性があります...)

于 2011-12-05T06:04:23.140 に答える