5-Minute-Snack: Loading big images into TImage without flicker

Loading images into a TImage component is easy. We do this during design-time most of the time. In the other cases it is mostly a call to LoadFromFile and we are done.

Recently, I had the task to display several images with a timer delay. Again, very simple to implement, but if you are not careful it looks hideous. This was the piece of code I implemented in the method that was triggered whenever the next image was supposed to be shown:

myImageComponent.LoadFromFile( TImageProvider.GetNextImageFilename );

 The image provider returns the filename of the next image. One would think that he last image being loaded is being shown until the next image is being displayed. Sadly, the VCL handles this differently – for good reasons, I guess. 

As soon as that line is invoked, the image displayed is being removed and you end up seeing an empty space where the image has been before. Depending on the size of the image file you load that might be a significant amount of time. Even if the image has a small file size, there will always be a flicker.

A simple trick helps. Sometimes more code less compact is actually better:

var
  lTempStream : TMemoryStream
  // ....

begin
  lTempStream := TMemoryStream.Create;
  try
    lTempStream.LoadFromFile( 
      TImageProvider.GetNextImageFilename
      );
    lTempStream.Position := 0;
    myImageComponent.Picture.LoadFromStream(
      lTempStream
     );
  finally
      lTempStream.Free;
  end;

  //...

end;

In this alternative approach, we load the image into memory first. That means the delay happens when the image is still visible. Furthermore, the assignment is instantaneous, so there will be no flicker.

Subtle difference in code, big difference in the presentation of your app.

Tags: , ,
5 comments on “5-Minute-Snack: Loading big images into TImage without flicker
  1. C Johnson says:

    Seems like it would be even better to load into an image object and assign that instead. That way decoding is also taken out of the equation.

    Extra points for doing that in a background thread, but you do have to manage overlapping requests (pretty simple to do) – make the main interface even smoother.

  2. Adrian says:

    Hey great work around!

  3. Totte Karlsson says:

    Hi and thanks for your code.

    I’m switching between images of various size, using C++ Builder XE3, and TImage. I tried your suggestion above, but still getting considerable flicker. In my case, I see no difference in fact.

    Also, for the image to actually be updated, I need to call
    TImage->Repaint(), Refresh or Invalidate(), and that is where I see the actual flicker.

    Any workaround for that?

    Cheers,
    tk

    • Holger Flick says:

      With regard to the size you should make sure that the image component is always the same size, i.e. AutoSize should be False. Then the fitting and stretching will give you a performance hit in case you use them. You should pre-process the images if you need a different size. The component is not optimized for that either. As soon as you assign a new reference or load a new image it will be repainted. May be you could look into the animation and graphic abilities of FireMonkey for your requirement?

Partnerships




Top