0

I have tried each of the following in Delphi 2010 to display an animated gif on my form. All result in an access violation. (Two of the three variations were commented out on each attempt.) Thanks much.

uses
  ... GIFImg,...

Image1: TImage;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // A valid animated gif was loaded into Image1 at design time
  TGIFImage(image1).Animate := true;
  TGIFImage(image1.Picture).Animate := true;
  TGIFImage(image1.Picture.Graphic).Animate := true;
end;

I attempted to follow the answer in the question linked above, but the solution did not work for me (and with that question being tagged explicitly as Delphi-7, I didn't know if something had changed). Rewriting to "(image1.Picture.Graphic as TGIFImage).Animate := true;" results in "... exception class EInvalidCast with message 'Invalid class typecast'." It's not clear to me why the typecast is invalid since I'm positive that an animated gif has already been loaded at design time.

Edit to clarify the issue, here's the revised code. The showmessage tells me that the image is a TdxSmartImage. No idea why it thinks this. (I did at one point try to load the image into a devExpress control to see if that would work, but I subsequently removed all dexExpress elements from the form/project and regenerated the gif file.

procedure TForm1.FormCreate(Sender: TObject);
begin
  image1.Picture.LoadFromFile('C:\ChronSource\ChronDialogs\11.0 job menu.gif');
  ShowMessage(image1.Picture.Graphic.ClassName);
  // this says "TdxSmartImage"
  (image1.Picture.Graphic as TGIFImage).Animate := true;
end;
Eric
  • 142
  • 1
  • 13
  • 3
    Only the 3rd variation is valid, but only *after* a GIF has been loaded into the `TImage`. If you are getting an AV on the 3rd variation, you need to debug to find out why. The 1st variation is invalid because a `TImage` is not a `TGIFImage`. The 2nd variation is invalid because a `TPicture` is not a `TGIFImage`. Those are invalid casts, but you are not using the `as` operator to perform the casts, so the compiler doesn't generate any code to check if the casts succeed at runtime – Remy Lebeau Apr 03 '18 at 22:34
  • 1
    What does `ShowMessage(image1.Picture.Graphic.ClassName);` tell you? – Sertac Akyuz Apr 04 '18 at 00:11
  • It may mean that I don't understand enough about what I'm doing on this. (do very little with images). It's telling me that it's a TdxSmartImage. No idea why it thinks that this is some sort of DevExpress(?) image since there are no remaining devExpress controls in this project, and I recreated the gif with Camtasia and then switched to loading it at runtime. – Eric Apr 04 '18 at 01:15
  • @Rudy: I don't think I knew enough to ask the question well, but I think the comments here are reflecting that there is something different going on here than in the previous question. – Eric Apr 04 '18 at 01:17
  • 2
    @Eric clearly you have another library in your project that is overwriting registration of the `.gif` file extension in `TPicture` so `TdxSmartImage` gets priority over `TGIFImage`. So, either remove that library, or create your own `TGIFImage` object at runtime and `Assign()` it to `image1.Picture` instead of calling `image1.Picture.LoadFromFile()`. – Remy Lebeau Apr 04 '18 at 04:32
  • @Eric: as it looked, my comment was right. It was unknown that something replaced the TGifImage. That should have been in the question. – Rudy Velthuis Apr 04 '18 at 10:44
  • @Rudy: agree. I didn't know enough until I'd read the comments from Remy and Sertac how to figure out where the problem was. – Eric Apr 04 '18 at 12:47
  • FWIW, did you also remove the devExpress units from your uses clause? If not, do so. – Rudy Velthuis Apr 04 '18 at 22:09
  • @Rudy: I did remove all devExpress units from the uses. So there must be something devExpress has that's now integrated with the IDE. Regardless, the approach that I took in my answer below ended up working quite well. Thanks for the help. – Eric Apr 04 '18 at 23:18

2 Answers2

3

You have a third party library that has replaced the TPicture property editor. The editor is creating the library's own gif implementation class but apparently it does not support animated images.

If you want to restore default design time behavior, you have to uninstall the property editor. For a one time override, after loading your picture, editing the dfm file to change the picture's class name and editing the pas file to change the required unit name might also work (which I'm not sure).

At runtime it's easier to use the class you want. If the unit responsible for gif images in the third party library is linked, unregister that first.

TPicture.UnRegisterGraphicClass(TdxSmartImage);
Image1.Picture.LoadFromFile('...');
(Image1.Picture.Graphic as TGIFImage).Animate := True;

If not, you should be able to load the image as a TGifImage without any problems.

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • thanks much. Your various comments helped me figure out the solution below that ended up working. – Eric Apr 04 '18 at 12:42
  • @Eric - You're welcome. I wonder if you tried the solution in the answer. I'm curious if it worked for you or not. – Sertac Akyuz Apr 04 '18 at 13:17
  • I didn't try it as written because the bit that I was writing in this test app is going into a much larger library. I was leery of UnRegisterGraphicClass because I wasn't sure how this might affect other devExpress controls in the library. You turned me on to the need to explictly cast the loaded image as a gif, butthe approach I took below struck me as being less risky to other controls. – Eric Apr 04 '18 at 13:45
  • Fair enough, thanks for explaining. There's nothing wrong with accepting your own answer, it's a fine solution. – Sertac Akyuz Apr 04 '18 at 13:49
3

Using the various responses above, I was able to come up with this approach that worked;

procedure TForm1.FormCreate(Sender: TObject);
  var
    aGIF:TGIFImage;
    sFile: string;
begin
  try
    ...
    aGIF := TGIFImage.Create;
    aGIF.LoadFromFile(sfile);
    aGIF.Animate := true;
    image1.Picture.Graphic := aGIF;
  except
  ...
Eric
  • 142
  • 1
  • 13
  • 2
    You should wrap the `aGIF` object in a `try..finally` block, as you need to `Free` it regardless of whether an exception is thrown or not. The `Graphic` property setter will create its own `TGIFImage` object that has a *copy* of `aGIF`'s data, so you have to call `aGIF.Free` afterwards to avoid a memory leak. – Remy Lebeau Apr 04 '18 at 18:12