Delphi Programming / Object Pascal
[掲載 2012年12月29日] [更新 2012年12月29日] GDI+ 関係サンプル |
GDI+ 関係サンプル
G140_表示中の画像ファイルの操作 |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE(UP1) Pro |
|
G140_GDIPlus_FileAccess.zip [3,125 KB] 2012年12月29日版 (EXE 同梱) |
表示中の画像ファイルの操作に関するサンプルです.
表示中の画像ファイルを削除した場合,あるいは削除できないようにしたい場合の参考です.実際にはこれらのサンプルのコードを組合せて使用することもあるかも知れません.
ネット上のコミュニティの場で,「GDI+ を使用すると,表示中の画像のファイルの削除や名前の変更等の編集ができなくなってしまいます」とか,逆に,「GDI+ を使用して画像を表示していても,その画像ファイルが削除できてしまいます」という記事をみかけました.
このページの記事は,これらに対する回答の意味もあります.
GDI+ に限らず,何かの動作をさせたい,という人がいれば,その動作をさせたくないという人もいるということです.どちらの機能も実装すると,利用者は,そのどちらかの動作仕様を選択することになります.そのアプリの設定項目が増えてしまいます.開発するアプリケーションの動作仕様の決定は難しいものです.
|
[備考]
「できなくなってしまいます」とか「できてしまいます」という表現は,主観的な表現です.科学技術関係では避けたい表現です.
一方,エンドユーザに対しては,製品や作品の特徴を表現する場合,「表示中の元の画像の削除や名前の変更等の操作も可能です」とか,「表示中の元の画像ファイルが変更されてしまうことはありません」等の肯定的な表現も使われます. |
01_画像ファイルの操作・削除可能 - 削除すると再描画で非表示 |
GDI+ 関係のサンプルプログラムは,一部を除いて,多くの場合,この描画コードとなっています.
それは,画像を表示するコントロールの OnPaint イベントあるいは,Paint メソッド内で,画像ファイルを読み込み,そのコントロールの Canvas に描画するものです.
この方法は,他のアプリでも,この画像ファイルを読み込んで表示でき,変更があった場合,再描画すればその変更結果が反映されます.したがって,削除という変更があった場合,描画すべき元の画像がなくなってしまうのですから,再描画すると画像は表示しないことになります. |
|
図1
画像ファイルを表示 |
|
図2
画像ファイルを削除して [再描画]
- 何も表示しなくなる
- [ファイルの削除] という変更結果が反映されたことになる
|
リスト1
表示中の画像ファイルを削除できるが,再描画しても画像が表示されない
他のアプリで変更があると,再描画で変更が反映される |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ComCtrls, StdCtrls, GDIPOBJ, GDIPAPI, GDIPUTIL, ExtDlgs;
type
TMyPanel = class(TCustomPanel)
private
FImageFilePath : String;
procedure SetImageFilePath(const Value: String);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
property ImageFilePath : String read FImageFilePath write SetImageFilePath;
end;
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
OpenPictureDialog1: TOpenPictureDialog;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
protected
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
JPEG,
GifImg,
pngimage;
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Self.Caption := 'GDI+ 画像ファイル削除可能';
//TMyPanelを生成して配置
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
Left := 5;
Top := 35;
Width := Self.ClientWidth - 10;
Height := Self.ClientHeight - Top - 5;
Anchors := [akLeft, akTop, akRight, akBottom];
Color := clWhite;
BevelOuter := bvNone;
ParentBackground := False;
DoubleBuffered := True;
end;
end;
//=============================================================================
// [画像ファイル]ボタン
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
if OpenPictureDialog1.InitialDir = '' then begin
OpenPictureDialog1.InitialDir := ExtractFileDir(ParamStr(0));
end;
OpenPictureDialog1.Filter := '画像ファイル|*.png;*.jpg;*.jpeg;*.bmp;*.gif';
if OpenPictureDialog1.Execute then begin
OpenPictureDialog1.InitialDir := ExtractFileDir(MyPanel.ImageFilePath);
MyPanel.ImageFilePath := OpenPictureDialog1.FileName;
end;
end;
//=============================================================================
// [再描画]ボタン
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
if Assigned(MyPanel) then MyPanel.Invalidate;
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// コンストラクタ
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
FImageFilePath := '';
end;
//-----------------------------------------------------------------------------
// ImageFilePathプロパティの設定メソッド
// 表示する画像ファイルを指定する
//-----------------------------------------------------------------------------
procedure TMyPanel.SetImageFilePath(const Value: String);
begin
if not FileExists(Value) then exit;
FImageFilePath := Value;
Invalidate;
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LGPImage : TGPImage;
LGPGraphic : TGPGraphics;
begin
inherited;
if FImageFilePath = '' then exit;
LGPImage := TGPImage.Create(FImageFilePath);
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
LGPGraphic.DrawImage(LGPImage, 0, 0, LGPImage.GetWidth, LGPImage.GetHeight);
LGPImage.Free;
LGPGraphic.Free;
end;
end.
表示中の画像ファイルに対して,削除も含めた変更を禁止する場合です.
この場合は,画像ファイルを読み込んで生成した TGPImage または TGPBitmap のインスタンスをグローバル変数にして,アプリ終了まで保持しておきます.そうすると,他のアプリから,この画像ファイルを変更することはできなくなります. |
|
図3
削除できない |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ComCtrls, StdCtrls, GDIPOBJ, GDIPAPI, GDIPUTIL, ExtDlgs;
type
TMyPanel = class(TCustomPanel)
private
FGDPImage : TGPImage;
FImageFilePath : String;
procedure SetImageFilePath(const Value: String);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property ImageFilePath : String read FImageFilePath write SetImageFilePath;
end;
TForm1 = class(TForm)
Button1: TButton;
OpenPictureDialog1: TOpenPictureDialog;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
protected
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
JPEG,
GifImg,
pngimage;
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Self.Caption := 'GDI+ 画像ファイル削除不可';
//TMyPanelを生成して配置
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
Left := 5;
Top := 35;
Width := Self.ClientWidth - 10;
Height := Self.ClientHeight - Top - 5;
Anchors := [akLeft, akTop, akRight, akBottom];
Color := clWhite;
BevelOuter := bvNone;
ParentBackground := False;
DoubleBuffered := True;
end;
end;
//=============================================================================
// [画像ファイル]ボタン
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
if OpenPictureDialog1.InitialDir = '' then begin
OpenPictureDialog1.InitialDir := ExtractFileDir(ParamStr(0));
end;
OpenPictureDialog1.Filter := '画像ファイル|*.png;*.jpg;*.jpeg;*.bmp;*.gif';
if OpenPictureDialog1.Execute then begin
OpenPictureDialog1.InitialDir := ExtractFileDir(MyPanel.ImageFilePath);
MyPanel.ImageFilePath := OpenPictureDialog1.FileName;
end;
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// コンストラクタ
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
FGDPImage := nil;
FImageFilePath := '';
end;
//-----------------------------------------------------------------------------
// デストラクタ
//-----------------------------------------------------------------------------
destructor TMyPanel.Destroy;
begin
if Assigned(FGDPImage) then FreeAndNil(FGDPImage);
inherited;
end;
//-----------------------------------------------------------------------------
// ImageFilePathプロパティの設定メソッド
// 画像ファイルを読み出して,FGPImageのインスタンスを生成
//-----------------------------------------------------------------------------
procedure TMyPanel.SetImageFilePath(const Value: String);
begin
if not FileExists(Value) then exit;
FImageFilePath := Value;
if Assigned(FGDPImage) then FreeAndNil(FGDPImage);
FGDPImage := TGPImage.Create(FImageFilePath);
Invalidate;
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LGPGraphic : TGPGraphics;
begin
inherited;
if not Assigned(FGDPImage) then exit;
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
LGPGraphic.DrawImage(FGDPImage, 0, 0, FGDPImage.GetWidth, FGDPImage.GetHeight);
LGPGraphic.Free;
end;
end.
03_画像ファイルの削除も変更も可能にする - TMemoryStream |
表示中の画像ファイルに対して,削除を含めた変更を可能にする場合です.
対象の画像ファイルが削除されても,その画像を表示するには,その画像の内容がメモリ上になければなりません.このサンプルでは TMemoryStream を生成して格納します.当然ですが,このメモリ上の操作は,他のアプリからはできません.したがって,他のアプリでの変更は反映されません.
筆者の環境では,このメモリストリームに格納するサンプルは,画像の種類によっては,メモリストリームから読み出す際に例外が発生することがありました. |
リスト3
表示中の画像ファイルの削除も変更も可能だが,変更の結果は反映されない |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ComCtrls, StdCtrls, GDIPOBJ, GDIPAPI, GDIPUTIL, ExtDlgs;
type
TMyPanel = class(TCustomPanel)
private
FImageStream : TMemoryStream;
FImageFilePath : String;
procedure SetImageFilePath(const Value: String);
protected
procedure Paint; override;
procedure SetParent(AParent: TWinControl); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property ImageFilePath : String read FImageFilePath write SetImageFilePath;
end;
TForm1 = class(TForm)
Button1: TButton;
OpenPictureDialog1: TOpenPictureDialog;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
protected
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
JPEG,
GifImg,
pngimage;
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Self.Caption := 'GDI+ 画像ファイルの操作可能';
//TMyPanelを生成して配置
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
Left := 5;
Top := 35;
Width := Self.ClientWidth - 10;
Height := Self.ClientHeight - Top - 5;
Anchors := [akLeft, akTop, akRight, akBottom];
Color := clWhite;
BevelOuter := bvNone;
ParentBackground := False;
DoubleBuffered := True;
end;
end;
//=============================================================================
// [画像ファイル]ボタン
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
if OpenPictureDialog1.InitialDir = '' then begin
OpenPictureDialog1.InitialDir := ExtractFileDir(ParamStr(0));
end;
OpenPictureDialog1.Filter := '画像ファイル|*.png;*.jpg;*.jpeg;*.bmp;*.gif';
if OpenPictureDialog1.Execute then begin
OpenPictureDialog1.InitialDir := ExtractFileDir(MyPanel.ImageFilePath);
MyPanel.ImageFilePath := OpenPictureDialog1.FileName;
end;
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// コンストラクタ
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
FImageStream := TMemoryStream.Create;
FImageFilePath := '';
end;
//-----------------------------------------------------------------------------
// デストラクタ
//-----------------------------------------------------------------------------
destructor TMyPanel.Destroy;
begin
FreeAndNil(FImageStream);
inherited;
end;
//-----------------------------------------------------------------------------
// SetParentメソッド処理
//-----------------------------------------------------------------------------
procedure TMyPanel.SetParent(AParent: TWinControl);
begin
inherited;
if not Assigned(AParent) then exit;
end;
//-----------------------------------------------------------------------------
// ImageFilePathプロパティの設定メソッド
// 画像ファイルを読み出して,メモリストリームに格納
//-----------------------------------------------------------------------------
procedure TMyPanel.SetImageFilePath(const Value: String);
begin
if not FileExists(Value) then exit;
FImageFilePath := Value;
FImageStream.Clear;
FImageStream.LoadFromFile(FImageFilePath);
//再描画
Invalidate;
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//
// 画像ファイルによっては例外が発生する場合あり
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LGPImage : TGPImage;
LGPGraphic : TGPGraphics;
begin
inherited;
if FImageStream.Size = 0 then exit;
//メモリストリームから読み出してTGPImageを生成
LGPImage := TGPImage.Create(TStreamAdapter.Create(FImageStream, soReference));
//TMyPanelのCanvasに描画
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
LGPGraphic.DrawImage(LGPImage, 0, 0);
LGPGraphic.Free;
LGPImage.Free;
end;
end.
04_画像ファイルの削除も変更も可能にする - TBitmap.Handle |
これも,表示中の画像ファイルに対して,削除を含めた変更を可能にする場合です.
このサンプルでは TBitmap に画像を格納し,描画の際,このビットマップのハンドルから TGPBitmap のインスタンスを生成して描画します.
こちらの方が,動作が確実なようです. |
リスト4
表示中の画像ファイルの削除も変更も可能だが,変更の結果は反映されない |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ComCtrls, StdCtrls, GDIPOBJ, GDIPAPI, GDIPUTIL, ExtDlgs;
type
TMyPanel = class(TCustomPanel)
private
FImageBitmap : TBitmap;
FImageFilePath : String;
procedure SetImageFilePath(const Value: String);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property ImageFilePath : String read FImageFilePath write SetImageFilePath;
end;
TForm1 = class(TForm)
Button1: TButton;
OpenPictureDialog1: TOpenPictureDialog;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
protected
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
JPEG,
GifImg,
pngimage;
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Self.Caption := 'GDI+ 画像ファイルの操作可能';
//TMyPanelを生成して配置
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
Left := 5;
Top := 35;
Width := Self.ClientWidth - 10;
Height := Self.ClientHeight - Top - 5;
Anchors := [akLeft, akTop, akRight, akBottom];
Color := clWhite;
BevelOuter := bvNone;
ParentBackground := False;
DoubleBuffered := True;
end;
end;
//=============================================================================
// [画像ファイル]ボタン
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
if OpenPictureDialog1.InitialDir = '' then begin
OpenPictureDialog1.InitialDir := ExtractFileDir(ParamStr(0));
end;
OpenPictureDialog1.Filter := '画像ファイル|*.png;*.jpg;*.jpeg;*.bmp;*.gif';
if OpenPictureDialog1.Execute then begin
OpenPictureDialog1.InitialDir := ExtractFileDir(MyPanel.ImageFilePath);
MyPanel.ImageFilePath := OpenPictureDialog1.FileName;
end;
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// コンストラクタ
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
FImageBitmap := TBitmap.Create;
FImageFilePath := '';
end;
//-----------------------------------------------------------------------------
// デストラクタ
//-----------------------------------------------------------------------------
destructor TMyPanel.Destroy;
begin
FreeAndNil(FImageBitmap);
inherited;
end;
//-----------------------------------------------------------------------------
// ImageFilePathプロパティの設定メソッド
// 画像ファイルを読み出して,TGPBitmapを生成
// ビットマップを生成し,そのCanvasにTGPBitmapに格納した内容を描画
//-----------------------------------------------------------------------------
procedure TMyPanel.SetImageFilePath(const Value: String);
var
LObjWidht : Integer;
LObjHeight : Integer;
LGPImage : TGPBitmap;
LGPGraphic : TGPGraphics;
begin
if not FileExists(Value) then exit;
FImageFilePath := Value;
LGPImage := TGPBitmap.Create(FImageFilePath);
try
LObjWidht := LGPImage.GetWidth;
LObjHeight := LGPImage.GetHeight;
FImageBitmap.Assign(nil);
FImageBitmap.SetSize(LObjWidht, LObjHeight);
LGPGraphic := TGPGraphics.Create(FImageBitmap.Canvas.Handle);
try
LGPGraphic.DrawImage(LGPImage, MakeRect(0, 0, LObjWidht, LObjHeight));
Invalidate;
finally
LGPGraphic.Free;
end;
finally
LGPImage.Free;
end;
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LGPImage : TGPBitmap;
LGPGraphic : TGPGraphics;
begin
inherited;
//ビットマップのハンドルからTGPImageを生成
LGPImage := TGPBitmap.Create(FImageBitmap.Handle, FImageBitmap.Palette);
//TMyPanelのCanvasに描画
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
LGPGraphic.DrawImage(LGPImage, 0, 0);
LGPImage.Free;
LGPGraphic.Free;
end;
end.
|