Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2012年12月02日] [更新 2017年06月25日] GDI+ 関係サンプル
   
GDI+ 関係サンプル 
G040_各種の画像形式の表示と変換
動作確認等 Windows 7 U64(SP1) + Delphi XE(UP1) Pro
G040_GDIPlus_SomeImageTypes.zip [1,258 KB] 2017年06月25日版 (EXE 同梱)



  • 2013年05月09日
  • GDI+ を使用しない画像形式の変換のサンプルを追加
  • 2013年05月15日
  • [マルチページ TIFF 画像の作成と表示] を追加
  • 2017年05月05日
  • GDI+ を使用しない画像形式の変換関係のサンプルを別のページに移動




GDI+ で扱える画像形式の種類


GDI+ では次の形式の画像をディスクから読み込んで表示できます.現在の画像形式を別の形式の画像に変換して保存ができますが,メタファイルと ICON 形式での保存はできません.
下の表の右端の値は,各画像ファイルの先頭バイトからの値です.画像形式を変換して保存した時に,バイナリエディタを使用して,画像の種類をこれらの値で確認できます.

アイコンは,TGPBitmap から ビットマップ (TBitmap) を取得して,そのビットマップをアイコン形式の画像に変換すれば保存できます.



拡張子 名称 保存の可否 先頭バイト値
BMP ビットマップ BM
GIF ジフ GIF89a
JPEG ジェイペグ $FFD8
PNG ピング $89 + PNG + $0D0A
TIFF ティフ MM または II
WMF (Windows メタファイル) ウィンドウズメタファイル 不可 未確認
EMF (拡張メタファイル) エンハンスドメタファイル 不可 未確認
EMF+ エンハンスドメタファイルプラス 不可 未確認
ICON アイコン 不可 未確認






01_TGPBitmap.Save メソッドで画像形式を指定して保存


GDI+ で画像を他の形式に変換して保存するには,GetEncoderClsid 関数で,各画像形式に応じた MIME タイプの GUID を取得します.そして,TGPGraphics の Save 関数の引数に,この GUID の値を指定するだけです.
このサンプルでは,変換可能な画像形式全てに変換して保存し,再度読み込んで表示します.結果はフォームの Canvas に表示します.

描画コードは,このフォームの OnPaint イベント内に書いています.描画先を TImage.Canvas にした場合,GDI+ による描画ては AutoSize,Stretch,Transparent は機能しません.また,描画の Canvas をクリアすると,デフォルトの「白」で塗潰されます.Transparent が機能しませんから,画像の白の部分が透過状態になっているのかを確認できません.そこでフォームの Canvas に描画するようにしています.


[備考]
TBitmap のインスタンスを別に生成しておいて,GDI+ による描画をそのビットマップの Canvas に実行すればそのビットマップを保存できます.
VCL に実装されている JPEG, PNG, GIF 画像処理用の機能を使用すれば,ビットマップを各種の画像形式に変換して保存できます.


  • 図1
  • 実行開始時画面

  • 図2
  • メタファイル画像を他の画像形式に変換して保存
  • 保存した画像ファイルを再度表示した結果
  • 画像の背景は,アルファ値が 0 のため黒く描画されている,上は元の WMF 画像

  • 図3
  • ビットマップ画像を他の画像形式に変換して保存
  • 保存した画像ファイルを再度表示した結果.上は元のビットマップ画像

  • 図4
  • GIF 画像を他の画像形式に変換して保存
  • 保存した画像ファイルを再度表示した結果.上は元の GIF 画像

  • 図5
  • JPEG 画像を他の画像形式に変換して保存
  • 保存した画像ファイルを再度表示した結果.上は元の JPEG 画像

  • 図6
  • PNG 画像を他の画像形式に変換して保存
  • 保存した画像ファイルを再度表示した結果.上は元の PNG 画像

  • 図7
  • TIFF 画像を他の画像形式に変換して保存
  • 保存した画像ファイルを再度表示した結果.上は元の TIFF 画像

リスト1
TPGImage または TGPBitmap の Save メソッドを使用して画像を他の画像形式で保存
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, GDIPAPI, GDIPOBJ, GDIPUTIL, StdCtrls, ExtCtrls, ExtDlgs;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    OpenDialog1: TOpenDialog;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormPaint(Sender: TObject);
  private
    { Private 宣言 }
    FImageFilePath : string;
    FLoadFilePath  : string;
    FSaveFilePath  : string;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

