Page 1 of 1

EOutOfResources with GIF images

Posted: Thu Mar 10, 2011 4:54 pm
by Jacek Puczynski
Hi.
I have a problem with displaying a large number of GIF images in TRichView.

I have a limit for number of items and I remove them with DeleteParas so the text will not grow too much.
However, there is still a problem that randomly occurs. I checked twice my code to see if there was any memory leak but all the images are correctly being removed from the memory when the program runs.

The problem results in one of possible errors (randomly):
it usually has to do with EOutOfResurces or "Incorrect Parameter" or "Cannot draw on canvas".
It seems that I am not the only one that have this problem. I found the article here: http://blagin.ru/articles/gif.html

For displaying images, I am using TGifimage build in C++Builder XE.

Is there any solution known for this problem? Any better GIF classes to use with TRichView (except vampyre imaging library that is also problematic to use in XE)? Or maybe some other solution?

Cheers,
Jacek

Posted: Thu Mar 10, 2011 8:22 pm
by Jacek Puczynski
To give more details I present the call stack before application crash:
:7512b727 KERNELBASE.RaiseException + 0x58
:005a24b0 ; Graphics::TCanvas::RequiredState
:006d8a12 ; Gifimg::TGIFFrame::Draw
:006deae1 ; Gifimg::TGIFImage::Draw
:005a1b8c ; Graphics::TCanvas::Draw
:00802f14 Rvgrin::TRVGraphicInterface::DrawGraphic + 0x14
:007f948c ; Rvitem::_16645
:007f965a ; Rvitem::TRVGraphicItemInfo::Paint
:007c2d4b ; Crvfdata::_16549
:007c3b0b ; Crvfdata::TCustomRVFormattedData::PaintTo
:0078fbc0 ; Rvctrldata::TRVControlData::PaintBuffered
:00767959 ; Richview::TCustomRichView::Paint
:005f4211 ; Controls::TCustomControl::PaintWindow
:005ee8e7 ; Controls::TWinControl::PaintHandler
:005ef0c5 ; Controls::TWinControl::WMPaint
:005f41aa Controls::TCustomControl::WMPaint + 0x16
:005ee72d ; Controls::TWinControl::WndProc
:0076bd93 ; Richview::TCustomRichView::WndProc
:006542be Classes::_17544 + 0x16
:76716238 ; C:\Windows\syswow64\USER32.dll
:76717298 USER32.GetDC + 0x52
:76717177 ; C:\Windows\syswow64\USER32.dll
:767172f1 USER32.GetDC + 0xab
:772500e6 ntdll.KiUserCallbackDispatcher + 0x2e
:005f145a Controls::TWinControl::Update(Controls::TWinControl * const ) + 0x1A
:007c59a1 ; Crvfdata::TCustomRVFormattedData::DeleteParas
DeleteParas is here but is I remove DeleteParas, the exception will also occur.

My experiments show that this error is somehow connected to animated gif. I.e. the exception occurs when I insert lot of not animated gifs. Animated gifs seem to have no limits.

Posted: Fri Mar 11, 2011 1:46 pm
by Sergey Tkachenko
Did you include RVGifAnimate2007 in your project?
Without this unit, animated gifs use too many resources.
When this unit is included, resource usage is optimized.

Posted: Mon Mar 14, 2011 11:31 am
by Jacek Puczynski
Sergey Tkachenko wrote:Did you include RVGifAnimate2007 in your project?
Without this unit, animated gifs use too many resources.
When this unit is included, resource usage is optimized.
Hi Sergey,
yes I include the file in this way:

Code: Select all

#include <RVGifAnimate2007.hpp>
#pragma link "RVGifAnimate2007"
As I said, the problem mostly with non-animated gifs. I.e. large number of small non-animated gifs.
I prepared a small demo project that, when run on my computer, triggers an error after pressing "Start Non-Animated":

http://www.2shared.com/file/vCOTZAPS/test.html

The demo project includes one non-animated and one animated gif files in debug directory.

Cheers,
Jacek

Posted: Mon Mar 14, 2011 4:12 pm
by Sergey Tkachenko
Well, as you can see, you can add 40,000 animated gifs in TRichView control, and the application still works.
But if you try the same with static gifs, you get an exception about a shortage of resources.

