Unicodeファイル名に対応したTBitmap。
Delphi 6のTBitmapはUnicodeなファイル名の画像ファイルを読み込んだり書き込んだりできません。
書き込みに関してはUnicodeな文字が代替文字に変わったファイル名で保存することは出来ますが(Queensrÿche.bmpがQueensryche.bmpになるなど)WideStringからAnsiStringへ変換後にUnicodeな文字が'?'になるハングルなどは'?'がファイル名に使えない文字であるのでそのままではエラーになってしまいます。
読み込みに関してはUnicode非対応のコンポーネントにファイルを渡すでやったようにUnicodeなファイル名を短いファイル名に変換してしまうやり方もありますがもっとましなやり方で。
TBitmapのソースコードを追っていくとファイルとのやり取りは結局LoadFromStreamとSaveToStreamでやっていました。
ということでUnicode対応のTFileStreamを利用すればOKということになります。
interface
uses
Classes,
Graphics,
SysUtils,
Windows;
type
//Unicode対応TFileStream
TMyFileStream = class(THandleStream)
public
constructor Create(
FileName : WideString;
AccessMode : DWORD = GENERIC_READ;
ShareMode : DWORD = FILE_SHARE_READ or FILE_SHARE_WRITE
);
destructor Destroy; override;
end;
type
//Unicode対応TBitmap
TMyBitmap = class(TBitmap)
public
procedure LoadFromFile(const Filename : WideString); reintroduce;
procedure SaveToFile (const Filename : WideString); reintroduce;
end;
implementation
//------------------------------------------------------------------------------
{ TMyFileStream }
//Unicode対応TFileStream
constructor TMyFileStream.Create(
FileName : WideString;
AccessMode : DWORD = GENERIC_READ;
ShareMode : DWORD = FILE_SHARE_READ or FILE_SHARE_WRITE
);
var
li_CreateMode: DWORD;
begin
if ((AccessMode and GENERIC_WRITE) <> 0) then begin
li_CreateMode := OPEN_ALWAYS;
end else begin
li_CreateMode := OPEN_EXISTING;
end;
inherited Create(CreateFileW(
PWidechar(FileName), //ファイル名
AccessMode,
//アクセスモード
ShareMode,
//共有モード
nil, //セキュリティ
li_CreateMode, //作成方法
FILE_ATTRIBUTE_NORMAL, //ファイル属性
0
//テンプレート
));
end;
destructor TMyFileStream.Destroy;
begin
if (FHandle >= 0) then begin
CloseHandle(FHandle);
end;
inherited Destroy;
end;
//------------------------------------------------------------------------------
{ TMyBitmap }
//Unicode対応TBitmap
procedure TMyBitmap.LoadFromFile(const Filename : WideString);
//Unicode対応の読み込み。
var
l_Stream : TStream;
begin
l_Stream := TMyFileStream.Create(Filename);
try
LoadFromStream(l_Stream);
finally
l_Stream.Free;
end;
end;
procedure TMyBitmap.SaveToFile(const Filename : WideString);
//Unicode対応の書き込み。
var
l_Stream : TStream;
begin
l_Stream := TMyFileStream.Create(Filename, GENERIC_WRITE);
try
SaveToStream(l_Stream);
finally
l_Stream.Free;
end;
end;
TMyFileStreamはTFileStreamと引数の指定の仕方が違います。
それはTFileStreamと同じ指定の仕方だと実装がややこしくなるので実装が簡単なやり方にしているためです。
AccessModeとShareModeはCreateFile APIの指定そのままです。
AccessModeには読み込みか書き込みかあるいはその両方かをGENERIC_READとGENERIC_WRITEの組み合わせで指定します。
ShareModeには共有するモードをFILE_SHARE_READとFILE_SHARE_WRITEの組み合わせで指定します。
あとはUnicode対応のTMyFileStreamを介してファイルとのやり取りをすればOKです。
TMyBitmapのLoadFromFileとSaveToFileはTBitmapのそれと引数の型が違うのでoverrideではなくreintroduceをつけます。
このUnicode対応のTMyFileStreamを介してファイルとのやり取りをするやり方はTBitmapに限らずTFileStreamを利用する他のコンポーネントやクラスに応用できます。
使用例
const
F_sFileName =
WideString(WideChar($00C4)) //Ä
+ WideString(WideChar($00D5)) //Õ
+ WideString(WideChar($00DC)) //Ü
;
procedure TForm1.Button1Click(Sender: TObject);
var
l_Bitmap : TMyBitmap;
begin
l_Bitmap := TMyBitmap.Create;
try
l_Bitmap.LoadFromFile(F_sFileName + '.bmp');
Image1.Picture.Assign(l_Bitmap);
finally
l_Bitmap.Free;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
l_Bitmap : TMyBitmap;
begin
l_Bitmap := TMyBitmap.Create;
try
l_Bitmap.Assign(Image1.Picture);
l_Bitmap.SaveToFile(F_sFileName + '_save.bmp');
finally
l_Bitmap.Free;
end;
end;
適当にUnicodeな名前(この例では「ÄÕÜ.bmp」)のビットマップファイルを用意します。
Button1をクリックすると用意した「ÄÕÜ.bmp」を読み込んでImage1に表示します。
Button2をクリックするとImage1に表示している画像を「ÄÕÜ_save.bmp」として保存します。
2011-03-17: