ビットマップ レベルではなく「ベクター」レベルでスケーリングを適用することで、よりシャープなコントロールを実際に印刷できます。
このスナップショットは、次の手法の結果を示しています (私の Win2000 っぽい UI を気にしないでください :-) ):
私たちがしていることは、 reneが彼の答えで示してControlCollection
いるのと非常によく似た方法でコントロールを反復することです.
しかし、さらに、コントロール自体の位置、サイズ、およびフォントにスケールを適用してから、ビットマップを事前設定されたサイズのビットマップに描画します。ほとんどのプリンタ)。
この理由は、印刷時にコントロールの細い線を鮮明に保つためです。または、ビットマップ自体をスケーリングするだけでは、解像度に関して何のメリットもありません。フォントをスケーリングすることで、アンチエイリアス効果を減らし、より良い印刷品質を提供できます。
これを行うには、最初にボタンのクリック イベントを次のように設定します。
//this will produce 5x "sharper" print
MemoryImage = new Bitmap((Panel1.Width * 5), (Panel1.Height * 5));
Using Graphics g = Graphics.FromImage(MemoryImage) {
ScaleControls(Panel1, g, 5);
};
PrintPreviewDialog1.Document = printdoc1;
PrintPreviewDialog1.ShowDialog();
再帰ScaleControls
的な関数では、ビットマップに描画する前に、各コントロール自体をより高い解像度にするために、位置、サイズ、およびフォントをスケーリングします。
private void ScaleControls(Control c, ref Graphics g, double s)
{
//To detach controls for panels, groupboxes etc.
List<Control> hold = null;
foreach (Control ctrl in c.Controls) {
if (ctrl is GroupBox || ctrl is Panel) {
//backup reference to controls
hold = new List<Control>();
foreach (Control gctrl in ctrl.Controls) {
hold.Add(gctrl);
}
ctrl.Controls.Clear();
}
//backup old location, size and font (see explanation)
Point oldLoc = ctrl.Location;
Size oldSize = ctrl.Size;
Font oldFont = ctrl.Font;
//calc scaled location, size and font
ctrl.Location = new Point(ctrl.Location.X * s, ctrl.Location.Y * s);
ctrl.Size = new Size(ctrl.Size.Width * s, ctrl.Height * s);
ctrl.Font = new Font(ctrl.Font.FontFamily, ctrl.Font.Size * 5,
ctrl.Font.Style, ctrl.Font.Unit);
//draw this scaled control to hi-res bitmap
using (Bitmap bmp = new Bitmap(ctrl.Size.Width, ctrl.Size.Height)) {
ctrl.DrawToBitmap(bmp, ctrl.ClientRectangle);
g.DrawImage(bmp, ctrl.Location);
}
//restore control's geo
ctrl.Location = oldLoc;
ctrl.Size = oldSize;
ctrl.Font = oldFont;
//recursive for panel, groupbox and other controls
if (ctrl is GroupBox || ctrl is Panel) {
foreach (Control gctrl in hold) {
ctrl.Controls.Add(gctrl);
}
ScaleControls(ctrl, g, s);
}
}
}
最後に、印刷用のイベント ハンドラーで:
double scale = MemoryImage.Width / e.PageBounds.Width;
e.Graphics.DrawImage(MemoryImage, 0, 0,
Convert.ToInt32(MemoryImage.Width / scale),
Convert.ToInt32(MemoryImage.Height / scale));
さて、この例では、コントロールをその場でスケーリングします。もちろん、印刷プレビューを行っている間、彼らは自分の人生を生きているように見えるので、これは理想的ではありません.
理想的には、繰り返しながら各コントロールを複製し、ビットマップに描画した後に破棄します。これにより、ジオメトリをバックアップする必要もなくなります。しかし、原則の例として、そのまま残しました。クローンなどはお任せします。
コントロールをデタッチする理由は、そうしないと (コードが現在のように - これは別の反復方法 (つまり、複製されたコントロールの事前スケーリング) を提供することで確実に変更できます) で、f.ex. GroupBox
コントロールが最初に印刷され、次にスケーリングされたものが反復時にそれらの上に表示されます。これは、そのコントロールをスケーリングする前に行うDrawToBitmap
ためです。GroupBox
これはあなたに任せます。
私たちが取り組んでいるビットマップは、ユーザーが印刷ダイアログを設定して最終的に得られる印刷の解像度に必ずしも適合しませんが、より高い解像度で作業することで、貧弱な画面ビットマップよりも優れた結果が得られます。私たちが最初に持っている解決策。
もちろん、他のコントロール、画像コントロールなどを保持できるPanel
以外のコントロールの特殊なケースのサポートを追加する必要があります。GroupBox