GDIデバイスコンテキストのDPIの指定
-
20-09-2019 - |
質問
メタファイル(EMF)を生成するアプリケーションがあります。参照デバイス(別名画面)を使用してこれらのメタファイルをレンダリングするため、メタファイルのDPIは、コードが実行されているマシンに応じて変更されます。
私のコードがx 11インチで8.5のメタファイルを作成することを意図しているとしましょう。私の開発ワークステーションを参照として使用すると、私は
- {0、0、21590、27940}のrclframe(メタファイルの寸法、1000分の1 mm)
- {1440、900}のszldevice(参照デバイスの寸法、ピクセル)
- {416、260}のszlmillimeters(mm単位の参照デバイスの寸法)
さて、RCLFrameはEMFのサイズは
- 21590 /2540 = 8.5ワイド
- 27940 /2540 = 11 = 11
右に。この情報を使用して、数学が正しい場合は、モニターの物理的なDPIも決定できます。
- (1440 * 25.4) / 416 = 87.9231水平DPI
- (900 * 25.4) / 260 = 87.9231垂直DPI
問題
このメタファイルを再生するもの - EMFからPDFへの変換、WindowsエクスプローラーのEMFを右クリックするときの「要約」ページなどは、計算されたDPI値を切り捨て、87.9231の代わりに87を表示するように見えます( 88は大丈夫です)。
これにより、メタファイルが再生されたときにx 11 in(88 dpiを使用)で8.5ではなく、x 10.98 in(87 dpiを使用)x 10.98 in(87 dpiを使用)として物理的にサイズのページが表示されます。
- 参照デバイスのDPIを変更して、DPIの計算に使用されるメタファイルに保存されている情報が素敵な整数に登場するようにすることは可能ですか?
- 独自のデバイスコンテキストを作成してDPIを指定できますか?それとも、プリンターを使用してそれを行う必要がありますか?
洞察をありがとう。
解決
Windowsがモニターの物理サイズをどのように知っているかについて興味があります。どこかで構成を変更したに違いありませんか?おそらく、それをうまく分割するより便利な値に変更することができます。
名前で暗示されているように、「デバイスコンテキスト」はシステムデバイスに接続する必要があります。ただし、これはハードウェアドライバーである必要はありません。PDFライタープリントドライバーなどのデバイスエミュレータである可能性があります。任意のDPIを設定できる少なくとも1つを見てきました。
他のヒント
私は今、私がメタファイルについて知っていることを気にかけてきた以上のことを学びました。
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;
}
あなたがaで通過した場合 SizeF
{8.5、11}の、あなたは Metafile
それにあります rclFrame
{21590、27940}。結局のところ、インチをミリメートルに変換するのは難しくありません。しかし、あなたはおそらくそうしません。解像度に応じて、GDI+は、インチパラメーターを変換するときに切り捨てられたDPI値を使用するようです。それを正しくするためには、100分の1ミリメートルで自分でやらなければなりません。GDI+は、メタファイルヘッダーにネイティブに保存される方法だからです。
this.currentMetafile = new Metafile(
this.currentStream,
deviceContextHandle,
new RectangleF(0, 0, pageSize.Width * 2540, pageSize.Height * 2540),
MetafileFrameUnit.GdiCompatible,
EmfType.EmfOnly);
丸めエラー#1解決 - rclFrame
私のメタファイルの今は正しいです。
2. aのDPI Graphics
インスタンス記録 Metafile
いつも間違っています。
それを見てください metafileGraphics
電話して設定した変数 Graphics.FromImage()
メタファイルについて?まあ、それはそうです Graphics
インスタンスのDPIは常に96 DPIです。 (私が推測しなければならなかった場合、それは常にに設定されています 論理 DPI、ではありません 物理的 1。)
あなたが描いているときに起こる陽気さを想像することができます Graphics
96 dpiで動作し、録音するインスタンス Metafile
87.9231 DPIがヘッダーに「記録された」インスタンス。 (私は他の値から計算されたために「記録された」と言います。)Metafileの「ピクセル」(メタファイルに保存されているGDIコマンドが指定されていることを思い出してください ピクセル)より大きいので、1インチの長さを描くためにあなたの呼びかけが1インチの長さの長さになるのかを呪い、つぶやきます。
解決策は、スケールダウンすることです Graphics
実例:
metafileGraphics = Graphics.FromImage(this.currentMetafile);
metafileHeader = this.currentMetafile.GetMetafileHeader();
metafileGraphics.ScaleTransform(
metafileHeader.DpiX / metafileGraphics.DpiX,
metafileHeader.DpiY / metafileGraphics.DpiY);
それはあまりにもじゃないの?しかし、それはうまくいくようです。
「丸め」エラー#2は解決しました - 88 dpiで「1インチ」で何かを描くと言うと、そのピクセルは$%$^であった方が良いです!ピクセル#88として記録されています。
3. szlMillimeters
大きく異なる可能性があります。リモートデスクトップは非常に楽しいものになります。
それで、私たちは(マークの答えごとに)、時にはWindowsがモニターのエディッドを照会し、実際にそれがどれほど大きいかを実際に知っていることを発見しました。 GDI+はこれを役立ちます(HORZSIZE
など)埋めるとき szlMillimeters
財産。
今、あなたが家に帰ってこのリモートデスクトップのコードをデバッグすることを想像してください。自宅のコンピューターがたまたま16:9ワイドスクリーンモニターがあるとしましょう。
明らかに、Windowsはリモートディスプレイのエディッドを照会できません。したがって、320 x 240 mmの昔ながらのデフォルトを使用しますが、たまたま4:3のアスペクト比であることを除いて問題ありません。正方形の物理ピクセル:水平DPIと垂直DPIは異なり、それが起こったのを最後に見たことを思い出せません。
今のところ私の回避策は、「まあ、リモートデスクトップの下で実行しないでください。」
4.私が使用していたEMF-to-PDFツールは、 rclFrame
ヘッダ。
これが私の問題の主な原因であり、この質問を引き起こしました。私のメタファイルはずっと「正しい」(まあ、最初の2つの問題を修正した後は正しい)、「高解像度」メタファイルを作成するためのこの検索はすべて赤いニシンでした。低解像度ディスプレイデバイスでメタファイルを記録すると、ある程度の忠実度が失われるのは事実です。これは、メタファイルで指定されたGDIコマンドがピクセルで指定されているためです。ベクトル形式であり、スケールアップまたはダウンできることは問題ではありません。一部の情報は失われます 実際の録音中 GDI+がどの「ピクセル」が操作をスナップするかを決定したとき。
私はベンダーに連絡し、彼らは私に修正されたバージョンをくれました。
丸めエラー#3が解決しました。
5. Windowsエクスプローラーの「要約」ペインは、計算されたDPIを表示するときに値を切り捨てます。
この切り捨てられた値は、EMFからPDFへのツールが内部で使用していたのと同じ誤った値を表していることがあります。これとは別に、この癖は議論に意味のあるものに貢献していません。
結論
私の質問は、デバイスのコンテキストでDPIを使用したフューチングに関するものだったので、Mark'sは良い答えです。
MetafileGraphics.dpixが120を返すことを意味する、常にWXPで120 dpiで実行されていることに注意してください。
EMFファイルは、DPIが参照コンテキストのものであるものを記録していないようです(この場合は120、他のほとんどの人で96)。
物事をより面白くするために、300dpiに設定されたsetSrolution()が設定されたメモリビットマップを描くことでEMFを作成することができます。その場合、スケーリング係数は300でなければならず、モニター(86.x)またはWindows(120)が使用しているものではないと考えています。
要約ページの値は間違っているようです。それらは次のように計算されます:
Size = round(precize_size)+1
Resolution = trunc(precize_resolution)
丸めや切り捨てなしにプリス値が計算される場合。