TOPページへ戻る  PCページへ戻る  一覧へ戻る

透過GIFのWin64でのバグ(Delphi XE2 update4 + Windows7 64bit)

私の環境では、platformがWin64、透過色に標準色(clWhiteやclRedなど)を指定すると透過GIFの作成方法で示したコードでは透過GIFになりませんでした。正確には、Windows7やFireFoxで透過GIFとして扱ってもらえませんでした(フォトレタッチソフトJTrimでは透過GIFとして表示されました)。これは、TGIFGraphicControlExtensionをCreateする前にTGIFImage.OptimizeColorMapを追記することで正常な透過GIFになります。


 USES ・・・, Vcl.ExtCtrls, Vcl.Imaging.GIFImg;

 type
   TForm1 = class(TForm)
     OpenDialog1: TOpenDialog;
     Image1: TImage;
   private
              ・
             ・
             ・
 procedure TForm1.ReadAndSaveTransGif;
 var GIFImage : TGIFImage;
     GCE : TGIFGraphicControlExtension;
 begin
 Image1.Picture.LoadFromFile(イメージファイルのパス);
 GIFImage := TGIFImage.Create;
 try
 GIFImage.Assign(Image1.Picture.Graphic);
 GIFImage.OptimizeColorMap;	// GIFフレームのカラーマップの最適化
 GCE := TGIFGraphicControlExtension.Create(GIFImage.Images[0]);
 GCE.Transparent := True;
 GCE.TransparentColor := GIFImage.Bitmap.Canvas.Pixels[0,GIFImage.Bitmap.Height-1];
 GIFImage.SaveToFile(GIFファイルのパス);
 finally
     FreeAndNil(GIFImage);
   end;
 end;

まだ完全に原因をつかめていませんが、上記で解決する理由は次のとおりです。

透過色を設定する際にTGIFGraphicControlExtension.TransparentColorに値を代入すると、内部では代入した値に相当するカラーマップのインデックスをTGIFColorMap.AddUnique関数で検索し、そのインデックスをTransparentColorIndexプロパティに設定します。また、platformがWin64の時、GIFImage.Images[0]フレームのカラーマップに標準色が重複して登録されます。さらに、デフォルト状態ではカラーマップが整列しておらず(OptimizedプロパティがFalse)、この場合、、TGIFColorMap.AddUnique関数のIndexOf関数でインデックスが大きい方から透過色と同じ色を探します。そのため、より若いインデックスに透過色があっても、大きい方のインデックスをTransparentColorIndexに保持してしまいます。どうもこの状態ではWindows7などで透過GIFと認識されないようです。TGIFImage.OptimizeColorMap手続きを実行すると、カラーマップ内で重複する色をマージして整列します。これにより正常な透過GIFと認識されるようです。

上のコードでは、TGIFImageのOptimizeColorMap手続きを呼んでいますが、TGIFImage.Optimize手続きでも同様に機能します。その際、第1引数(Options)にooMergeを指定する必要があります。他に似た手続きにTGIFColorMap.Optimizeがありますが、透過GIFにならないことがありました。

OptimizeColorMap手続きは内部で色のマージや並べ替えなど比較的多くの処理をします。それを避けたいならば、カラーマップが重複し、且つOptimizedプロパティがFalseでも最も若いインデックスをTransparentColorIndexに設定するようにしても解決します。そのためには、以下のような自前でカラーマップを検索する関数を用意すればよいでしょう。


 USES ・・・, Vcl.ExtCtrls, Vcl.Imaging.GIFImg;

 type
   TForm1 = class(TForm)
     OpenDialog1: TOpenDialog;
     Image1: TImage;
   private
     function TransColorIndexOf(TransparentCol:TColor; GIFMapCol:TGIFColorMap):Integer;
              ・
             ・
             ・
 function TForm1.TransColorIndexOf(TransparentCol:TColor; GIFMapCol:TGIFColorMap):Integer;
 begin
 Result := 0;
 while Result < GIFMapCol.Count do
     begin
     if TransparentCol = GIFMapCol[Result] then
         break;
     Inc(Result);
     end;
 end;
 
 procedure TForm1.ReadAndSaveTransGif;
 var GIFImage : TGIFImage;
     GCE : TGIFGraphicControlExtension;
     Index: Integer;
 begin
 Image1.Picture.LoadFromFile(イメージファイルのパス);
 GIFImage := TGIFImage.Create;
 try
 GIFImage.Assign(Image1.Picture.Graphic);
 GCE := TGIFGraphicControlExtension.Create(GIFImage.Images[0]);
 GCE.Transparent := True;
 Index := TransColorIndexOf(GIFImage.Bitmap.Canvas.Pixels[0,GIFImage.Bitmap.Height-1],
                            GIFImage.Images[0].ColorMap);
 if Index < GIFImage.Images[0].ColorMap.Count then
     GCE.TransparentColorIndex := Index
 else 
     GIFImage.Images[0].Add(GIFImage.Bitmap.Canvas.Pixels[0,GIFImage.Bitmap.Height-1]);   // Indexが見つからない場合の処理
 GIFImage.SaveToFile(GIFファイルのパス);
 finally
     FreeAndNil(GIFImage);
   end;
 end;

上のコードではIndex変数に一度透過色のインデックスを保存し、もし透過色がカラーマップに見つかれない場合はカラーマップに透過色を追加しています。これはTGIFColorMap.AddUnique関数と同等の処理です。

TOPページへ戻る  PCページへ戻る  一覧へ戻る