Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2000年12月12日] [更新 2016年04月25日] 印刷プレビュー制御コンポーネント
   
印刷プレビュー制御コンポーネント
イメージの描画
動作確認等 図 Windows 7 U64(SP1) + Delphi XE(UP1) Pro で作成







イメージの描画


印刷プレビュー制御コンポーネントでは,文字列や画像 (イメージ) を内部の TMetaFileCanvas に描画しています.そのため,画像ファイルの中には,特にメタファイルは,以下のメソッドでは描画できないものもあります.
画像の拡大,縮小の補間処理はしていません.必要であれば各自で実装してください.





イメージの描画 ( サイズ調整なし )


DrawPict(X1, Y1, FileName)

ディスクからグラフィックス・イメージを読込んで描画します.大きさは元のままです.
ただし,TplPrev では 1 ドットが 0.1 mm であることに注意して下さい.これは,同じ画像でも,プリンタの印刷の解像度 (DPI) が異なると,印刷結果の画像の大きさが異なることを意味します.

Delphi 2007 以前では EMF, BMP, ICO, JPG が,Delphi 2009 以降では GIF, PNG の画像も表示できます.ただし,画像のフォーマットによっては表示できないこともあります. 画像の種類は拡張子で判定しています.拡張子は大文字でも小文字でも認識します.

TBitmap 等のオブジェクトを印刷するコードは,各自で作成してください.通常の TCanvas 関係の描画メソッド類が使用できます.TplPrev.Canvas に描画します.


[備考]
説明用の資料作成等で,場合によっては,実際のピクセル数に応じたサイズで描画,印刷したいことがあります.そのためのメソッドです.


引数 説明
X1 Integer 描画するイメージ左端の X 座標値
Y1 Integer 描画するイメージ上端の Y 座標値
FileName String 描画するイメージのファイル名




イメージの描画 ( 指定枠内 )


StretchDrawPict(X1, X2, Y1, Y2, IsFit, FileName)

ディスクからグラフィックス・イメージを読込んで指定表示枠に合わせて,拡大縮小して描画します.表示枠は描画しません.
画像の縦横比を保ったまま,指定した枠 (四角の領域) に合わせて画像を描画するには,画像の縦横比を計算して,その値を元にして X1, X2, Y1, Y2 の値を計算する必要があります.

Delphi 2007 以前では EMF, BMP, ICO, JPG が,Delphi 2009 以降では GIF, PNG の画像も表示できます.ただし,画像のフォーマットによっては表示できないこともあります.
画像の種類は拡張子で判定しています (大文字小文字は問いません).

TBitmap 等のオブジェクトを印刷するコードは,各自で作成してください.通常の TCanvas 関係の描画メソッド類が使用できます.TplPrev.Canvas に描画します.


引数 説明
X1 Integer 表示枠の左端のX座標値
X2 Integer 表示枠の右端の X 座標値
Y1 Integer 表示枠の上端の Y 座標値
Y2 Integer 表示枠の下端の Y 座標値
IsFit Boolean 縦横比フラグ.
Ture : 枠の大きさに合わせて拡大縮小描画.縦横比は変化
False : 縦横比は変えずに,縦または横の寸法に合わせて描画
FileName String 描画するイメージのファイル名


図1
左が IsFit=True で右が False の場合




ビットマップの指定枠内への描画


StretchDrawBitmap(ARect, Pict)

TBitmap の画像を,指定枠内にストレッチ描画します.
画像の縦横比を保ったまま,指定した枠 (四角の領域) に合わせて画像を描画するには,画像の縦横比を計算して,その値を元にして ARect の各メンバの値を計算する必要があります.

TBitmap 以外のオブジェクトを印刷するコードは,各自で作成してください.通常の TCanvas 関係の描画メソッド類が使用できます.TplPrev.Canvas に描画します.


引数 説明
ARect TRect 領域を指定する TRect 構造体
Pict TBitmap 描画するビットマップ




メタファイルの指定枠内への描画


StretchDrawMetaFile(ARect, Pict)

