Image from Resources via ResourceStream returns nil - delphi

I've got a function that returns a TPicture object, from a resource stream, which loads PNGImage from a resource file.
function getImage(AName : string; lvl : integer): TPicture;
var Loader : TResourceStream;
image : TPngImage;
begin
Image := TPngImage.Create;
try begin
Loader := TResourceStream.Create(hInstance, AName+'_l'+IntToStr(lvl) , RT_RCDATA);
Loader.Position := 0;
Image.LoadFromStream(Loader);
result.Graphic := Image;
end
finally
Image.Free;
Loader.Free;
end;
end;
Can you tell me what is wrong with the code? The image object always nil, I searched the web for the answer, or any other way to load image from resources to TPicture, but found no answer that helped.

As stated in comments, your code is quite broken. It should look more like this instead:
function getImage(AName : string; lvl : integer): TPicture;
var
Loader : TResourceStream;
image : TPngImage;
begin
Result := nil;
Image := TPngImage.Create;
try
Loader := TResourceStream.Create(hInstance, AName+'_l'+IntToStr(lvl), RT_RCDATA);
try
Image.LoadFromStream(Loader);
finally
Loader.Free;
end;
Result := TPicture.Create;
try
Result.Graphic := Image;
except
Result.Free;
raise;
end;
finally
Image.Free;
end;
end;
Then the caller can do this:
var
Pic: TPicture;
begin
Pic := getImage(...);
try
// use Pic as needed...
finally
Pic.Free;
end;
end;
That being said, it is generally not a good design choice to return a new object as a function result. The caller should create the object and pass it into the function to be filled in, that way the caller can choose where the object comes from (for example, using the TImage.Picture property):
procedure getImage(AName : string; lvl : integer; APicture: TPicture);
var
Loader : TResourceStream;
image : TPngImage;
begin
APicture.Assign(nil);
Image := TPngImage.Create;
try
Loader := TResourceStream.Create(hInstance, AName+'_l'+IntToStr(lvl), RT_RCDATA);
try
Image.LoadFromStream(Loader);
finally
Loader.Free;
end;
APicture.Graphic := Image;
finally
Image.Free;
end;
end;
Then the caller can do this:
var
Pic: TPicture;
begin
Pic := TPicture.Create;
try
getImage(..., Pic);
// use Pic as needed...
finally
Pic.Free;
end;
end;
Or this:
begin
getImage(..., Image1.Picture);
end;

Related

LoadFromStream doesn't appear to work in Delphi 5

I'm using Delphi 5 Enterprise because that's what the program I'm working with was written in. I have written a procedure which saves bitmaps to an Access database quite happily. Now I want to be able to retrieve the bitmaps. Saving the bitmaps, I use SaveToStream. Retrieving them, I used LoadFromStream but the compiler tells me that it doesn't recognise that function. The code is below:
procedure TForm1.Button2Click(Sender: TObject);
var
Field : TBlobField;
Stream : TStream;
BMap : TBitMapImage;
begin
if BloBQuery.Active then
begin
Field := TBlobField(BlobQuery.FieldByName('Blob'));
Stream := BlobQuery.CreateBlobStream(Field, bmRead);
BMap := TBitMapImage.Create;
try
Image2.Picture.Graphic := BMap.LoadFromStream(Stream);
finally
BMap.Free;
Stream.Free;
end;
end;
end;
Can anyone tell me when LoadFromStream won't work? It seems odd! Thanks.
The code which wrote the bitmap was:
procedure TForm1.Button1Click(Sender: TObject);
var
Field : TBlobField;
Stream : TStream;
begin
if (BlobQuery.Active = True) and (Image1.Picture.Graphic <> nil) then begin
BlobQuery.Insert;
Field := TBlobField(BlobQuery.FieldByName('Blob'));
Stream := BlobQuery.CreateBlobStream(Field, bmWrite);
try
Image1.Picture.Graphic.SaveToStream(Stream);
finally
Stream.Free;
BlobQuery.Post;
end;
end;
end;
Assuming Image1.Picture.Graphic was pointing at a TBitmap object when you saved it to the DB, you need to use a TBitmap object instead of a TBitMapImage object when reading the image back out, eg:
procedure TForm1.Button2Click(Sender: TObject);
var
Field : TBlobField;
Stream : TStream;
BMap : TBitmap;
begin
if BlobQuery.Active then
begin
Field := TBlobField(BlobQuery.FieldByName('Blob'));
Stream := BlobQuery.CreateBlobStream(Field, bmRead);
try
BMap := TBitmap.Create;
try
BMap.LoadFromStream(Stream);
Image2.Picture.Graphic := BMap;
finally
BMap.Free;
end;
finally
Stream.Free;
end;
end;
end;
Alternatively:
procedure TForm1.Button2Click(Sender: TObject);
var
Field : TBlobField;
Stream : TStream;
begin
if BlobQuery.Active then
begin
Field := TBlobField(BlobQuery.FieldByName('Blob'));
Stream := BlobQuery.CreateBlobStream(Field, bmRead);
try
Image2.Picture.Bitmap.LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
end;