const
  OpenFileFilter =
    '画像ファイル|*.png;*.jpg;*.gif;*.bmp;*.tif;*.emf;*.wmf;*.ico' +
    '|*.png|*.png' +
    '|*.jpg|*.jpg' +
    '|*.gif|*.gif' +
    '|*.bmp|*.bmp' +
    '|*.tif|*.tif' +
    '|*.emf|*.emf' +
    '|*.wmf|*.wmf' +
    '|*.ico|*.ico';

//=============================================================================
//  フォーム生成時の処理
//  画像ファイルの読み出しフォルダと,保存先のフォルダをデリミタ付きで設定
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Caption := 'GDI+  各種画像形式に変換して保存';

  FLoadFilePath := ExtractFilePath(ParamStr(0)) + 'OriginalImages';
  FLoadFilePath := IncludeTrailingPathDelimiter(FLoadFilePath);

  FSaveFilePath := ExtractFilePath(ParamStr(0)) + 'ChangedImages';
  FSaveFilePath := IncludeTrailingPathDelimiter(FSaveFilePath);
end;

//=============================================================================
//  画像ファイルを読み出して,各種形式で保存
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LGPBitmap     : TGPBitmap;
  LSaveFilePath : string;
  LFileName     : string;
  LImgGUID      : TGUID;
begin
  if OpenDialog1.InitialDir = '' then begin
    OpenDialog1.InitialDir := ExtractFileDir(FLoadFilePath);
  end;

  OpenDialog1.Filter := OpenFileFilter;
  if OpenDialog1.Execute then begin
    FImageFilePath := OpenDialog1.FileName;
    LGPBitmap      := TGPBitmap.Create(FImageFilePath);

    LFileName     := ExtractFileName(FImageFilePath);
    LSaveFilePath  := FSaveFilePath + LFileName;
    Label1.Caption := LFileName;
    Label2.Caption := '左から  .bmp,  .jpg,  .gif,   .png,  .tif ';

    //指定MIMEタイプのGUIDを求め,読み出したファイル名の拡張子を変更して保存
    //ビットマップ画像として保存
    if GetEncoderClsid('image/bmp', LImgGUID) >= 0 then begin
      LGPBitmap.Save(ChangeFileExt(LSaveFilePath, '.bmp'), LImgGUID);
    end;

    //JPEG画像として保存
    if GetEncoderClsid('image/jpeg', LImgGUID) >= 0 then begin
      LGPBitmap.Save(ChangeFileExt(LSaveFilePath, '.jpg'), LImgGUID);
    end;

    //GIF画像として保存
    if GetEncoderClsid('image/gif', LImgGUID) >= 0 then begin
      LGPBitmap.Save(ChangeFileExt(LSaveFilePath, '.gif'), LImgGUID);
    end;

    //PNG画像として保存
    if GetEncoderClsid('image/png', LImgGUID) >= 0 then begin
      LGPBitmap.Save(ChangeFileExt(LSaveFilePath, '.png'), LImgGUID);
    end;

    //TIFF画像として保存
    if GetEncoderClsid('image/tiff', LImgGUID) >= 0 then begin
      LGPBitmap.Save(ChangeFileExt(LSaveFilePath, '.tif'), LImgGUID);
    end;

    LGPBitmap.Free;
    Invalidate;
  end;
end;

//=============================================================================
//  フォームのOnPaintイベント
//  読み出した画像と,保存した画像を読み出して描画
//=============================================================================
//  GetImageEncodersSize
procedure TForm1.FormPaint(Sender: TObject);
var
  LLoadFilePath : string;
  LFileName     : string;
  LGPGraphic    : TGPGraphics;
  LGPImage      : TGPImage;
  LWidth        : Integer;
  LHeight       : Integer;
  LLeft         : Integer;
  LTop          : Integer;