拡張子が wmf, emf のファイルから TMetaFile オブジェクトに読込んだり,コード内で作成したメタファイル等を表示します.ただし,メタファイルによつては描画できないものもあります.

画像の縦横比を保ったまま,指定した枠 (四角の領域) に合わせて画像を描画するには,画像の縦横比を計算して,その値を元にして ARect の各メンバの値を計算する必要があります.


引数 説明
ARect TRect 領域を指定する TRect 構造体
Pict TMetaFile 描画するメタファイル




画像の縦横比を保ったまま画像を描画する例 - 横幅固定


これ以降は,元の画像の縦横比を保ったまま,指定した枠 (四角の領域) に合わせて画像を描画する具体的な例です.これらの描画方法は,StrethcDrawPict の引数を変えることで実現できますが,その際の計算の参考用です.

下のコードでは,横幅を固定して,その横幅と画像の縦横比の値から描画の高さを計算して,画像を描画します.描画の右端の座標値が,印刷可能な領域の右端を超えないように注意します.横長の画像の描画用の参考コードと言えます.
縦長の画像だと,下部がクリップされて描画されないことがあります.



//=============================================================================
//  指定領域に合わせて画像を描画する例
//  印刷領域の横幅を基準にする場合
//  横長の画像用
//
//  新規のプロジェクトに
//  TButtonと拙作のTplPrevコンポを配置
//
//  poLandscape等の定数名の使用にはusesにPrintersが必要
//
//  動作確認 Widnows 7 U64(SP1) + Delphi XE(UP1) Pro
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LBitmap         : TBitmap;
  LImgRatio       : Double;
  LImgPrintRect   : TRect;
  LImgPrintWidth  : Integer;
  LImgPrintHeight : Integer;
begin
   //用紙の設定をA4縦方向の印刷とする
   plPrev1.plSetPrinter.PaperNumber := DMPAPER_A4;
   plPrev1.plSetPrinter.Orientation := poPortrait;

   //印刷用のコードを書く
   plPrev1.BeginDoc;
   try
     LBitmap := TBitmap.Create;
     try
       //画像をディスクから読み込む
       LBitmap.LoadFromFile(ExtractFilePath(Application.ExeName) + 'TestImage.bmp');

       if (LBitmap.Width * LBitmap.Height) > 0 then begin
         //画像の縦横比を計算
         LImgRatio  := LBitmap.Height / LBitmap.Width;
         //画像の描画の横幅を固定値として,縦横比から描画の高さを計算
         //ここでは横幅を1500(150mm)としている
         //高さを固定する場合は,以下のように高さを決めてから幅を計算する
         //  LImgPrintHeight := 1100;
         //  LImgPrintWidth  := Trunc(LImgPrintHeight / LImgRatio);
         LImgPrintWidth  := 1500;
         LImgPrintHeight := Trunc(LImgPrintWidth * LImgRatio);

         LImgPrintRect.Left   := 300;          //描画開始右端X座標値(30mm)
         LImgPrintRect.Top    := 250;          //描画開始上端Y座標値(25mm)
         LImgPrintRect.Right  := LImgPrintRect.Left + LImgPrintWidth;
         LImgPrintRect.Bottom := LImgPrintRect.Top  + LImgPrintHeight;

         //TplPrev.Canvasに画像を描画
         plPrev1.Canvas.StretchDraw(LImgPrintRect, LBitmap);
       end;
     finally
       FreeAndNil(LBitmap);
     end;
   finally
     plPrev1.EndDoc;
   end;
   //プレビュー表示開始
   plPrev1.ShowModal;
end;




画像の縦横比を保ったまま画像を描画する例 - 高さ固定


元の画像の縦横比を保ったまま,指定した枠 (四角の領域) に合わせて画像を描画する例です.
このコードでは,高さを固定して,その高さと画像の縦横比の値から描画の横幅を計算して,画像を描画します.描画の下端の座標値が,印刷可能な領域の下端を超えないように注意します.縦長の画像描画用の参考コードと言えます.
横長の画像だと,右側がクリップされて描画されないことがあります.