Getting JPEG Error #42 when trying to add new record

I have figured out how to store and retrieve a JPEG file in my database. If the JPEG file is there, I can easily edit it, but if I try to enter a new record, I always get JPEG Error #42. Here are my code snippets. I use btnLabelGetClick to upload an image to the stream to be posted.
procedure TfrmWines.AutoSetDataChange(Sender: TObject; Field: TField);
var
JPG: TJPEGImage;
ms: TMemoryStream;
begin
JPG := TJPEGImage.Create;
ms := TMemoryStream.Create;
try
TBlobField(wdatamod.mywines.FieldByName('winelabel')).SaveToStream(ms);
ms.Position := 0;
JPG.LoadFromStream(ms);
Image1.Picture.Assign(JPG);
finally
JPG.Free;
ms.Free;
end;
end;
procedure TfrmWines.btnAddClick(Sender: TObject);
begin
ButtonsEnter;
//btnLabelGet.Click;
wdatamod.mywines.Insert;
edWinename.SetFocus;
end;
procedure TfrmWines.btnLabelGetClick(Sender: TObject);
begin
if OpenPictureDialog1.Execute(Self.Handle) then
Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
end;
I solved this AND coded the way to add a standing image for all new records if I don't have an image I want to use:
if autoset.DataSet.State = dsInsert then
begin
image1.Picture.Graphic.LoadFromFile('q:\sourcecode\mycellar\images\blk_wht_glass.jpg');
Exit;
end;
Here is the new code that prevents the JPEG Error #42 on adding a new record
procedure TfrmWines.AutoSetDataChange(Sender: TObject; Field: TField);
var
JPG:TJPEGImage;
ms:TMemoryStream;
begin
if autoset.DataSet.State = dsInsert then
begin
image1.Picture.Graphic.LoadFromFile('q:\sourcecode\mycellar\images\blk_wht_glass.jpg');
Exit;
end;
begin
JPG:=TJPEGImage.Create;
ms:=TMemoryStream.Create;
try
TBlobField(wdatamod.mywines.FieldByName('winelabel')).SaveToStream(ms);
ms.Position := 0;
JPG.LoadFromStream(ms);
Image1.Picture.Assign(JPG);
finally
JPG.Free;
ms.Free;
end;
end;
end;
If your BLOB field is empty, there is no data to load into TJPEGImage. You need to check for that condition before calling LoadFromStream().
Also, I suggest using TDataSet.CreateBlobStream() instead of using TBlobStream.SaveToStream() to make a copy of the BLOB data in memory. Let TJPEGImage read the data directly from the database, the DataSet knows how to read/write BLOB data using streams.
Try something more like this:
procedure TfrmWines.AutoSetDataChange(Sender: TObject; Field: TField);
var
Fld: TField;
JPG: TJPEGImage;
strm: TStream;
begin
Fld := wdatamod.mywines.FieldByName('winelabel');
if (Fld.DataSet.State = dsInsert) or (TBlobField(Fld).BlobSize = 0) then
begin
Image1.Picture.LoadFromFile('q:\sourcecode\mycellar\images\blk_wht_glass.jpg');
end else
begin
JPG := TJPEGImage.Create;
try
strm := Fld.DataSet.CreateBlobStream(Fld, bmRead);
try
JPG.LoadFromStream(strm);
finally
strm.Free;
end;
Image1.Picture.Assign(JPG);
finally
JPG.Free;
end;
end;
end;
Alternatively:
procedure TfrmWines.AutoSetDataChange(Sender: TObject; Field: TField);
var
Fld: TField;
JPG: TJPEGImage;
strm: TStream;
begin
Fld := wdatamod.mywines.FieldByName('winelabel');
if TBlobField(Fld).BlobSize > 0 then
begin
JPG := TJPEGImage.Create;
try
strm := Fld.DataSet.CreateBlobStream(Fld, bmRead);
try
JPG.LoadFromStream(strm);
finally
strm.Free;
end;
Image1.Picture.Assign(JPG);
finally
JPG.Free;
end;
end else
begin
Image1.Picture.LoadFromFile('q:\sourcecode\mycellar\images\blk_wht_glass.jpg');
end;
end;

