私は今、メタファイルについて知っていた以上のことを学びました。
1.Metafile
クラスのコンストラクターのオーバーロードの一部は正常に機能せず、切り捨てられたDPI値で動作します。
次のことを考慮してください。
protected Graphics GetNextPage(SizeF pageSize)
{
IntPtr deviceContextHandle;
Graphics offScreenBufferGraphics;
Graphics metafileGraphics;
MetafileHeader metafileHeader;
this.currentStream = new MemoryStream();
using (offScreenBufferGraphics = Graphics.FromHwnd(IntPtr.Zero))
{
deviceContextHandle = offScreenBufferGraphics.GetHdc();
this.currentMetafile = new Metafile(
this.currentStream,
deviceContextHandle,
new RectangleF(0, 0, pageSize.Width, pageSize.Height),
MetafileFrameUnit.Inch,
EmfType.EmfOnly);
metafileGraphics = Graphics.FromImage(this.currentMetafile);
offScreenBufferGraphics.ReleaseHdc();
}
return metafileGraphics;
}
{8.5、11}のを渡した場合、{21590、27940}のを取得することをSizeF
期待できます。結局のところ、インチからミリメートルへの変換は難しくありません。しかし、あなたはおそらくそうしないでしょう。解像度にもよりますが、GDI +は、インチパラメータを変換するときに切り捨てられたDPI値を使用するようです。それを正しくするために、私は100分の1ミリメートルでそれを自分で行う必要があります。これは、GDI +がメタファイルヘッダーにネイティブに格納される方法であるため、通過するだけです。Metafile
rclFrame
this.currentMetafile = new Metafile(
this.currentStream,
deviceContextHandle,
new RectangleF(0, 0, pageSize.Width * 2540, pageSize.Height * 2540),
MetafileFrameUnit.GdiCompatible,
EmfType.EmfOnly);
丸め誤差#1が解決されました-rclFrame
メタファイルのが正しくなりました。
Graphics
2.に記録するインスタンスのDPIMetafile
は常に間違っています。
メタファイルmetafileGraphics
を呼び出して設定した変数を参照してください。Graphics.FromImage()
そうですね、そのGraphics
インスタンスのDPIは常に96dpiになるようです。(推測する必要がある場合は、物理的なDPIではなく、常に論理的なDPIに設定されます。)
Graphics
96 dpiで動作しているインスタンスを描画しMetafile
、ヘッダーに87.9231dpiが「記録」されているインスタンスに記録しているときに生じる陽気さを想像してみてください。(他の値から計算されるため、「記録された」と言います。)メタファイルの「ピクセル」(メタファイルに格納されているGDIコマンドはピクセルで指定されていることを忘れないでください)は大きいので、何かを描画するための呼び出しを呪い、つぶやきます1インチの長さは、1インチを超える長さになります。
Graphics
解決策は、インスタンスを縮小することです。
metafileGraphics = Graphics.FromImage(this.currentMetafile);
metafileHeader = this.currentMetafile.GetMetafileHeader();
metafileGraphics.ScaleTransform(
metafileHeader.DpiX / metafileGraphics.DpiX,
metafileHeader.DpiY / metafileGraphics.DpiY);
それはやっかいではありませんか?しかし、それはうまくいくようです。
「丸め」エラー#2は解決しました。88dpiで「1インチ」で何かを描くと言うと、そのピクセルは$%$^の方がよいでしょう。ピクセル#88として記録されます。
3.szlMillimeters
大きく変化する可能性があります。リモートデスクトップは非常に楽しいものです。
そのため、(Markの回答によると)WindowsがモニターのEDIDを照会し、実際にモニターの物理的な大きさを認識していることを発見しました。GDI +HORZSIZE
は、プロパティを入力するときにこれ(など)を有効に使用しszlMillimeters
ます。
ここで、家に帰ってこのリモートデスクトップのコードをデバッグするとします。自宅のコンピューターに16:9のワイドスクリーンモニターがあるとします。
明らかに、WindowsはリモートディスプレイのEDIDを照会できません。そのため、従来のデフォルトである320 x 240 mmを使用します。これは、アスペクト比が4:3であることを除けば問題ありません。現在、まったく同じコードが、ディスプレイ上にメタファイルを生成しています。正方形の物理ピクセル:水平DPIと垂直DPIは異なり、最後にそれが発生したのを思い出せません。
今のところ、これに対する私の回避策は、「まあ、リモートデスクトップで実行しないでください」です。
rclFrame
4.使用していたEMF-to-PDFツールで、ヘッダーを見るときに丸め誤差が発生しました。
これが、この質問を引き起こした私の問題の主な原因でした。私のメタファイルはずっと「正しい」ものであり(最初の2つの問題を修正した後は正しい)、「高解像度」のメタファイルを作成するためのこの検索はすべて赤ニシンでした。低解像度のディスプレイデバイスでメタファイルを記録すると、ある程度の忠実度が失われるのは事実です。これは、メタファイルで指定されているGDIコマンドがピクセル単位で指定されているためです。ベクトル形式であり、スケールアップまたはスケールダウンできるかどうかは関係ありません。実際の記録中に、 GDI +が操作をスナップする「ピクセル」を決定すると、一部の情報が失われます。
ベンダーに連絡したところ、修正されたバージョンが提供されました。
丸め誤差#3が解決されました。
5. Windowsエクスプローラーの[概要]ペインは、計算されたDPIを表示するときに値を切り捨てます。
この切り捨てられた値が、EMF-to-PDFツールが内部で使用していたのと同じ誤った値を表しているのは偶然です。これを除けば、この癖は議論に意味のあるものを何も提供しません。
結論
私の質問はデバイスコンテキストでのDPIの使用に関するものだったので、Mark'sは良い答えです。