//=============================================================================
//  指定領域に合わせて画像を描画する例
//  印刷領域の高さを基準にする場合
//  縦長画像用
//
//  新規のプロジェクトに
//  TButtonと拙作のTplPrevコンポを配置
//
//  poLandscape等の定数名の使用にはusesにPrintersが必要
//
//  動作確認 Widnows 7 U64(SP1) + Delphi XE(UP1) Pro
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LBitmap         : TBitmap;
  LImgRatio       : Double;
  LImgPrintRect   : TRect;
  LImgPrintWidth  : Integer;
  LImgPrintHeight : Integer;
begin
   //用紙の設定をA4横方向の印刷とする
   plPrev1.plSetPrinter.PaperNumber := DMPAPER_A4;
   plPrev1.plSetPrinter.Orientation := poLandscape;

   //印刷用のコードを書く
   plPrev1.BeginDoc;
   try
     LBitmap := TBitmap.Create;
     try
       //画像をディスクから読み込む
       LBitmap.LoadFromFile(ExtractFilePath(Application.ExeName) + 'TestImageVert.bmp');

       if (LBitmap.Width * LBitmap.Height) > 0 then begin
         //画像の縦横比を計算
         LImgRatio  := LBitmap.Height / LBitmap.Width;
         //画像の描画の高さを固定値として,縦横比から描画の幅を計算
         //ここでは高さを1100(110mm)としている
         //幅を固定する場合は,以下のように幅を決めてから高さを計算する
         //  LImgPrintWidth  := 1500;
         //  LImgPrintHeight := Trunc(LImgPrintWidth * LImgRatio);
         LImgPrintHeight := 1100;
         LImgPrintWidth  := Trunc(LImgPrintHeight / LImgRatio);

         LImgPrintRect.Left   := 300;               //描画開始右端X座標値(30mm)
         LImgPrintRect.Top    := 250;               //描画開始上端Y座標値(25mm)
         LImgPrintRect.Right  := LImgPrintRect.Left + LImgPrintWidth;
         LImgPrintRect.Bottom := LImgPrintRect.Top  + LImgPrintHeight;

         //TplPrev.Canvasに画像を描画
         plPrev1.Canvas.StretchDraw(LImgPrintRect, LBitmap);
       end;
     finally
       FreeAndNil(LBitmap);
     end;
   finally
     plPrev1.EndDoc;
   end;
   //プレビュー表示開始
   plPrev1.ShowModal;
end;




印刷可能な領域の幅を基準にして画像を描画する例


上の最初のコードと同じですが,用紙の印刷可能範囲を横幅とする例です.
横長の画像を描画する際の参考コードと言えます.

用紙の印刷可能な範囲に画像を描画するわけですから,画像を描画する範囲を,その印刷可能な範囲に設定することになります.このサンプルでは,横幅を印刷可能な領域の幅と同じにしています.また,上端は,印刷可能な上端と同じとしています.したがって,縦長の画像の場合,サイズによっては,画像の下部がクリップされ,印刷されない可能性もあります.
今度は,JPEG 画像をディスクから読み込むものとします.

このコードは,上の方の,横幅固定のサンプルコードで,描画の幅を印刷可能な領域の幅にして,描画開始位置の上端を,印刷可能な上端の座標にしただけです.上端に余白 (マージン) が必要であれば,描画開始の上端の Y 座標値を別の値にします.




図2
実行結果の例

//=============================================================================
//  指定領域に合わせて画像を描画する例
//
//  新規のプロジェクトに
//  TButtonと拙作のTplPrevコンポを配置
//
//  poPortrait等の定数名の使用にはusesにPrintersが必要
//  TJPEGImageの使用にはusesにJpegが必要
//
//  動作確認 Widnows 7 U64(SP1) + Delphi XE(UP1) Pro
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  LJpegImage      : TJPEGImage;
  LImgRatio       : Double;
  LImgPrintRect   : TRect;
  LImgPrintWidth  : Integer;
  LImgPrintHeight : Integer;
