Paradigm Shift Design

ISHITOYA Kentaro's blog.

大きな画像を一枚に印刷する方法

今日もC#
話がループしちゃって片付かないのは何でだろうといつも思う.
飲み込めばいいのかな.
折衷案を考えるのが仕事になってるような.


まいいや,やることをやろう.
で,画像を印刷する方法.


まず,非ビジュアルコンポーネント*1のPrintDocumentをFormにドラッグアンドドロップする.どうでもいいけどVS2005の「ツールボックス」ってのは分かりにくい.コンポーネントあるいはコントロール一覧と書いておいて欲しい.


で,次のメソッドを印刷する前のタイミングのどこかで1回呼び出しておく.

protected void initializePrinterSettings(String printerName)
{
    //プリンタ名の設定
    this.printDocument1.DefaultPageSettings.PrinterSettings.PrinterName = printerName;
    if (this.printDocument1.DefaultPageSettings.PrinterSettings.IsValid == false)
    {
        //プリンター名がおかしい場合の処理.
        throw new Exception("specified printer name is invalid");
    }
    int paperIndex = 0;
    foreach (PaperSize ps in printDocument1.PrinterSettings.PaperSizes)
    {
        Console.WriteLine(ps.PaperName);
        if (ps.PaperName.Equals("A4"))//用紙のサイズ指定
        {
            break;
        }
        paperIndex++;
    }
    printDocument1.DefaultPageSettings.PaperSize =
    printDocument1.PrinterSettings.PaperSizes[paperIndex];
    printDocument1.DefaultPageSettings.Landscape = true; //横向きならtrue
    printDocument1.DefaultPageSettings.Color = true; //カラー印刷ならtrue
}

設定についてはiniからでも読めばいい.プリンター名はプリンタとFAXにかいてある名前.これまたどうでもいいけど,プロパティがUpperCamelNameなのがすっごい違和感.むかつく.


次に,PrintDocumentコンポーネントのPrintPageイベントに次の関数を割り当てる.

//印刷イベントハンドラ
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
    //拡大率を指定.
    float zoom = 1;
    float padding = 20;
    if (this._bitmap.Width > e.Graphics.VisibleClipBounds.Width)
    {
        zoom = e.Graphics.VisibleClipBounds.Width /
            this._bitmap.Width;
    }
    if ((this._bitmap.Height + padding) * zoom > 
            e.Graphics.VisibleClipBounds.Height)
    {
        zoom = e.Graphics.VisibleClipBounds.Height /
            (this._bitmap.Height + padding);
    }
    e.Graphics.DrawString(DateTime.Now.ToString("yyyy年MM月dd日 (dddd) tt hh時mm分ss秒"),
                          new Font("MS UI Gothic", 11), Brushes.Black, new Point(0, 0));

    //EventArgsのGraphicsにデータを書き込むとそれが印刷される.
    e.Graphics.DrawImage(this._bitmap, 0, padding, 
                                       this._bitmap.Width * zoom,
                                       this._bitmap.Height * zoom);
}

イベントハンドラは定義しただけではダメで,ちゃんとデザイナからイベントハンドラをコンポーネントと関連付けしておかないと印刷されないので注意.

あとは

printDocument1.Print();

として呼び出せば印刷が実行される.
因みにイベントハンドラは,上側に20pxの余白を作ってそこに日付を挿入する.そして,余ったスペースに収まるように画像を拡大縮小して印刷する.日付が不必要なら,paddingを削れば紙全体に収まるように印刷される.
中央ぞろえとかも,これの応用でできるだろう.


因みに,今回は,前回の画面キャプチャと一緒に利用して,キャプチャを即印刷するためのコードとして用意した.

private void button1_Click(object sender, EventArgs e)
{
    //キャプチャ処理
    Rectangle rc;
    rc = Screen.PrimaryScreen.Bounds;

    this._bitmap = new Bitmap(
      rc.Width, rc.Height, PixelFormat.Format32bppArgb);
    using (Graphics g = Graphics.FromImage(this._bitmap))
    {
        g.CopyFromScreen(rc.X, rc.Y, 0, 0,
          rc.Size, CopyPixelOperation.SourceCopy);
    }

    //印刷の実行
    printDocument1.Print();
}

画面キャプチャして,その画像を保存しておいてすぐ印刷.
というわけでした.


C#は好きになれない言語です.多分.

*1:C#用語ではなんていうんだろう