お知らせ

電子会議

ライブラリ

パレット

Delphi FAQ検索

Delphi FAQ一覧

サンプル蔵





FDelphi FAQ
16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル

"256色スクリーンでのTrueColorBitmapセーブバグ回"







 以下のプログラムを256色スクリーンの元で試してみてください。
INPUT.BMPは24ビット(TrueColor)のビットマップです。

procedure TForm1.Button1Click(Sender: TObject);
var
    Bitmap1, Bitmap2: TBitmap;
begin
    Bitmap1 := TBitmap.Create;
    Bitmap1.LoadFromFile('INPUT.BMP');
    Bitmap2 := TBitmap.Create;
    Bitmap2.Assign(Bitmap1);
    Bitmap2.Handle;
    Bitmap2.SaveToFile('OUTPUT.BMP');


 どういう訳か、OUTPUT.BMPはINPUT.BMPよりも1024バイト大きくなって
おり、OUTPUT.BMPを市販の画像ソフト(Photoshop等)に読込ませると正常に
表示されません(D3.1、D4で確認)。

 Bitmap2.Handleの参照だけでなく、例えば Bitmap2.Height := 100; などと
して、Bitmap1と共有している内部データを別にするような操作をすると、こ
の現象がおきます。

 これは、TBitmapのバグによるものです。TBitmapは256色スクリーンの動
作下で、24ビットカラー(あるいは16ビット)のビットマップを読込むと、
それができるだけ奇麗に表示できるように、自動的にハーフトーンパレットと
いうものを作って自分の中に保持します。

 これはあくまで表示用なのでセーブ時(SaveToFile時)には、一緒にセーブし
てしまわないように内部的なフラグ(FHalfTone)をTrueにしておきます。とこ
ろが、内部データを他のBitmapと共有した場合、その共有が解かれるときに、
このフラグをコピーするのを忘れています。フラグをコピーせずに描画用パレ
ットはしっかりコピーしているので、上記のような妙な現象(ロードしたもの
とセーブするものが異なる)が起こってしまいます。

 このバグの回避方法は、以下のものが考えられます。

1. Graphicsユニットを修正して、FHalftoneフラグを一緒にコピーしてあげる。
   (FHalfToneはPrivateメンバなので外からはいじれません)

2. 同じくGraphicsユニットを修正して、ハーフトーンパレットを作らせない
   ようにする(奇麗な表示にはならないが、ハーフトーンパレットを作った
   ところでどーせ満足な表示ができる訳がない)。

3. SaveToFile/Streamの前にBitmap.Palette := 0としてパレットを破壊して
   おく(ただしパレットが必要なBitmapについてまで破壊しないように)。

 以下では2の修正方法を示します。GraphicsユニットのTBitmap.PaletteNeeded
を以下のようにします(D3.1, D4ともに全く同じです)。

procedure TBitmap.PaletteNeeded;
var
  DC: HDC;
begin
  with FImage do
  begin
    if FIgnorePalette or (FPalette <> 0) or (FDIBHandle = 0) then Exit;
    if FHandle = FDIBHandle then DeselectBitmap(FDIBHandle);
    FPalette := PaletteFromDIBColorTable(FDIBHandle, nil, 1 shl 
                                               FDIB.dsbmih.biBitCount);
    if FPalette <> 0 then Exit;
    {***** 削除ここから ******************
    DC := GDICheck(GetDC(0));
    FHalftone := FHalftone or
      ((GetDeviceCaps(DC, BITSPIXEL) * GetDeviceCaps(DC, PLANES)) <
      (FDIB.dsbm.bmBitsPixel * FDIB.dsbm.bmPlanes));
    if FHalftone then FPalette := CreateHalftonePalette(DC);
    ReleaseDC(0, DC);
    if FPalette = 0 then IgnorePalette := True;
    **************** 削除ここまで ********}
    IgnorePalette := True; //これを追加
  end;
end;

                             98/11/20(金) ytm PAF03212@niftyserve.or.jp

Original document by ytm             氏 ID:(PAF03212)


ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。

Copyright 1996-2002 Delphi Users' Forum