begin
   //用紙の設定をA4縦方向の印刷とする
   plPrev1.plSetPrinter.PaperNumber := DMPAPER_A4;
   plPrev1.plSetPrinter.Orientation := poPortrait;

   //印刷用のコードを書く
   plPrev1.BeginDoc;
   try
     LJpegImage := TJPEGImage.Create;
     try
       //画像をディスクから読み込む
       LJpegImage.LoadFromFile(ExtractFilePath(Application.ExeName) + 'TestImage.jpg');

       if (LJpegImage.Width * LJpegImage.Height) > 0 then begin
         //画像の縦横比を計算
         LImgRatio  := LJpegImage.Height / LJpegImage.Width;
         //画像の描画の横幅を固定値として,縦横比から描画の高さを計算
         //ここでは横幅を印刷可能な幅としている
         LImgPrintWidth  := plPrev1.PageWidth;
         LImgPrintHeight := Trunc(LImgPrintWidth * LImgRatio);

         LImgPrintRect.Left   := plPrev1.LeftOffset;   //描画開始右端X座標値
         LImgPrintRect.Top    := plPrev1.TopOffset;    //描画開始上端Y座標値
         LImgPrintRect.Right  := LImgPrintRect.Left + LImgPrintWidth;
         LImgPrintRect.Bottom := LImgPrintRect.Top + LImgPrintHeight;

         //TplPrev.Canvasに画像を描画
         plPrev1.Canvas.StretchDraw(LImgPrintRect, LJpegImage);
       end;
     finally
       FreeAndNil(LJpegImage);
     end;
   finally
     plPrev1.EndDoc;
   end;
   //プレビュー表示開始
   plPrev1.ShowModal;
end;


綴じ代の分として,左端にある程度の余白 (マージン) が必要であれば,次のように,ます,描画開始の左端位置を決めて,描画の幅を計算します.求まった描画の幅と画像の縦横比から描画の高さを計算することができます.



         //画像の縦横比を計算
         LImgRatio  := LJpegImage.Height / LJpegImage.Width;

         LImgPrintRect.Left := 250;
         LImgPrintRect.Top  := 350;

         LImgPrintWidth  := plPrev1.RightOffset - LImgPrintRect.Left;
         LImgPrintHeight := Trunc(LImgPrintWidth * LImgRatio);

         LImgPrintRect.Right  := LImgPrintRect.Left + LImgPrintWidth;
         LImgPrintRect.Bottom := LImgPrintRect.Top + LImgPrintHeight;


右端にもマージンが必要な場合は,まず,左端と右端の位置を決めます.その値から画像の描画幅が求まります.求まった描画幅の値と画像の縦横比から描画の高さを計算します.



         //画像の縦横比を計算
         LImgRatio  := LJpegImage.Height / LJpegImage.Width;

         LImgPrintRect.Left  := 250;
         LImgPrintRect.Top   := 350;
         LImgPrintRect.Right := plPrev1.PaperWidth - 150;

         LImgPrintWidth  := LImgPrintRect.Right - LImgPrintRect.Left;
         LImgPrintHeight := Trunc(LImgPrintWidth * LImgRatio);

         LImgPrintRect.Bottom := LImgPrintRect.Top + LImgPrintHeight;




印刷可能な領域の高さを基準にして画像を描画する例


次のコードは,縦長の画像用です.
描画の高さを印刷可能な領域の高さと同じにして,左端からの描画位置を決めています.

このコードは,上の方の,高さ固定のサンプルコードで,描画の高さを印刷可能な領域の高さとして,描画開始位置の上端を,印刷可能な上端にして,描画開始の左端の X 座標を指定しただけです.




図3
実行結果の例

procedure TForm1.Button4Click(Sender: TObject);
var
  LBitmap         : TBitmap;
  LImgRatio       : Double;
  LImgPrintRect   : TRect;
  LImgPrintWidth  : Integer;
  LImgPrintHeight : Integer;