how to convert idhttp downloaded image from extention to another?

i have this Thread that get image url from the web then save it to memory stream then save from memory stream To file
i needed to convert any image that downloaded to a gif image so i do something like this
unit downloadimgThread;
interface
uses Windows, SysUtils, Classes, dialogs, IdSSLOpenSSL, IdHttp, IdUri, System.AnsiStrings, Graphics, Jpeg, Vcl.Imaging.GIFImg, PNGImage;
type
TDownloadUpdateVisualEvent = procedure(Sender: TObject; Anameofimg: String;
var Aimagelocate: String) of object;
type
TURLDownload = class(TThread)
private
FOnUpdateVisual: TDownloadUpdateVisualEvent;
FURL: String;
Fnameofimg: string;
FPathImage: string;
FFileNameImage: string;
ImageName: string;
PathURL: string;
procedure DoUpdateVisual;
protected
procedure Execute; override;
public
constructor Create(Thrdid: Pointer; const AUrl: String;
Const AOutPathImages: string; AOnUpdateVisual: TDownloadUpdateVisualEvent;
Anameofimg: String); reintroduce;
property URL: string read FURL write FURL;
property PathImage: string read FPathImage;
property FileNameImage: string read FFileNameImage;
end;
var
URLDOWNLOAD: TURLDownload;
implementation
{ TURLDownload }
function JpgToGif(ms: TMemoryStream): Boolean;
var
gif: TGIFImage;
jpg: TJPEGImage;
begin
Result := False;
gif := TGIFImage.Create;
try
jpg := TJPEGImage.Create;
try
//jpg
ms.Position := 0;
jpg.LoadFromStream(ms);
jpg.DIBNeeded;
gif.Assign(jpg);
//save...
ms.Clear;
gif.SaveToStream(ms);
Result := True;
finally
jpg.Free;
jpg := nil;
end;
finally
gif.Free;
gif := nil;
end;
end;
constructor TURLDownload.Create(Thrdid: Pointer; const AUrl, AOutPathImages: string; AOnUpdateVisual: TDownloadUpdateVisualEvent; Anameofimg: String);
var
URI: TIdURI;
begin
inherited Create(false);
FreeOnTerminate := True;
FURL := AUrl;
FOnUpdateVisual := AOnUpdateVisual;
Fnameofimg := Anameofimg;
FPathImage := AOutPathImages;
URI := TIdURI.Create(AUrl);
try
ImageName := URI.Document;
PathURL := URI.path;
finally
URI.Free;
end;
end;
procedure TURLDownload.DoUpdateVisual;
begin
if Assigned(FOnUpdateVisual) then
FOnUpdateVisual(self, Fnameofimg, FFileNameImage);
end;
procedure TURLDownload.Execute;
var
aMs: TMemoryStream;
aIdHttp: TIdHttp;
IdSSL: TIdSSLIOHandlerSocketOpenSSL;
path: string;
dir: string;
SPEXT : String;
itsimage: string;
responsechk: Integer;
begin
dir := AnsiReplaceText(PathURL, '/', '');
if (ImageName = '') then
begin
exit;
end;
SPEXT := ExtractFileExt(ImageName);
ImageName := Copy(ImageName, 1, Length(ImageName) - Length(SPEXT));
path := PathImage + '\' + ImageName + '.gif';
if fileexists(path) then
begin
FFileNameImage := path;
if Assigned(FOnUpdateVisual) then
begin
Synchronize(DoUpdateVisual);
end;
exit;
end
else
if not fileexists(path) then
begin
aMs := TMemoryStream.Create;
aIdHttp := TIdHttp.Create(nil);
IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try
IdSSL.SSLOptions.Method := sslvTLSv1;
IdSSL.SSLOptions.Mode := sslmUnassigned;
aIdHttp.HTTPOptions := [hoForceEncodeParams] + [hoNoProtocolErrorException];
aIdHttp.IOHandler := IdSSL;
aIdHttp.AllowCookies := True;
aIdHttp.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0';
aIdHttp.HandleRedirects := True;
aIdHttp.RedirectMaximum := 3;
try
aIdHttp.Head(trim(FURL));
except
end;
itsimage := aIdHttp.Response.ContentType;
responsechk := aIdHttp.ResponseCode;
if responsechk <> 200 then
begin
FFileNameImage := 'error';
if Assigned(FOnUpdateVisual) then
begin
Synchronize(DoUpdateVisual);
end;
exit;
end;
if (itsimage = 'image/gif') then
begin
try
aIdHttp.Get(trim(FURL), aMs);
except
end;
aMs.SaveToFile(path);
end else if (itsimage = 'image/jpeg') then
begin
try
aIdHttp.Get(trim(FURL), aMs);
except
end;
if JpgToGif(aMs) then
begin
aMs.SaveToFile(path);
end;
end;
try
if aIdHttp.Connected then
aIdHttp.Disconnect;
except
end;
finally
aMs.Free;
IdSSL.Free;
aIdHttp.Free;
end;
end;
FFileNameImage := path;
if Assigned(FOnUpdateVisual) then
begin
Synchronize(DoUpdateVisual);
end;
end;
end.
in this unit i try to check if image type is jpg then convert it to gif and save it specifically at this line of code
if (itsimage = 'image/jpeg') then
begin
try
aIdHttp.Get(trim(FURL), aMs);
except
end;
if JpgToGif(aMs) then
begin
aMs.SaveToFile(path);
end;
// function to convert
function JpgToGif(ms: TMemoryStream): Boolean;
var
gif: TGIFImage;
jpg: TJPEGImage;
begin
Result := False;
gif := TGIFImage.Create;
try
jpg := TJPEGImage.Create;
try
//jpg
ms.Position := 0;
jpg.LoadFromStream(ms);
jpg.DIBNeeded;
gif.Assign(jpg);
//save...
ms.Clear;
gif.SaveToStream(ms);
Result := True;
finally
jpg.Free;
jpg := nil;
end;
finally
gif.Free;
gif := nil;
end;
end;
when i try to convert the image and save it the image saved is corrupted what could be the issue ?
There is a very simple solution for this. And that is to use FMX Bitmap instead of default VCL Bitmap as it allows automatic format recognition on load and automatic format choosing on save based on file extension of the file name you provide to SaveToFile method.
Here is a simple code that loads selected image chosen in OpenDialog into Memory stream first and then into Bitmap and then it saves the image into GIF format.
procedure TForm1.Button1Click(Sender: TObject);
var Bitmap: FMX.Graphics.TBitmap;
MS: TMemoryStream;
begin
if OpenDialog1.Execute then
begin
MS := TMemoryStream.Create;
MS.LoadFromFile(OpenDialog1.FileName);
Bitmap := FMX.Graphics.TBitmap.Create;
Bitmap.LoadFromStream(MS);
Bitmap.SaveToFile('D:\Proba.gif');
end;
end;
As you can see you only need just a few lines and you get ability to convert images between all supported formats.
You can see which ones are supported here:
http://docwiki.embarcadero.com/Libraries/XE8/en/FMX.Graphics.TBitmapCodecManager#Supported_Image_Formats
Just make sure you are indeed using FMX.Graphics.TBitmap by specifying the full namespace for the file in which it resided.
NOTE: Working on VCL application does not mean you can't use some of the functionality that is present in Fire Monkey.

