• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 561
  • Last Modified:

Imagelist - does it need memory reserved

HI experts
I am using Timagelist to store a series of fairly large bitmap objects (up to 700 x 500 pixels 24 bits).  I am finding that after a certain number of images (30 to 150 depending on size of bitmap), it gives an error.   I have tried loading the imagelist object during the form create, and using the Replace method.  The error is "Cannot replace".
I tested this some time ago on Delphi7 and I am sure it worked.  I am now using TD
I guess the Imagelist object is just an array of pointers.  But how does the memory get allocated for the bitmaps ?  Does it need to be reserved in some way ??
Thanks
0
diver999
Asked:
diver999
  • 7
  • 6
  • 2
  • +1
3 Solutions
 
epasquierCommented:
of course it is reserved. All the images in an ImageList are loaded in memory. But you have nothing to do, it is all managed by Delphi.
I guess the Imagelist object is just an array of pointers
in a way, yes, but Delphi manages the memory where those pointers points to.

You are aware that an ImageList is supposed to contain images of the same size (Height and Width property of the ImageList component) ? Maybe you are trying to replace the image with one that has different size than what is specified, I'm not sure how TImageList handles that.
0
 
diver999Author Commented:
Thanks for coming back
The images are all of the same size.   This will work for between 30 and 130 images depending on size.   It does not seem to be exactly a size related limit - for example, I can store about 134 images of 385 x 500, but only 34 images of 896 x 500.
The image size is set at the time the process is launched so the images will be same size.
0
 
epasquierCommented:
why do you use Replace ? if you load dynamically all images, maybe Windows (that is under Delphi layer, and it is the OS that is sending the error) will behave better if it just has to ADD images, not replace.
So, instead of Replace, empty the list and add all the images in the right order.
And see if it changes anything in your limitations
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
diver999Author Commented:
I want to implement a rotating buffer.   The number of images could be high, so I just want (say) the last 1000 images.   So I replace image number  (imagecount mod maximages).  
These images are held in memory unless or until the user decides to commit to hard disk.  
0
 
epasquierCommented:
looking at Delphi's ImageList.Replace code, all the question is why the Win API function GetImageHandle returns an error. Which error, that is unknown, nor MSDN says much about the possible errors and even less the cause. That error is what Delphi translates into a cannot replace exception.
At this point, the image you add has been converted already (to the size and pixel format of the ImageList elements, if they are not the same), so that cause can be ruled out.
I'll dig some possible cause for that Windows function to fail
0
 
epasquierCommented:
At this point, Google do not find much reference of the possible error reasons, nor occurrences of the same problem encountered by anybody, be it with Delphi or C/C++ code....

I think you have found a very peculiar issue. Try with other images, or a different order of replacement, on another system, in order to see what could be the environmental cause of the problem.

And when the problem occurs, try this :
ShowMessage(SysErrorMessage(GetLastError));

to see what was the last reported OS error. That could give some clues
0
 
diver999Author Commented:
The message is "The parameter is incorrect"

Is this helpful ???

Here is the line of code
          Form1.thumbnail.Replace(imagecount mod maximage,Image11.Picture.Bitmap,nil);
0
 
Ephraim WangoyaCommented:

If the TImageList is not handling it properly, you can just replace it with TList.

Note that you will have destroy the bitmaps when you are done with the list.

Implement your own methods for Replace
0
 
epasquierCommented:
are you sure of your index ?
(imagecount mod maximage) might not be < thumbnail.Count

please check both values and report
0
 
diver999Author Commented:
In FormCreate I load the thumbnail object with maximage images of the right size.
So I think it should be ok.... ???
0
 
epasquierCommented:
can you post here your code, or at least a small part of if that reproduce the problem ?
0
 
developmentguruCommented:
I have run into ImageList issues in the past that caused odd, OS, errors that may or may not show at any time during the program's execution, but predominantly during shutdown.  In my case the ImageList contained an image that was over 64k and this caused an access violation.  This was on Windows XP.  Ewangoya mentioned, I would try replacing it with a TList (or TObjectList if you want it to free the bitmaps).  This will not try to enforce the same size and may get you around the error just because of that.  You may find that the image causing the error is NOT the same size even though it is supposed to be.  This could cause an issue with a TImageList that would not appear using a different TList type.

In your testing of this you must be precise.  Are you always loading the images starting in the same place?  Does the error always happen on the same image?  If it happens on the same image, what would happen if you skipped that one image (could the image be the issue)?  Another way to test this would be to copy one image you have loaded to a new directory and make 1,000 copies of it, then try to load the images from that directory.

Without being able to see 1) your code and 2) your images I (and the other experts here) are only able to guess at the cause and try to provide some guidance in how to debug it.
0
 
diver999Author Commented:
Hi developmentguru

This is running under WinXP with TD - but the later unreleased version is running under W7 with Delphi XE.  

My testing has been done by recalling a sequence of images - typically 10 to 20 of them.   Depending on image size, the problem can occur repeatably ar image 34, 39, 130, or such numbers.  So the image that causes the problem had successfully written into the object before.  The images are quite big - typically from 200k to 400k pixels x 24 bits.

The relevant line is :
          Form1.thumbnail.Replace(imagecount mod maximage,Image11.Picture.Bitmap,nil);

I have a workaround which just uses array of Tbitmap.   I declare this at a fixed size (say 500).   That seems to work fine.   So instead of Add/Replace I just write to the element of the array.  I need to do this to do it
          MStream := TMemoryStream.Create;
          Image11.Picture.Bitmap.SaveToStream(MStream);
          MStream.Position := 0;
          Thumbnail3[imagecount mod maximage].LoadFromStream(MStream);
          MStream.Free;

I would appreciate any comments on this - it seems a bit tacky but I think it works....
Thanks
0
 
epasquierCommented:
If you don't use any of the specific abilities of TImageList
- possibility to use them with other components and index, like in TreeView & its items
- enforcement of same size for all items
- capability to draw elements easily on canvas, using transparency
- probably a few other needs I don't have in mind
then yes you should abandon TImageList and use an other kind of list (TObjectList for example) as developmentguru said
The use of array is quite well possible if your application will always have a fixed number of thumbnails, that is a bit easier to use.
But in all cases, be prudent with the memory management of the list/array items, and the way you use them (like passing of reference), as it can be tricky.

Instead of use of MemoryStream as a way to sync data between the image and the thumbnail array, you can just use Assign :
Thumbnail3[imagecount mod maximage].Assign(Image11.Picture.Bitmap);

Open in new window

0
 
developmentguruCommented:
The array is a good way of handling things if you know you will not exceed the 500 size limit.  If the list could change size (start at 100, go to 175, 325, 415, etc) but not exceed 500 then you could keep the array of 500 but I would add a separate counter to show how many are currently in use.  If you will only replace (never delete) then this would work well.  You need to remember that your array is storing an array of pointers to bitmaps.  Your code does not show the initiation of the bitmap objects... Do you create all 500 to start?  If so then the code you have should work.  You did not show freeing them either, yet I should be safe in assuming that you did.

The only reasons I would consider moving to a TObjectList instead would be
1) If you need to be able to have a dynamic size (allow deleting from the list, adding, and going over 500)
2) It would allow you to remove the cleanup code for the bitmaps (destroying the TObjectList would free all bitmaps, as Deleting one would free it's bitmap)
0
 
diver999Author Commented:
Thanks, experts
I have tried to split points.
I have implemented using array of Tbitmap.  I pre-load this, to be sure it works.  It would appear to be a problem of how compiler reports errors ??
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 7
  • 6
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now