begin
   //用紙の設定をA4横方向の印刷とする
   plPrev1.plSetPrinter.PaperNumber := DMPAPER_A4;
   plPrev1.plSetPrinter.Orientation := poLandscape;

   //印刷用のコードを書く
   plPrev1.BeginDoc;
   try
     LBitmap := TBitmap.Create;
     try
       //画像をディスクから読み込む
       LBitmap.LoadFromFile(ExtractFilePath(Application.ExeName) + 'TestImageVert.bmp');

       if (LBitmap.Width * LBitmap.Height) > 0 then begin
         //画像の縦横比を計算
         LImgRatio  := LBitmap.Height / LBitmap.Width;
         //画像の描画の高さを固定値として,縦横比から描画の幅を計算
         //ここでは高さを印刷可能高さとしている
         LImgPrintHeight := plPrev1.PageHeight;
         LImgPrintWidth  := Trunc(LImgPrintHeight / LImgRatio);

         LImgPrintRect.Left   := 250;
         LImgPrintRect.Top    := plPrev1.TopOffset;
         LImgPrintRect.Right  := LImgPrintRect.Left + LImgPrintWidth;
         LImgPrintRect.Bottom := LImgPrintRect.Top + LImgPrintHeight;

         //TplPrev.Canvasに画像を描画
         plPrev1.Canvas.StretchDraw(LImgPrintRect, LBitmap);
       end;
     finally
       FreeAndNil(LBitmap);
     end;
   finally
     plPrev1.EndDoc;
   end;
   //プレビュー表示開始
   plPrev1.ShowModal;
end;


上部に説明文章用等に,ある程度の余白 (マージン) が必要な場合は,次のように,まず,描画開始位置の上端の位置を決めて.描画の高さを計算します.その描画の高さと縦横比から描画の幅を計算することができます.



         //画像の縦横比を計算
         LImgRatio  := LBitmap.Height / LBitmap.Width;

         LImgPrintRect.Left := 250;
         LImgPrintRect.Top  := 350;

         LImgPrintHeight := plPrev1.BottomOffset - LImgPrintRect.Top;
         LImgPrintWidth  := Trunc(LImgPrintHeight / LImgRatio);

         LImgPrintRect.Right  := LImgPrintRect.Left + LImgPrintWidth;
         LImgPrintRect.Bottom := LImgPrintRect.Top + LImgPrintHeight;


下端にもマージンが必要な場合は,まず,上端と下端の位置を決めます.その値から画像の描画高さが求まります.求まった高さの値と画像の縦横比から描画の幅を計算します.



         //画像の縦横比を計算
         LImgRatio  := LBitmap.Height / LBitmap.Width;

         LImgPrintRect.Left   := 250;
         LImgPrintRect.Top    := 350;
         LImgPrintRect.Bottom := plPrev1.PaperHeight - 150;

         LImgPrintHeight := LImgPrintRect.Bottom - LImgPrintRect.Top;
         LImgPrintWidth  := Trunc(LImgPrintHeight / LImgRatio);

         LImgPrintRect.Right  := LImgPrintRect.Left + LImgPrintWidth;




印刷可能な領域の上下左右の中央に描画する例


印刷可能な領域の上下左右の中央に描画する例です.
このコードは,描画の横幅を固定して,印刷可能な領域の上下左右の中央に描画します.この時,画像の描画幅を,印刷可能な領域の幅よりも大きくしないように注意します.
このコードは,横長の画像を描画する際の参考コードと言えます.したがって,縦長の画像だと,サイズによっては,上下がクリップされて描画されないことがあります.




図4
実行結果の例

//=============================================================================
//  指定領域に合わせて画像を描画する例
//  用紙の印刷可能領域の上下左右の中央に描画する場合
//
//  新規のプロジェクトに
//  TButtonと拙作のTplPrevコンポを配置
//
//  poLandscape等の定数名の使用にはusesにPrintersが必要
//
//  動作確認 Widnows 7 U64(SP1) + Delphi XE(UP1) Pro
//=============================================================================
procedure TForm1.Button5Click(Sender: TObject);
var
  LBitmap         : TBitmap;
  LImgRatio       : Double;
  LImgPrintRect   : TRect;
  LImgPrintWidth  : Integer;
  LImgPrintHeight : Integer;