How to get image binary data using XMLHTTPRequest in Delphi

I need to access binary image data using XMLHttpRequest in Delphi. I am using the following code but its not working, could someone please tell me what's wrong with this code, thanks in advance.
//I am using this function to get Image Binary data into Memory Stream.
procedure SendGETRequest(p_Url: string; p_resStream: TMemoryStream);
begin
FXmlHttpReq.open(METHOD_GET, p_Url, false, FUsername, FPassword);
FXmlHttpReq.setRequestHeader(HTTP_AUTHENTICATION, HTTP_BASIC + EncodeBase64(
FUsername + ':'+FPassword));
FXmlHttpReq.setRequestHeader(HTTP_CACHE_CONTROL, HTTP_NO_CACHE);
//FXmlHttpReq.setRequestHeader('Content-type','application/octet-stream');
FXmlHttpReq.send('');
if not VarIsEmpty(FXmlHttpReq.responseBody) then
begin
p_resStream:= OleVariantToMemoryStream(FXmlHttpReq.responseStream);
end;//if...
end;
function OleVariantToMemoryStream(OV: OleVariant): TMemoryStream;
var
Data: PByteArray;
Size: integer;
begin
Result := TMemoryStream.Create;
try
Size := VarArrayHighBound (OV, 1) - VarArrayLowBound(OV, 1) + 1;
Data := VarArrayLock(OV);
try
Result.Position := 0;
Result.WriteBuffer(Data^, Size);
finally
VarArrayUnlock(OV);
end;
except
Result.Free;
Result := nil;
end;
end;
responseStream is IStream. You need to convert it using TOleStream (AxCtrls):
uses AxCtrls, ComObj, ActiveX;
procedure TForm1.Button1Click(Sender: TObject);
var
oXMLHTTP: OleVariant;
MemoryStream: TMemoryStream;
Stream: IStream;
OleStream: TOleStream;
begin
oXMLHTTP := CreateOleObject('MSXML2.XMLHTTP.3.0');
oXMLHTTP.open('GET', 'https://www.google.com/images/srpr/logo11w.png', False);
oXMLHTTP.send(EmptyParam);
Stream := IUnknown(oXMLHTTP.ResponseStream) as IStream;
OleStream := TOleStream.Create(Stream);
try
OleStream.Position := 0;
MemoryStream := TMemoryStream.Create;
try
MemoryStream.CopyFrom(OleStream, OleStream.Size);
MemoryStream.SaveToFile('logo11w.png');
finally
MemoryStream.Free;
end;
finally
OleStream.Free;
end;
end;