begin
  if FImageFilePath = '' then exit;

  LFileName      := ExtractFileName(FImageFilePath);
  LLoadFilePath  := FSaveFilePath + LFileName;

  LWidth  := 110;
  LHeight := 110;
  LLeft   := 10;
  LTop    := 40;

  //変換元の画像ファイルからTGPImageを生成
  LGPImage   := TGPImage.Create(FImageFilePath);
  //描画先はこのCanvasとする
  LGPGraphic := TGPGraphics.Create(Canvas.Handle);

  //元の画像を描画
  LGPGraphic.DrawImage(LGPImage, MakeRect(LLeft, LTop, LWidth, LHeight));

  LGPImage.Free;
  LGPGraphic.Free;


  //表示位置を設定して...
  LLeft := 10;
  LTop  := 160;
  //画像の形式を変換して保存したファイルを読み出して表示
  //ビットマップ画像に変換した画像
  LGPImage   := TGPImage.Create(ChangeFileExt(LLoadFilePath, '.bmp'));
  LGPGraphic := TGPGraphics.Create(Canvas.Handle);
  LGPGraphic.DrawImage(LGPImage, MakeRect(LLeft, LTop, LWidth, LHeight));

  LGPImage.Free;
  LGPGraphic.Free;


  LLeft := LLeft + LWidth + 10;
  //JPEG画像に変換した画像
  LGPImage   := TGPImage.Create(ChangeFileExt(LLoadFilePath, '.jpg'));
  LGPGraphic := TGPGraphics.Create(Canvas.Handle);
  LGPGraphic.DrawImage(LGPImage, MakeRect(LLeft, LTop, LWidth, LHeight));

  LGPImage.Free;
  LGPGraphic.Free;


  LLeft := LLeft + LWidth + 10;
  //GIF画像に変換した画像
  LGPImage   := TGPImage.Create(ChangeFileExt(LLoadFilePath, '.gif'));
  LGPGraphic := TGPGraphics.Create(Canvas.Handle);
  LGPGraphic.DrawImage(LGPImage, MakeRect(LLeft, LTop, LWidth, LHeight));

  LGPImage.Free;
  LGPGraphic.Free;


  LLeft := LLeft + LWidth + 10;
  //PNG画像に変換した画像
  LGPImage   := TGPImage.Create(ChangeFileExt(LLoadFilePath, '.png'));
  LGPGraphic := TGPGraphics.Create(Canvas.Handle);
  LGPGraphic.DrawImage(LGPImage, MakeRect(LLeft, LTop, LWidth, LHeight));

  LGPImage.Free;
  LGPGraphic.Free;


  LLeft := LLeft + LWidth + 10;
  //TIFF画像に変換した画像
  LGPImage   := TGPImage.Create(ChangeFileExt(LLoadFilePath, '.tif'));
  LGPGraphic := TGPGraphics.Create(Canvas.Handle);
  LGPGraphic.DrawImage(LGPImage, MakeRect(LLeft, LTop, LWidth, LHeight));

  LGPImage.Free;
  LGPGraphic.Free;
end;

end.




02_GDI+ を使用したマルチページ TIFF 画像の作成と表示


マルチページ TIFF 画像は主にメタファイルや PDF ファイルを扱うことが多いようですが,ここでは各種画像を TIFF 画像ファイルに保存または読み出して TImage に表示します.JPEG 画像品質等,各種の設定が可能ですが,ここではデフォルトの設定で扱っています.デフォルトでの圧縮形式は LZW となるようです.

既存の TIFF 画像の場合,内部形式によっては読み出しに失敗することがあるようです.そのような場合は,参考リンクにある LibTiffDelphi というライブラリを使用すると読み込めるようですが,筆者は確認していません.

このサンプルでは,TIFF 画像を TImage に表示していますが,TIFF 画像を表示できるのは Delphi 2010 以降の TImage です.また,Windows Vista 以降,.NET Framework 3.0 以降の環境でないと TImage には表示できません.
Delphi 2010 よりも前のバージョン,あるいは,Windows XP 以前の環境でテストする場合は,これまでのサンプルのようにフォームまたは TPanel 等の Canvas に描画してください.



図8
設計時画面
図9
操作結果
  • [マルチ TIFF 作成] ボタンをクリック
  • [マルチ TIFF 表示] ボタンをクリック
  • これは最後の画像
    サンプルコードでは以下の画像を保存,表示する
    503.bmp
    ABC.bmp
    054709.gif
    agt_business.png

リスト2
マルチページ TIFF 画像の作成と表示
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, GDIPAPI, GDIPOBJ, GDIPUTIL;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Image1: TImage;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  Math;

{$R *.dfm}

