256色以下のビットマップをTBitmapで読み込み/保存を行うと、ビットマップが破損することがある
対象となるIDE製品
- Delphi/C++Builder/RAD Studio 10 Seattle以降
問題
256色以下のビットマップファイルをTBitmapで読み込んで、PixelFormatプロバティを32ビット(フルカラー)に変更し、ファイルを保存すると、ビットマップが破損することがあります。
ビットマップが破損する症状が再現するコード例は、以下の通りです。
procedure TForm1.Button1Click(Sender: TObject);
var
Bitmap : TBitmap;
begin
Bitmap := TBitmap.Create;
Bitmap.LoadFromFile('test.Bitmap'); // 256色のビッドマップを読み込む
Bitmap.PixelFormat := pf32bit; // フルカラーに変更
Bitmap.SaveToFile('test1.Bitmap');
Bitmap.LoadFromFile('test1.Bitmap');
Bitmap.SaveToFile('test2.Bitmap');
Bitmap.LoadFromFile('test2.Bitmap');
image1.Picture.Assign(Bitmap);
Bitmap.Free;
end;
解決
10 Seattle以降でVcl.GraphicsユニットのTBitmap.ReadDIBメソッドが変更されており、修正箇所に不具合があり、適切にカラーパレットが適用されません。
本件の回避策としては、主に2つの方法があります。
- 256色以下の元の画像ファイルを24ビット以上のビットマップへ変換する
- TBitmapで読み込むオリジナルの画像ファイル(256色以下)を、ペイントツールなどを利用して事前に24ビット以上のビットマップ形式に変換しておくと、同じ手順でTBitmapを利用して読み込み/保存を行ってもビットマップは破損しません。
- Vcl.GraphicsユニットのTBitmap.ReadDIBメソッドの実装コードを修正する
- Vcl.Graphics.pasのソースコードをエディタで開いて、以下の箇所を直接修正してください。
- <修正前>
procedure TBitmap.ReadDIB(Stream: TStream; ImageSize: LongWord; bmf: PBitmapFileHeader); .. .. if (bmiHeader.biBitCount > 8) and (bmiHeader.biBitCount <= 16) and (bmiHeader.biClrUsed > 0) and (Pal = 0)then ..
- <修正後>
procedure TBitmap.ReadDIB(Stream: TStream; ImageSize: LongWord; bmf: PBitmapFileHeader); .. .. if ((bmiHeader.biBitCount > 8) and (bmiHeader.biBitCount <= 16) or (bmiHeader.biBitCount = 32)) and (bmiHeader.biClrUsed > 0) and (Pal = 0)then ..
- 修正したVcl.Graphics.pasの適用方法は、以下のドキュメントを参照してください。
- <注意点>:2の方法でVcl.Graphicsのソースコードを修正した場合、その修正が反映されるのアプリケーションの実行時のみです。もしRAD Studio IDEのVCLフォームデザイナで設計時にビットマップの割り当てを行っている場合はこの修正は反映されませんので、ご注意ください。
本件の修正は、RAD Studio 11.1(11 Update1)を予定しております。