あなたの質問には、「最良の」長方形が何であるかについて少し明確さが欠けています。印刷時に 100% 表示される最大の長方形を意味すると仮定します。
それでは、印刷ドキュメントのグラフィックス オブジェクトの「起点」とは何か、OriginAtMargins プロパティがこの起点にどのように影響するかを理解することから始めましょう。
OriginAtMargins - ページに関連付けられたグラフィックス オブジェクトの位置が、ユーザー指定の余白のすぐ内側にあるか、ページの印刷可能領域の左上隅にあるかを示す値を取得または設定し
ます。
- MSDN の PrintDocument クラス定義
したがって、 (デフォルト) にOriginAtMargins
設定するとfalse
、グラフィックス オブジェクトは PrintableArea の四角形に調整されます (私のレーザー プリンターでは各ページの端から約 5/32、古いレーザー プリンターはそれ以上になる可能性があり、新しいインクジェットは端まで印刷される可能性があり、ソフトウェア PDF プリンターは端まで印刷されます)。したがって、私のグラフィックス オブジェクトの 0,0 は、レーザー プリンターの物理ページでは実際には 16,16 です (プリンターは異なる場合があります)。
デフォルトの 1 インチのページ マージンを にOriginAtMargins
設定するtrue
と、グラフィック オブジェクトは通常の縦長のレター ページの 100、100、650、1100 の長方形に調整されます。これは、物理的な各ページの端から 1 インチ内側にあります。したがって、グラフィック オブジェクトの 0,0 は、物理ページでは実際には 100,100 です。
マージンは、ソフトウェアで定義され、物理的な印刷デバイスの影響を受けないため、「ソフト マージン」とも呼ばれます。これは、ソフトウェアで現在のページ サイズに適用され、実際のページの縦または横の寸法を反映することを意味します。
PrintableArea は、印刷デバイスの物理的な制限を反映する「ハード マージン」とも呼ばれます。これは、プリンターごと、メーカーごとに異なります。これらはハードウェアの測定値であるため、ページを横向き/縦向きに設定しても回転しません。ソフトウェアの印刷設定に関係なく、物理的な制限はプリンターで変更されないため、印刷ドキュメントのソフトウェア設定 (方向) に応じて、正しい軸にそれらを適用する必要があります。
したがって、投稿したサンプル コードの大まかなモデルに従って、表示されたまま可能な限り大きな四角形を描画する PrintDocument.PrintPage イベント ハンドラーを次に示します (デフォルトPrintDocument.OriginsAtMargins
はfalse
)。これを設定PrintDocument.OriginsAtMargins
するtrue
と、構成されたソフト マージン (デフォルトではページの端から 1 インチ) 内に表示されたまま、できるだけ大きな長方形が描画されます。
PrintAction printAction = PrintAction.PrintToFile;
private void printDocument_BeginPrint(object sender, PrintEventArgs e)
{
// Save our print action so we know if we are printing
// a preview or a real document.
printAction = e.PrintAction;
// Set some preferences, our method should print a box with any
// combination of these properties being true/false.
printDocument.OriginAtMargins = false; //true = soft margins, false = hard margins
printDocument.DefaultPageSettings.Landscape = false;
}
private void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
Graphics g = e.Graphics;
// If you set printDocumet.OriginAtMargins to 'false' this event
// will print the largest rectangle your printer is physically
// capable of. This is often 1/8" - 1/4" from each page edge.
// ----------
// If you set printDocument.OriginAtMargins to 'false' this event
// will print the largest rectangle permitted by the currently
// configured page margins. By default the page margins are
// usually 1" from each page edge but can be configured by the end
// user or overridden in your code.
// (ex: printDocument.DefaultPageSettings.Margins)
// Grab a copy of our "soft margins" (configured printer settings)
// Defaults to 1 inch margins, but could be configured otherwise by
// the end user. You can also specify some default page margins in
// your printDocument.DefaultPageSetting properties.
RectangleF marginBounds = e.MarginBounds;
// Grab a copy of our "hard margins" (printer's capabilities)
// This varies between printer models. Software printers like
// CutePDF will have no "physical limitations" and so will return
// the full page size 850,1100 for a letter page size.
RectangleF printableArea = e.PageSettings.PrintableArea;
// If we are print to a print preview control, the origin won't have
// been automatically adjusted for the printer's physical limitations.
// So let's adjust the origin for preview to reflect the printer's
// hard margins.
if (printAction == PrintAction.PrintToPreview)
g.TranslateTransform(printableArea.X, printableArea.Y);
// Are we using soft margins or hard margins? Lets grab the correct
// width/height from either the soft/hard margin rectangles. The
// hard margins are usually a little wider than the soft margins.
// ----------
// Note: Margins are automatically applied to the rotated page size
// when the page is set to landscape, but physical hard margins are
// not (the printer is not physically rotating any mechanics inside,
// the paper still travels through the printer the same way. So we
// rotate in software for landscape)
int availableWidth = (int)Math.Floor(printDocument.OriginAtMargins
? marginBounds.Width
: (e.PageSettings.Landscape
? printableArea.Height
: printableArea.Width));
int availableHeight = (int)Math.Floor(printDocument.OriginAtMargins
? marginBounds.Height
: (e.PageSettings.Landscape
? printableArea.Width
: printableArea.Height));
// Draw our rectangle which will either be the soft margin rectangle
// or the hard margin (printer capabilities) rectangle.
// ----------
// Note: we adjust the width and height minus one as it is a zero,
// zero based co-ordinates system. This will put the rectangle just
// inside the available width and height.
g.DrawRectangle(Pens.Red, 0, 0, availableWidth - 1, availableHeight - 1);
}
利用可能な幅と利用可能な高さを決定する 2 つの行は、質問で探していたものだと思います。これらの 2 行は、ソフト マージンまたはハード マージンのどちらが必要か、および印刷ドキュメントが横向きまたは縦向きのどちらに設定されているかを考慮します。
使用Math.Floor()
可能な幅と高さが使用可能な寸法のすぐ内側にあることを確認するためだけに、小数を超えるもの (例: 817.96 -> 817) をドロップする簡単な方法を使用しました。ここでは「フェイルセーフ」です。(int ではなく) float ベースの座標を維持したい場合は、切り捨てられたグラフィックスになる丸め誤差に注意してください (817.96 を 818 に丸める場合)。その後、プリンタードライバーはそれが表示されなくなったと判断します)。
Dell 3115CN、Samsung SCX-4x28、および CutePDF ソフトウェア プリンターで、ハード マージンとソフト マージンの両方を使用して、縦向きと横向きの両方でこの手順をテストしました。これで質問が適切に解決されなかった場合は、「魔法の長方形」と「最適な長方形」を明確にするために質問を修正することを検討してください。
編集:「ソフトマージン」に関する注意
ソフト マージンはソフトウェアで適用され、プリンターのハードウェア制限は考慮されません。これは意図的であり、設計によるものです。必要に応じて、印刷可能領域の外側にソフト マージンを設定できます。出力がプリンターのドライバーによって切り取られる場合があります。これがアプリケーションにとって望ましくない場合は、プログラム コードのマージンを調整する必要があります。ユーザーが印刷可能領域外の余白を選択できないようにする (または選択する場合は警告する) か、実際にドキュメントの印刷 (描画) を開始するときに、コードで最小/最大条件を強制することができます。
例: Microsoft Word 2007 でページの余白を 0,0,0,0 に設定すると、「ページの印刷可能領域の外側に 1 つまたは複数の余白が設定されています。[修正] ボタンを選択して、ページの余白を増やします。」という警告ダイアログが表示されます。適切なマージン。」[修正] をクリックすると、Word は単純にハード マージンをソフト マージンにコピーするため、ダイアログにはすべてのマージンが 0.16 インチと表示されます (私のレーザー プリンターの機能)。
これは予期される動作です。ユーザーがこの警告を無視し、0,0,0,0 ページの余白を使用したために、印刷されたページが切り取られても、Microsoft Word のバグ/問題ではありません。これはアプリケーションでも同じです。ユースケースで適切な場合は、制限を適用する必要があります。警告ダイアログを表示するか、コードで制限をより強く強制することができます (ユーザーに選択肢を提供しないでください)。
代替戦略
ハード マージンだけを取得するのではなく、ソフト マージンを取得してから、印刷時にソフト マージンが印刷可能領域内に残るように強制することもできます。ここで別の戦略を立てましょう。
この例では、余白で起点を使用し、ユーザーが必要な余白を選択できるようにしますが、選択した余白が印刷可能領域外にならないようにコードで強制します。選択した余白が印刷可能領域の外側にある場合は、単に印刷可能領域内になるように調整します。
PrintAction printAction = PrintAction.PrintToFile;
private void printDocument_BeginPrint(object sender, PrintEventArgs e)
{
// Save our print action so we know if we are printing
// a preview or a real document.
printAction = e.PrintAction;
// We ALWAYS want true here, as we will implement the
// margin limitations later in code.
printDocument.OriginAtMargins = true;
// Set some preferences, our method should print a box with any
// combination of these properties being true/false.
printDocument.DefaultPageSettings.Landscape = false;
printDocument.DefaultPageSettings.Margins.Top = 100;
printDocument.DefaultPageSettings.Margins.Left = 0;
printDocument.DefaultPageSettings.Margins.Right = 50;
printDocument.DefaultPageSettings.Margins.Bottom = 0;
}
private void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
Graphics g = e.Graphics;
// If you set printDocumet.OriginAtMargins to 'false' this event
// will print the largest rectangle your printer is physically
// capable of. This is often 1/8" - 1/4" from each page edge.
// ----------
// If you set printDocument.OriginAtMargins to 'false' this event
// will print the largest rectangle permitted by the currently
// configured page margins. By default the page margins are
// usually 1" from each page edge but can be configured by the end
// user or overridden in your code.
// (ex: printDocument.DefaultPageSettings.Margins)
// Grab a copy of our "hard margins" (printer's capabilities)
// This varies between printer models. Software printers like
// CutePDF will have no "physical limitations" and so will return
// the full page size 850,1100 for a letter page size.
RectangleF printableArea = e.PageSettings.PrintableArea;
RectangleF realPrintableArea = new RectangleF(
(e.PageSettings.Landscape ? printableArea.Y : printableArea.X),
(e.PageSettings.Landscape ? printableArea.X : printableArea.Y),
(e.PageSettings.Landscape ? printableArea.Height : printableArea.Width),
(e.PageSettings.Landscape ? printableArea.Width : printableArea.Height)
);
// If we are printing to a print preview control, the origin won't have
// been automatically adjusted for the printer's physical limitations.
// So let's adjust the origin for preview to reflect the printer's
// hard margins.
// ----------
// Otherwise if we really are printing, just use the soft margins.
g.TranslateTransform(
((printAction == PrintAction.PrintToPreview)
? realPrintableArea.X : 0) - e.MarginBounds.X,
((printAction == PrintAction.PrintToPreview)
? realPrintableArea.Y : 0) - e.MarginBounds.Y
);
// Draw the printable area rectangle in PURPLE
Rectangle printedPrintableArea = Rectangle.Truncate(realPrintableArea);
printedPrintableArea.Width--;
printedPrintableArea.Height--;
g.DrawRectangle(Pens.Purple, printedPrintableArea);
// Grab a copy of our "soft margins" (configured printer settings)
// Defaults to 1 inch margins, but could be configured otherwise by
// the end user. You can also specify some default page margins in
// your printDocument.DefaultPageSetting properties.
RectangleF marginBounds = e.MarginBounds;
// This intersects the desired margins with the printable area rectangle.
// If the margins go outside the printable area on any edge, it will be
// brought in to the appropriate printable area.
marginBounds.Intersect(realPrintableArea);
// Draw the margin rectangle in RED
Rectangle printedMarginArea = Rectangle.Truncate(marginBounds);
printedMarginArea.Width--;
printedMarginArea.Height--;
g.DrawRectangle(Pens.Red, printedMarginArea);
}