begin
   //用紙の設定をA4縦方向の印刷とする
   plPrev1.plSetPrinter.PaperNumber := DMPAPER_A4;
   plPrev1.plSetPrinter.Orientation := poPortrait;

   //印刷用のコードを書く
   plPrev1.BeginDoc;
   try
     LBitmap := TBitmap.Create;
     try
       //画像をディスクから読み込む
       LBitmap.LoadFromFile(ExtractFilePath(Application.ExeName) + 'sakura_yoko.bmp');

       if (LBitmap.Width * LBitmap.Height) > 0 then begin
         //画像の縦横比を計算
         LImgRatio  := LBitmap.Height / LBitmap.Width;

         //横幅を固定して,その値から描画高さを計算
         //高さ固定の場合は高さを決めてから幅を計算する
         //  LImgPrintHeight := 1200;
         //  LImgPrintWidth  := Trunc(LImgPrintHeight / LImgRatio);
         LImgPrintWidth  := 1500;
         LImgPrintHeight := Trunc(LImgPrintWidth * LImgRatio);
         //これ以降は幅固定の場合でも,高さ固定の場合でも同じ

         LImgPrintRect.Left   := plPrev1.LeftOffset
                               + (plPrev1.PageWidth  - LImgPrintWidth)  div 2;
         LImgPrintRect.Top    := plPrev1.TopOffset
                               + (plPrev1.PageHeight - LImgPrintHeight) div 2;
         LImgPrintRect.Right  := LImgPrintRect.Left + LImgPrintWidth;
         LImgPrintRect.Bottom := LImgPrintRect.Top  + LImgPrintHeight;

         //TplPrev.Canvasに画像を描画
         plPrev1.Canvas.StretchDraw(LImgPrintRect, LBitmap);
       end;
     finally
       FreeAndNil(LBitmap);
     end;
   finally
     plPrev1.EndDoc;
   end;
   //プレビュー表示開始
   plPrev1.ShowModal;
end;


画像を,印刷可能な領域の上下左右の中央に描画する際,印刷可能な領域の幅,あるいは高さにするには,印刷可能な領域の幅,または印刷可能な領域の高さに設定します.

また,StretchDrawPict メソッドも利用できます.StretchDrawPict メソッドの引数を以下のように,印刷可能な領域の値と同じにします.StretchDrawPict メソッドを以下のように設定すると,画像の全てを印刷可能な領域内に描画することができます.
ここまで,いろいろな設定の例を示しましたが,StretchDrawPict の該当する引数の値を変更することでも全て実現可能です.ただし,StretchDrawPict は,画像をディスクから読み込んで描画します.したがって,画像をリソース等から取り出したり,内部で生成する用途には向いていません.



   IsFit := False;
   X1 := plPrev1.LeftOffset;
   X2 := plPrev1.RightOffset;
   Y1 := plPrev1.TopOffset;
   Y2 := plPrev1.BottomOffset;


下のコードは,StretchDrawPict メソッドを使用して,JPEG 画像を印刷可能な領域の上下左右の中央に描画する例です.
この画像は横長で,描画幅が印刷可能な幅と同じになっています.したがって,左端にマージンが必要であれば,第 1 引数の値を変更するだけで対応できます.



図5
実行結果の例

procedure TForm1.Button9Click(Sender: TObject);
var
  LFileName : string;
begin
   //用紙の設定をA4縦方向の印刷とする
   plPrev1.plSetPrinter.PaperNumber := DMPAPER_A4;
   plPrev1.plSetPrinter.Orientation := poPortrait;

   //印刷用のコードを書く
   plPrev1.BeginDoc;
   try
     //読み込む画像のファイル名
     LFileName := ExtractFilePath(Application.ExeName) + 'test.jpg';
     //TplPrev.Canvasに画像を描画
     plPrev1.StretchDrawPict(plPrev1.LeftOffset,
                             plPrev1.RightOffset,
                             plPrev1.TopOffset,
                             plPrev1.BottomOffset,
                             False,
                             LFileName);

     plPrev1.FontSize(40);
     plPrev1.Canvas.Font.Color := clBlack;
     plPrev1.Canvas.TextOut(600, 1200, '画像の印刷例');
   finally
     plPrev1.EndDoc;
   end;
   //プレビュー表示開始
   plPrev1.ShowModal;
end;