I discovered that this is the problem using MemProof. Which showed that
CreatePalette did not have a corresponding DeleteObject after the program
ended. I could be misreading the results, but this is the only thing I can
find that is causing my resource problem.
Note: My client application's images are being updated when changes occur on
the server. I am creating a network based game and therefore changes to the
user's view do change quite frequently.
Can anyone help or steer me to a solution to the issue?
Thanks in advance,
Robert
if you are using Delphi 3, this is a documented bug I had terrible
hours with until I found a fix at the Delphi Buglist by Reinier
Sterkenburg. Find a link to it on my "Delphi-Box" Tips area,
the buglist also shows a fix for the leak.
regards,
Richey
Robert
r.fellner _@_ bigfoot dot com (http://come.to/Delphi-Box) wrote in message
<368fd909...@forums.inprise.com>...
The resolution to the problem was not obvious, but the Bitmap.ReadDIB and
HintWindow.WMNCPaint removed 99% of the resource leaks.
There still remain a dozen, which do not grow as the application is run, but
I have applied every fix that applies, except the JPEG one. Since I do not
have any JPEG images I am guessing this is not one of the last leaks. But
am not sure because MemProof is being arcane in its reporting of these last
leaks.
Thanks again for the reference Richey.
Btw, it seems Delphi shipped the JPEG.dcu but not the source. Where do I
get the source? If it is not available to a Delphi3 developer, or a better
fix has been found, perhaps the Palette leak can be fixed in the Graphics
unit? (Note: I do not use Packages)
Robert
Robert Winkler wrote in message <76o5ro$6i...@forums.borland.com>...
>Btw, it seems Delphi shipped the JPEG.dcu but not the source. Where do I
>get the source? If it is not available to a Delphi3 developer, or a better
>fix has been found, perhaps the Palette leak can be fixed in the Graphics
>unit? (Note: I do not use Packages)
Hi Robert.
You'll find the JPEG source on the Delphi CD in D:\INFO\EXTRAS\JPEG.
Note this uses the .obj files in D:\INFO\EXTRAS\JPEG\OBJ which are
compiled from the C code in D:\INFO\EXTRAS\JPEG\SRC.
The palette leak for JPEGs is only a problem when run on 256 colour
displays. The following was published by Greg Chapman on 16/02/98. I
can email the modified JPEG.PAS and .DCU if you require.
Regards,
Chris Roberts
================================================================
More on JPEG Unit leaves Palettes behind (Greg Chapman 16/02/98)
================================================================
There was a thread in this group back in December about GDI palettes not
being freed by the JPEG unit. A fix for one bug was posted by Xavier
Pacheco, but a second bug, which occurs when the JPEG's PixelFormat =
pf8Bit, did not have a fix posted. I would like to propose a temporary
fix here (a permanent fix requires modifying the VCL Graphics unit).
The leak occurs in the TJPEGImage.GetBitmap method in cases in which the
newly allocated FBitmap's PixelFormat is set to pf8Bit. In
TBitmap.SetPixelFormat, the pf8Bit parameter will result in a call to
CreateHalftonePalette, which returns a newly allocated GDI palette which
is then passed to TBitmap.CopyImage. CopyImage creates a new
TBitmapImage for the bitmap, and, in so doing, it creates a new copy of
the passed in palette (through the call to CopyPalette). The problem is
that the original copy (allocated in SetPixelFormat) is never freed.
As far as I can tell, there is no way to fix this palette leak without
modifying the Graphics unit (and thus forcing oneself to do without
packages). However, the leak can be limited to one palette per
application by adding the following routine to the JPEG unit:
var pf8BitBitmap: TBitmap = nil;
procedure Set8BitPixelFormat(ABitmap: TBitmap);
begin
if not Assigned(pf8BitBitmap) then begin
pf8BitBitmap:= TBitmap.Create;
pf8BitBitmap.PixelFormat:= pf8Bit;
end;
ABitmap.Assign(pf8BitBitmap);
end;
Then change the TJPEGImage.GetBitmap routine as follows:
// Set the bitmap pixel format
FBitmap.Handle := 0;
if (PixelFormat = jf8Bit) or (jc.d.out_color_space =
JCS_GRAYSCALE)
then
// FBitmap.PixelFormat := pf8bit {causes palette leak}
Set8BitPixelFormat(FBitmap)
else
FBitmap.PixelFormat := pf24bit;
Finally, include a call to pf8BitBitmap.Free in the unit's finalization
section.
All comments appreciatd. Thanks.
Greg Chapman
===================
Thanks for the info. I should have searched my CD and not just my
harddrive. I found the source on the CD and can hopefully figure out how to
get the .DCU compiled and in the right spot for Delphi, however before I
attempt this I have a question.
Does "TBitmap" use the jpeg code? I can find no reference to the
"TJPEGImage" object anywhere in the Delphi source. Therefore, I assumed,
when I read about the bug previously, that the palette leak would not affect
me. Note: I do sometimes use the 256 color display mode when testing for
potential client configurations.
Thanks,
Robert
Chris Roberts wrote in message <369a05f8...@forums.inprise.com>...
>Thanks for the info. I should have searched my CD and not just my
>harddrive. I found the source on the CD and can hopefully figure out how to
>get the .DCU compiled and in the right spot for Delphi, however before I
>attempt this I have a question.
>
>Does "TBitmap" use the jpeg code? I can find no reference to the
>"TJPEGImage" object anywhere in the Delphi source. Therefore, I assumed,
>when I read about the bug previously, that the palette leak would not affect
>me. Note: I do sometimes use the 256 color display mode when testing for
>potential client configurations.
Robert,
As you can see below in the initialization code for the JPEG.PAS unit,
TJPEGImage is registered as a TPicture file format during run-time
startup. The method of registering file formats lets you add other 3rd
party add-ons such as TGIFImage to work with the standard Delphi3
TImage. You can work with the resulting TBitmap on screen or in memory,
leaving TJPEGImage to do all the conversion hard yakka to and from disk.
Greg Chapman's palette leak fix does not fully cure the problem. It
just limits the leak to one palette per application, not one palette per
JPEG loaded. By fixing JPEG.PAS and not GRAPHICS.PAS you can still use
packages.
Regards,
Chris Roberts
=================
initialization
InitDefaults;
TPicture.RegisterFileFormat('jpg', 'JPEG Image File', TJPEGImage);
TPicture.RegisterFileFormat('jpeg', 'JPEG Image File', TJPEGImage);
finalization
TPicture.UnregisterGraphicClass(TJPEGImage);
if pf8BitBitmap <> nil then // palette bug fix Greg Chapman 15/02/98
pf8BitBitmap.Free;
end.
=================
I hope I am not being obtuse, but I still don't see that TBitmap is using
the jpeg code. MemProof is not reporting that I am leaking repeatedly for
each image and so I am guessing that TBitmap does not use TJPEGImage.
Note that, if jpeg.dcu is being used, then it would be too bad that there is
not a graphics.pas fix, for people like me who do not use packages.
However, eliminating the leaks down to one is better than running out of
resources.<g>
Thanks,
Robert
>I hope I am not being obtuse, but I still don't see that TBitmap is using
>the jpeg code. MemProof is not reporting that I am leaking repeatedly for
>each image and so I am guessing that TBitmap does not use TJPEGImage.
Roberts,
"I just use the stuff. I don't know how it works." ;-)
'My' way of explaining it is that TBitmap does not use TJPEGImage, but
the two objects have 'equivalences' which can be 'exchanged'. See code
below. TJPEGImage will only be used for JPEG images.
Regards,
Chris Roberts
==============
procedure TForm1.Button1Click(Sender: TObject);
begin
StatusBar1.SimpleText := '';
if OpenPicDialog1.Execute then
try
Image1.Picture.LoadFromFile(OpenPicDialog1.FileName);
Button2.Enabled := (Image1.Picture.Graphic is TBitmap);
Button3.Enabled := (Image1.Picture.Graphic is TJPEGImage);
Button4.Enabled := (Image1.Picture.Graphic is TGIFImage);
StatusBar1.SimpleText := OpenPicDialog1.FileName;
except
on EInvalidGraphic do MessageDlg('Invalid Graphic Format', mtError,
[mbOK],0);
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
JP : TJPEGImage;
begin
if Image1.Picture.Graphic is TBitmap then
begin
{Convert a Bitmap image to a JPEG image}
Jp := TJPEGImage.Create;
try
Jp.Assign(Image1.Picture.Graphic);
Jp.SaveToFile('c:\bmp2jpeg.jpg');
finally
Jp.Free;
end;
end;
end;
=======================
This is a very nice feature of Delphi. TPicture.RegisterFileFormat
tells TPicture what graphics types have been registered for TImage to
manipulate -- you supply the file extension, the english name of the
format, and the class that implements the routines to read the format:
TPicture.RegisterFileFormat('jpg', 'JPEG Image File', TJPEGImage);
Erik
I suppose that's just the wonder of object orientation.
By adding the JPEG unit to the project, Delphi inherits the ability to
handle JPEG images and adds it to its existing knowledge and methods
for handling TImages.
So we just carry on using TImage but Delphi now knows what to do with
JPEGs. Clever isn't it? Not that I really understand it either :-)
I wonder how many other people (like me) don't really understand or
use the object oriented features of Delphi to the full?
Steve
--
Steve Gouldstone, Helpburger: the easy to use
and affordable Windows Help authoring tool.
http://www.euro-share.com/langdale/helpburger.htm
Robert