//=============================================================================
//  マルチページTIFF画像の作成
//  ビットマップ,GIF,PNG画像をTIFFに変換して1つのファイルに格納
//  変換形式は何も設定していないのでデフォルトのまま
//
//  このコードは新規作成(上書き)保存としている  
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LSaveFilePath      : string;
  LEncoderParams     : TEncoderParameters;
  LEncoderParamValue : TEncoderValue;
  LclsidTIFF         : TGUID;
  LGPImage          : TGPImage;
  LGPImageTIFF      : TGPImage;
begin
  Button1.Enabled := False;
  Button2.Enabled := False;
  Sleep(100);
  Button2.Refresh;

  //保存ファイル名
  LSaveFilePath := ExtractFilePath(Application.ExeName) + 'MultiTest.tif';

  //ここではTIFFへのエンコードだけ指定
  LEncoderParams.Count := 1;
  LEncoderParams.Parameter[0].Guid           := EncoderSaveFlag;
  LEncoderParams.Parameter[0].Type_          := EncoderParameterValueTypeLong;
  LEncoderParams.Parameter[0].NumberOfValues := 1;
  LEncoderParams.Parameter[0].Value          := @LEncoderParamValue;
  //TIFFのGUIDを取得
  GetEncoderClsid('image/tiff', LclsidTIFF);

  //最初の画像をTGPImageに読み込みマルチ画像であることを指定して保存
  LGPImage := TGPImage.Create('503.bmp');
  LEncoderParamValue := EncoderValueMultiFrame;
  LGPImage.Save(LSaveFilePath, LclsidTIFF, @LEncoderParams);

  //2番目以降は別のTGPImageを生成して読み込み,それをSaveAddで追加保存する
  LGPImageTIFF := TGPImage.Create('ABC.bmp');
  try
    LEncoderParamValue := EncoderValueFrameDimensionPage;
    LGPImage.SaveAdd(LGPImageTIFF, @LEncoderParams);
  finally
    LGPImageTIFF.Free;
  end;

  LGPImageTIFF := TGPImage.Create('054709.gif');
  try
    LEncoderParamValue := EncoderValueFrameDimensionPage;
    LGPImage.SaveAdd(LGPImageTIFF, @LEncoderParams);
  finally
    LGPImageTIFF.Free;
  end;

  LGPImageTIFF := TGPImage.Create('agt_business.png');
  try
    LEncoderParamValue := EncoderValueFrameDimensionPage;
    LGPImage.SaveAdd(LGPImageTIFF, @LEncoderParams);
  finally
    LGPImageTIFF.Free;
  end;

  LGPImage.Free;

  Button1.Enabled := True;
  Button2.Enabled := True;
end;

//=============================================================================
//  マルチページTIFFの表示
//  指定時間間隔で各ページを表示
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LGPGraphic      : TGPGraphics;
  LGPImage        : TGPImage;
  LPageGuid       : TGUID;
  LPageCount      : Cardinal;
  LPageDimensions : TGPSizeF;
  i               : Integer;
begin
  Button1.Enabled := False;
  Sleep(100);
  Button1.Refresh;
  Button2.Enabled := False;

  LGPGraphic := TGPGraphics.Create(Image1.Canvas.Handle);

  //TGPImageを生成して画像を読み込み,ページ数を取得
  LGPImage   := TGPImage.Create('MultiTest.tif');
  LPageGuid  := FrameDimensionPage;
  LPageCount := LGPImage.GetFrameCount(LPageGuid);

  //順番に表示
  for i := 0 to LPageCount - 1 do begin
    LGPImage.SelectActiveFrame(LPageGuid, i);
    LGPImage.GetPhysicalDimension(LPageDimensions);
    //各ページの画像のサイズが必要なら,以下のコードで取得
    //Image1.Width  := Trunc(LPageDimensions.Width);
    //Image1.Height := Trunc(LPageDimensions.Height);

    //TImageのCanvasを現在の色で塗り潰す(画像のクリア)
    Image1.Canvas.FillRect(Image1.Canvas.ClipRect);
    //表示
    LGPGraphic.DrawImage(LGPImage, MakeRect(0, 0, Image1.Width, Image1.Height));
    //描画の更新
    Image1.Repaint;
    Sleep(1000);
  end;

  LGPGraphic.Free;
  LGPImage.Free;

  Button1.Enabled := True;
  Button2.Enabled := True;
end;

end.