imageでgifを読み込もうとしたところ、JPGやBMPは読み込めるのですが、GIFは読み込むことが出来ませんでした。で、私なりに色々調べてみた結果、どうやら
http://www.melander.dk/
にgifを読み込むことが出来るようになるコンポーネントが存在していることがわかりました。しかし、残念なことにリンク切れしていました。どなたかこのコンポーネントの存在するページ、または他の方法でgif画像を読み込む方法を、知っていらっしゃるかたがいれば教えて欲しいです。おそらく超初歩的な質問をしていると思いますが、よろしくお願いします。
Halbow です。
gif 画像をプログラムで扱うのは Unisys の特許に触れる可能性があるので一種の
タブーになっているようです。この特許に関しては、WEB 上で検索するとたくさん
見つかることでしょう。それで、この特許が主張される以前は、gif 画像を扱う
ライブラリやコンポーネントがたくさんありました。それがなくなってしまい、
Susie のプラグインもなくなり、Delphi から使える最後のライブラリが
Melander 氏のものだったのですが、1年くらい前になくなってしまいました。
わたしは、彼のライブラリを持っています。コンパイラからみてパスのとおった
ところにこれを置くと、uses に加えるだけで、TJpegImage と同じようにして
gif 画像を扱うことができます。しかし、特許の問題や作者に無断で再配布する
ことは残念ですができません。
GIFの特許は、あと数ヶ月持つそうですので、Halbowさんの言うとおり、使えません。
ただ、読み込みだけなら、Susieプラグインを使えば可能です。
Susieプラグインの、LZ-Rを手に入れ、Delphi用のTSPIなどのコンポーネントをインストールすれば、
TPictureでも、Gifイメージが扱えるようになります。
(TSPIコンポーネントを設置すると、LZ-Rが読み込まれて、TPictureが、Gifイメージを扱えるようになる、ただし、TSPIが生成されている間だけ)
ただ、TSPIBitmapという形式なので、TBitmapを使うなりして、TBitmapに
変換するといいでしょう。
サンプルとしては、わたしのYahooブリーフケースにおいてある( http://briefcase.yahoo.co.jp/takamichie/ )、Delphiコンポーネントエディタの、TPictureコンポーネントエディタにそういうコードがあるので、ご覧ください。
(入って、共有ドキュメント>コンポーネント>Delphiコンポーネントエディタ)
未完成ということになってますけど、TPictureエディタには今のところバグは見つかってません。
何か誤解がおこりそうかもしれないので追記します。
Unisysが特許を持ってるのは、Gif画像の"圧縮方法"です。(とほほのWWW入門、アラカルト参照)
LZ-Rは、Gif画像を別の方法で展開します。
なので、特許には引っかかりません(そのぶん展開速度は遅いですが、気になるほどではないかと)
Halbowさんのおっしゃっているのは、おそらくその前にあったらしい、IfGifというプラインのことだと思います。
さて、わたしの言ったコンポーネントエディタについてですが、
TSPIコンポーネントを、ライブラリパスの通ったところにおき(インストールはしてなくてもいいです)、
Susieをインストールしたフォルダか、コンポーネントエディタの生成場所(Bplファイルが出来る場所?)に、使いたいプラグインをおいてください。
ただの学生はん、調べ方足りんは超初心者やな。
>残念なことにリンク切れしていました。
TGifImageで検索せーな。ごっつエエもん落ちとるで。
本家のTGifImageはDelphi5までの対応みたいやけども、探せばDelphi7対応版まであるやんけ。
けどリスクは自分で負わなアカンで〜(‾〜‾)
procedure TForm1.Button1Click(Sender: TObject);
var
Gif: TGifImage;
begin
Gif := TGifImage.Create;
try
Gif.LoadFromFile('じふ饅.gif');
Image1.Picture.Bitmap.Assign(Gif);
finally
Gif.Free;
end;
end;
たかみちえさんのYahooブリーフケースのURLリンク、お尻に?が付いとるンはご愛嬌(^^ゞ
GIFのLZW圧縮ファイルについては非LZW圧縮・展開法は可能です。
それはLZWの特許要件である辞書が
展開後の本体と全く同一であるところに起因します。
LZWより高速になると思うので特許切れは近いですが
あえて今「非LZW・LZW互換」で行くのもよいのではないかと思います。
しかしそれより安易で海外でも定着している方法として
OLELoadPictureを使う方法があります。
少なくともこの方法を使っているサイトは数年前からあり
アメリカなどでもUNYSYSと正非は別としても法廷論争も存在しないようです。
要はWindowsの価格に含まれているということです。
海外ではこれがGIF表示の常道になっているようですが日本では
あまり知られていないようです
XPだと別のAPIもあるそうですが
このAPIでWMF、GIF、JPEG、BMPが展開できるので
単に画像をロードする場合IJGなどの100kbyte強のオーバーヘッドをさけることができます。
関連した関数としてOLEloadpictureFileもあります。
基本的にOleLoadpictureとTbitmapあたりの組み合わせがお勧めです。
コードは短くてすみますがgroballockとかインターフェース型(Istream,Ipicture)など使ったことのない人は
ちょっと面食らうかもしれません。
あとサイズ指定時Ipictureの返すサイズの単位はドットでないのも注意が必要です。
iPicture.getheight(height);
height1:=Multidiv(height,getdevicecaps(GetDC(0),LOGPIXELSY),2540));
みたいな感じ
ActiveXをインクルードしますが
IIDなど自前で書かないといけないようです。
使うのはOleauto.dllなのですが以前はdelphiの宣言文が違っていたので苦労した覚えがあります。
詳細はOLEPictureを探索すればでてくると思います。
delphiの場合Ipicture.renderでTbitmapDCなどを渡して描画します。
GIFの場合透明処理はしてくれるのですが
その後透明色が何かわからなくなっちゃうので
フォーマット分析しない場合は
事前に絶対に使っていない色でぬり潰してから24bitモードにして
その色をTbitmapの透明色にするなどするとうまく使えます。
この方法はWMFのBMP化にも使いやすいので重宝します。
以前フォーマットの解析部に既存のルーチンを使い
レンダー部だけこちらを使う方法を取っているサイトを海外で見たことがあります。
この関数で透明色を換算する二度塗り法にについて丹念に解説しているサイトを見たことがありますが
素直にファイルを解析して存在しない色を使うか透明色で塗りつぶすほうが速いです。
あともう一つMCIでも現状GIFとJPEGには対応しているので
アニメーションGIFの表示だけしたい場合はこちらを使うのも手です。
詳しく知りたい人はとにかくGoogleなどで「OleloadPicture」で探索することでは無いかと思います。
早速みなさんのレスをもとに問題解決を図りたいのですが、少々わたし別件で忙しくなってきたので、別件が片付き次第、また書き込みます。ほんとすいません!絶対書き込みますので。
Webにdelphi用のサンプルコードが無かったのでここに書きます。
このまんま使って使えると思います。
//
unit OlePictures;
interface
uses
Windows,SysUtils,Classes,Graphics,ActiveX;
type
TOleBITMAP = Class(TBitmap)
Public
Procedure Loadfromstream (Stream: TStream);override;
end;
//
function GetPicturetype(const header,header2:Longword):byte;
function LoadOlepicfile(var Picture:Tbitmap;const filename:string):byte;
function LoadOlepicStream(var Picture:Tbitmap; strm:Tstream):byte;
const
G_BMP = $21;
G_EMF = $22;
G_WMF = $23;
G_ICO = $24;
G_CUR = $25;
G_ANI = $26;
G_JFIF = $11;
G_EXIF = $12;
G_GIF = $13;
G_TGA = $31;
G_SVG = $32;
G_SWF = $33;
CMP_ZLB = $0000DA78;//zlib and$0000FFFF $51
WIN_BMP = $00004D42;//bmp and$0000FFFF $21
WIN_EMF = $00000001;//EMF?? $22
WIN_EMF2 = $464D4520;//EMF OFF $28
WIN_WMF = $9AC6CDD7;//WMF $23
WIN_RIFF = $46464952;//ANI $26
OLE_JFIF = $E0FFD8FF;//JFIF $11
OLE_EXIF = $E1FFD8FF;//EXIF $12
OLE_GIF = $38464947;//GIF8 $13
WIN_ICO = $00010000;//ICO $24
// WIN_CUR = $00020000;//CUR $25
WIN_RES = $20200001 ;//CUR,ico $25
GRA_TGAP = $00010100;//tga PALLET $31
GRA_TGA = $00020000;//tga RGB $31
GRA_TGAM = $00030000;//tga MONO $31
GRA_SVG = $6776733C;//SVG text $32
GRA_SWF = $00535746;//SWF and $00FFFFFF $33
implementation
Procedure TOleBitmap.loadfromstream(Stream: TStream);
begin
LoadOlepicStream(Tbitmap(self),stream);
end;
function GetPicturetype(const header,header2:Longword):byte;
begin
result:=0;
case header of
OLE_JFIF:result:=$11;
OLE_EXIF:result:=$12;
OLE_GIF :result:=$13;
WIN_ICO :result:=G_ICO;//EMF??
WIN_EMF :result:=G_EMF;//EMF??
WIN_WMF : result:=$23;//WMF
WIN_RIFF : result:=$26;//ANI
GRA_TGA :
if header2 = WIN_RES then result:= G_CUR else result:=G_TGA;
GRA_TGAP : result:=G_TGA;//tga
GRA_TGAM : result:=G_TGA;//tga
GRA_SVG : result:=$32;//SVG text $32
else
if (header and $00FFFFFF) = GRA_SWF then result:= $33;
if (header and $0000FFFF) = WIN_BMP then result:= $21;
if (header and $0000FFFF) = CMP_ZLB then result:= $51;
end;
end;
const
IID_IPICTURE:TGUID ='{7BF80980-BF32-101A-8BBB-00AA00300CAB}';
function LoadOlepicStream(var Picture:Tbitmap; strm:Tstream):byte;
var
hr:hresult;
iPicture1:IPicture;//Disp;
istream1:IStream;
//
nFileSize,pheader,pheader2:Longword;
hGlobal:Thandle;
lWidth,lHeight,FWidth,FHeight:integer;
pdata:Pointer;
rc:Trect;
flg:smallint;
ptype:byte;
begin
result:=0;
if strm.Read(pheader,4) <4 then exit;
if strm.Read(pheader2,4) <4 then exit;
strm.Seek(0,soFromBeginning);
ptype:=GetPicturetype(pheader,Pheader2);
// if ((ptype <$11) or (ptype > $13)) then Exit;
if ptype in [G_BMP,G_CUR,G_ICO,G_EMF,G_WMF ]then
picture.PixelFormat:=pf24bit else
if ((ptype <G_JFIF) or (ptype > G_GIF)) then Exit;
if not (picture.PixelFormat in [pf1bit,pf24bit,pf32bit])
then picture.PixelFormat:=pf24bit;
nFileSize:=strm.Size;
hGlobal := GlobalAlloc(GMEM_MOVEABLE, nFileSize);
try
pData := GlobalLock(hGlobal);
strm.ReadBuffer(pdata^,nFileSize);
GlobalUnlock(hGlobal);
iStream1:=nil;
HR:= CreateStreamOnHGlobal(hGlobal, TRUE, iStream1);
IF hr <> s_ok THEN EXIT;
HR := OleLoadPicture(istream1, nFileSize, FALSE, IID_IPICTURE,iPicture1);
IF hr <> s_ok THEN EXIT;
iPicture1.get_Width(lWidth);
iPicture1.get_Height(lHeight);
FWidth:= MulDiv(lWidth, GetDeviceCaps(GetDC(0), LOGPIXELSX), 2540);
FHeight:=MulDiv(lHeight, GetDeviceCaps(GetDC(0), LOGPIXELSY), 2540);
Picture.Width:= FWidth;
Picture.Height:=FHeight;
rc.Top:=0;
rc.Left:=0;
rc.Bottom:=Picture.Height;
rc.Right:=Picture.Width;
if ptype in[G_CUR,G_ICO,G_GIF,G_WMF,G_EMF] then begin
if (Picture.TransparentColor and $00FFFFFF) =$FFFFFF then Picture.TransparentColor:=$FD017F;
Picture.Canvas.Brush.Color:=Picture.TransparentColor;//
Picture.Canvas.Brush.Style:=bssolid;
Picture.Canvas.FillRect(rc);
Picture.Transparent:=true;
end;
Ipicture1.get_Type(flg);
ptype:=byte(flg);
iPicture1.Render(
Picture.Canvas.Handle,0,0,Picture.Width,Picture.Height,
0, lHeight, lWidth, -lHeight, rc);
result:=ptype;
finally
GlobalFree(hGlobal);
end;
end;
function LoadOlepicfile(var Picture:Tbitmap;const filename:string):byte;
var
Fs:Tfilestream;
begin
Fs := TFileStream.Create(FileName, fmOpenRead);
try
result:=LoadOlePicStream(Picture,Fs);
finally
Fs.Free;
end;
end;
initialization
TPicture.RegisterFileFormat('gif','compuserve graphic',TOleBitmap);
TPicture.RegisterFileFormat('jpg','jpeg',TOleBitmap);
end.
このユニットでJPEGを使わない場合はJPEGの部分をコメントアウトすればよいです。
TOLEBitmapを使わない場合はinitialization以降をコメントアウトすればよいです。
他にもWMF,curなども登録すればOpenPictureDialogでも使えます。
透明色処理は適当ですが結構うまく動きます。
テストフォーム
unit test11;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,OlePictures, ExtDlgs, ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
Bt1: TButton;
Im1: TImage;
OPD1: TOpenPictureDialog;
procedure Bt1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Bt1Click(Sender: TObject);
begin
if OPD1.Execute then
begin
Im1.Picture.LoadFromFile(OPD1.FileName);
end;
end;
end.
適当にOpenPictureDialogとTimage、Buttonをフォームに貼り付けて
名称をOPD1,Im1,Bt1としています。
Delphi6で420kbyte程度です。
じふ饅さんも書かれていますが、キーワード[GifImage Delphi]で検索するとたくさん出てきます。
ただし、国内サイトでは駄目だと思います。
私が使っているAnders Melander氏によるものは、
Delphi5からDelphi7対応版が次のサイトで入手できます。
http://finn.mobilixnet.dk/delphi/
これらはDelphi3/4にも対応しているようですが、保証はされていません。
いずれにせよ、自分用にしか使わないほうが無難だと思っています。
みなさんの方法を駆使して、GIF画像が扱えるようになりました!今回はテクニックの部分だけでなく、特許にも気をつけなければいけないなど、非常に勉強になりました。レスをくれた方、貴重な時間を割いて、たくさんのアドバイス本当にありがとうございました。
ツイート | ![]() |