TGifImage Transparency Issue

I am using TGifImage that is included with Delphi XE.
What I am trying to do is load a Gif from a File and and extract all the frames to a Bitmap.
This is what I did so far:
procedure ExtractGifFrames(FileName: string);
var
Gif: TGifImage;
Bmp: TBitmap;
i: Integer;
begin
Gif := TGifImage.Create;
try
Gif.LoadFromFile(FileName);
Bmp := TBitmap.Create;
try
Bmp.SetSize(Gif.Width, Gif.Height);
for i := 0 to Gif.Images.Count - 1 do
begin
if not Gif.Images[i].Empty then
begin
Bmp.Assign(Gif.Images[i]);
Bmp.SaveToFile('C:\test\bitmap' + IntToStr(i) + '.bmp');
end;
end;
finally
Bmp.Free;
end;
finally
Gif.Free;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenPictureDialog1.Execute then
begin
ExtractGifFrames(OpenPictureDialog1.FileName);
end;
end;
The problem I am facing is with some transparency issue with a lot of different Gifs, and also size problems.
Here are some example bitmaps that were saved using my code above:
As you can see the results are not great, they have size and transparency issues.
I know the Gif Files themselves are not corrupt, because I can load them through my web browser and they display correctly without fault.
How can I load a Gif from File, assign each frame to Bitmap without losing any quality?
For older Delphi Versions (Pre 2009): Take a look at the code of GIFImage unit, you might want to check how TGIFPainter renders the images based on each Frame's Disposal method.
I have wrote a small code utilizing TGIFPainter.OnAfterPaint event handler to save the active frame to BMP, and do all the "hard work".
Note: GIFImage unit version 2.2 Release: 5 (23-MAY-1999)
type
TForm1 = class(TForm)
Button1: TButton;
ProgressBar1: TProgressBar;
procedure Button1Click(Sender: TObject);
public
FBitmap: TBitmap;
procedure AfterPaintGIF(Sender: TObject);
end;
...
procedure TForm1.Button1Click(Sender: TObject);
var
GIF: TGIFImage;
begin
GIF := TGIFImage.Create;
FBitmap := TBitmap.Create;
Button1.Enabled := False;
try
GIF.LoadFromFile('c:\test\test.gif');
GIF.DrawOptions := GIF.DrawOptions - [goLoop, goLoopContinously, goAsync];
GIF.AnimationSpeed := 1000; // Max - no delay
FBitmap.Width := GIF.Width;
FBitmap.Height := GIF.Height;
GIF.OnAfterPaint := AfterPaintGIF;
ProgressBar1.Max := Gif.Images.Count;
ProgressBar1.Position := 0;
ProgressBar1.Smooth := True;
ProgressBar1.Step := 1;
// Paint the GIF onto FBitmap, Let TGIFPainter do the painting logic
// AfterPaintGIF will fire for each Frame
GIF.Paint(FBitmap.Canvas, FBitmap.Canvas.ClipRect, GIF.DrawOptions);
ShowMessage('Done!');
finally
FBitmap.Free;
GIF.Free;
Button1.Enabled := True;
end;
end;
procedure TForm1.AfterPaintGIF(Sender: TObject);
begin
if not (Sender is TGIFPainter) then Exit;
if not Assigned(FBitmap) then Exit;
// The event will ignore Empty frames
FBitmap.Canvas.Lock;
try
FBitmap.SaveToFile(Format('%.2d.bmp', [TGIFPainter(Sender).ActiveImage]));
finally
FBitmap.Canvas.Unlock;
end;
ProgressBar1.StepIt;
end;
Note: No error handling to simplify the code.
For newer Delphi Versions (2009+): With build-in GIFImg unit, you can do this quit easy with the use of TGIFRenderer (which completely replaced old TGIFPainter) e.g.:
procedure TForm1.Button1Click(Sender: TObject);
var
GIF: TGIFImage;
Bitmap: TBitmap;
I: Integer;
GR: TGIFRenderer;
begin
GIF := TGIFImage.Create;
Bitmap := TBitmap.Create;
try
GIF.LoadFromFile('c:\test\test.gif');
Bitmap.SetSize(GIF.Width, GIF.Height);
GR := TGIFRenderer.Create(GIF);
try
for I := 0 to GIF.Images.Count - 1 do
begin
if GIF.Images[I].Empty then Break;
GR.Draw(Bitmap.Canvas, Bitmap.Canvas.ClipRect);
GR.NextFrame;
Bitmap.SaveToFile(Format('%.2d.bmp', [I]));
end;
finally
GR.Free;
end;
finally
GIF.Free;
Bitmap.Free;
end;
end;
Using GDI+:
uses ..., GDIPAPI, GDIPOBJ, GDIPUTIL;
procedure ExtractGifFrames(const FileName: string);
var
GPImage: TGPImage;
encoderClsid: TGUID;
BmpFrame: TBitmap;
MemStream: TMemoryStream;
FrameCount, FrameIndex: Integer;
begin
GPImage := TGPImage.Create(FileName);
try
if GPImage.GetLastStatus = Ok then
begin
GetEncoderClsid('image/bmp', encoderClsid);
FrameCount := GPImage.GetFrameCount(GDIPAPI.FrameDimensionTime);
for FrameIndex := 0 to FrameCount - 1 do
begin
GPImage.SelectActiveFrame(GDIPAPI.FrameDimensionTime, FrameIndex);
MemStream := TMemoryStream.Create;
try
if GPImage.Save(TStreamAdapter.Create(MemStream), encoderClsid) = Ok then
begin
MemStream.Position := 0;
BmpFrame := TBitmap.Create;
try
BmpFrame.LoadFromStream(MemStream);
BmpFrame.SaveToFile(Format('%.2d.bmp', [FrameIndex]));
finally
BmpFrame.Free;
end;
end;
finally
MemStream.Free;
end;
end;
end;
finally
GPImage.Free;
end;
end;
The frames of an animated GIF file often only contain the differences from the previous frame (an optimisation technique to reduce file size). So in order to produce a snapshot of the GIF at a particular point, you'll have to paste all the frames up to that point, one after the other.
We can achieve this by using Draw() with its 'draw transparently' option set:
procedure ExtractGifFrames(FileName: string);
var
Gif: TGifImage;
Bmp: TBitmap;
i: Integer;
Bounds: TRect;
begin
Gif := TGifImage.Create;
try
Gif.LoadFromFile(FileName);
Bounds := Rect(0, 0, Gif.Width-1, Gif.Height-1);
Bmp := TBitmap.Create;
try
Bmp.SetSize(Gif.Width, Gif.Height);
Bmp.PixelFormat := pf32bit;
for i := 0 to Gif.Images.Count - 1 do
begin
if not Gif.Images[i].Empty then
begin
Gif.Images[i].Draw(Bmp.Canvas, Bounds, True, True);
Bmp.SaveToFile(IntToStr(i) + '.bmp');
end;
end;
finally
Bmp.Free;
end;
finally
Gif.Free;
end;
end;
NB: There are other elements to the animated GIF format, which specify the amount of times frames are to be repeated etc. but they may not concern you.

Resources