Why does it happen? For animated gifs, TRichView uses its own special code for drawing TGifImage, using as less resources as possible.
For static images, TRichView just uses graphic.Draw method. Unfortunately, TGifImage caches some resources (bitmap, mask, palette) after drawing an image, and you quickly run out of resources.
There are no memory/resource leaks, they just caches too much.

Well, I can implement a special fake animator even for static gifs.
But the latest version of TRichView offers a better solution: shared images. You can use only one copy of TGifImage for inserting as many images as you want.

Code: Select all

	TGIFImage *gifImage = new TGIFImage();
	gifImage->LoadFromFile(file);
	for (int i = 0; i < 50; ++i)
	{
		for (int j = 0; j < 200; ++j)
		{
			RichView1->AddPictureEx(L"abc", gifImage, -1, rvvaBaseline);
			RichView1->SetItemExtraIntProperty(RichView1->ItemCount-1, rvepShared, 1);
		}
		RichView1->FormatTail();
		Application->ProcessMessages();
	}
	// do not free gifImage until RichView1 is cleared.
TRichView 13 will be available in the next couple of days.

PS: FormatTail() should be used only when the next portion of document is added from a new line.

Posted: Tue Mar 15, 2011 9:07 am
by Jacek Puczynski
Hi Sergey,
thanks for help.
Yes, it is a good idea to give a possibility of suppressing the destruction of that images. I was already testing it and it works until clearing of control which then tries to delete many pointers of the same object instance.

Fake animator from the other side, will be probably easier to use for many people (easy to understand) 8)
Additionally, fake animator will handle the situation when 40 000 distinct, static images are being inserted into the control (when the shared method will probably fail).

Cheers, Jacek

Posted: Thu Mar 17, 2011 2:18 am
by Anders
An easy solution might be to call TGIFImage.Dormant after TGIFImage.Draw.

TGIFImage.Dormant releases all cached resources so it should reduce resource use but will probably also increase the CPU usage on redraws.

Posted: Thu Mar 17, 2011 8:14 am
by Jacek Puczynski
Anders wrote:An easy solution might be to call TGIFImage.Dormant after TGIFImage.Draw.

TGIFImage.Dormant releases all cached resources so it should reduce resource use but will probably also increase the CPU usage on redraws.
Hi Anders,
yes, it is possible, but it requires the modification in the component source on each update (that is problematic).
Is there any chance that you could add the cache disabling option in TGIFImage? :roll:
Also, I think, the error of the memory scarcity of TGIFImage should not be severe to application and caught internally - or maybe there is some way of catching it that I don't know about? My users experiencing now crashes of the application just because of small gif problem - that's not desirable.

Cheers, Jacek

Posted: Thu Mar 17, 2011 8:36 am
by Anders
Jacek Puczynski wrote:yes, it is possible, but it requires the modification in the component source on each update (that is problematic).
Then ask Sergey to add it to the TRichView source. It's an easy fix (although it's a hack):

Code: Select all

Canvas.StretchDraw(Image, ...);
if (Image is TGIFImage) then
  TGIFImage(Image).Dormant;
Jacek Puczynski wrote:Is there any chance that you could add the cache disabling option in TGIFImage? :roll:
No.
Embarcadero is the current maintainer of TGIFImage. You can ask them (through QC) but IMO it would be a waste of your time. They have fixed some of the bugs I have reported, but they have never implemented any of the improvements I have posted over the years so I've simply stopped reporting feature and improvement requests.
Jacek Puczynski wrote:Also, I think, the error of the memory scarcity of TGIFImage should not be severe to application and caught internally
Well, yes it's unfortunate but TGIFImage was never meant to used the way you are using it. The current implementation is optimized for performance rather than resources - as you've discovered :-(

Posted: Thu Mar 17, 2011 7:18 pm
by Sergey Tkachenko
I cannot add the code using TGifImage directly in TRichView files, because using TGifImage is optional (units playing gif animations are exceptions, because they could be included in projects or not).

But of course, some solution is possible. But we need some time to complete the release of trichview 13 before starting making changes.

Anders, thanks for participating :)