Timage gets white and bitmap has size 0 bytes - delphi

I have some data stored inside my TImage Component. I want to save the image as an bitmap. Executing this code the TImage content gets white and only a bmp file with 0 bytes has been created on the harddisk. What is wrong with my code ?
MainStatusbar.SimpleText := 'save the image .... ';
if SaveDialog.Execute then
begin
Image1.picture.Bitmap.SaveToFile(SaveDialog.filename);
end;
MainStatusbar.SimpleText := 'done ';

TPicture is a container for multiple different types of images. If the current image is not a TBitmap, then Picture.Bitmap will not contain your image. When you refer to Picture.Bitmap your original image will be destroyed, and an empty TBitmap created. So, the obvious explanation in that Picture.Bitmap is empty when SaveToFile() is called.
You should be saving your image by calling SaveToFile on the Picture object instead:
Image1.Picture.SaveToFile(...);

If the original image is not a bitmap then calling Picture.Bitmap will erase the content and create an empty bitmap. Depending on the original picture format an automatic conversion (e.g. from an icon) may be possible, but has to be done outside of TImage.

If the TImage.Picture.Graphic property does not currently hold a TBitmap then accessing the TImage.Picture.Bitmap property will free the current Graphic and replace it with a blank TBitmap. This is documented behavior.
Since you want to save a bitmap, check if the current Graphic is already a TBitmap. If so, save it as-is. Otherwise create a temp TBitmap, assign the current Graphic to it, and then save it.
MainStatusbar.SimpleText := 'save the image .... ';
if SaveDialog.Execute then
begin
if Image1.Picture.Graphic is TBitmap then
Image1.Picture.Bitmap.SaveToFile(SaveDialog.FileName)
else
begin
Tmp := TBitmap.Create;
try
Tmp.Assign(Image1.Picture.Graphic);
Tmp.SaveToFile(SaveDialog.FileName);
finally
Tmp.Free;
end;
end;
end;
MainStatusbar.SimpleText := 'done ';

Related

How to convert delphi TImageList to TImageCollection programmatically?

I want to assign the existing TImageList Handle to TImageCollection so that I can use my TImagecollection with TvirtualImageList.
Here FormSet.SmallImageListHandle is a TImageList which is loading images from some other modules but I want copy these images to TvirtualImageList without touching the deeper layer in my codebase for FormSet.SmallImageListHandle.
Below is a sample code I have tried but didn't get success yet. Need to know if somehow I can assign Images to ImCol ?
Images := TImageList.Create(nil); // This is Timagelist
ImCol := TImageCollection.Create(nil);
imgclIte := TImageCollectionItem.Create(nil);
try
Images.Handle := FormSet.SmallImageListHandle;
//this line is existing code used as Timagelist
// need to assign this to Imagecollection
//ImCol.
Images.ShareImages := TRUE;
//FormIconsImageList.Images
// FormIconsImageListOld.AddImages(Images); // Old Approach with TImageList
FormIconsImageList.ImageCollection := ImCol; // Eventually I will set this
//Timagecollection to TvirtualImageList for Icons replacement

How to save a TImage containing a TPngImage as Bitmap file?

In Delphi 10.4, I have loaded a PNG image (32BPP with Alpha Channel Transparency) at DESIGN-TIME in the Picture property of a TImage. Here is how it looks at run-time:
Here is a copy of the TImage component (which can be pasted at design-time in any Delphi VCL Application project):
object Image1: TImage
Left = 46
Top = 200
Width = 32
Height = 32
AutoSize = True
Center = True
Picture.Data = {
0954506E67496D61676589504E470D0A1A0A0000000D49484452000000200000
00200806000000737A7AF40000000473424954080808087C086488000006F749
44415478DAB557694C545714BE33C3BE8A0CEBB096224EA94241B16AACA68520
6DA1D1D485B00A1421DA0A36A9B64D9AFE68AA69A340451B4A41405903D6A5D4
0AB4285B59442236884C054640C080EC8475A6DF19670803B40C466F72F3DEBB
E7DC73BE77EED92EE78083195BB74A87310E872D1E52261E9D6409CD8FD9CB1A
9CD3EEF66C9B99E11800682FD62F9DBA3F34AE155CD9F212016C788500CCD2FB
12069002002FB8F2C1336658C9CCCC8C595B5B333E9FCF74747494D827262658
5F5F1FEBECEC64DDDDDD4C2291BC180011756DCCDDDD9DB9B8B8700C0D0DB781
F23EE69B988E98AB3149D300A608F32FCCC2D1D1D18AC6C646697D7D3D1B1F1F
7F7E001D1C4DDE9FF61BB8BABABA2158390E2B38AA625AA9544AE77672727232
A3ACAC4C72E7CE9DE703D06624E0D55B39D740F146B960311E7C7CEBE2FD1814
24C0D4126D6DED20ACA5606D06F4C778B791F3D7E211D4D2D2222A2C2C645353
532B03D0C2B7E5DDB35C2B81A04758F91CCF6A0827538FE15D909E9E3E3A3838
C8A2A3A3D53435351F81660E3C6E780AC1F32D9EB6E01BC6DC03BF28CECDCD55
02B12C0091B135EFAEA5300B020EE25C47F4F5F58F40681CBE33E16C41999999
32566F6F6FE6EAEA7A06B443A07D353636F60D9C541FDF4998FBB13685E9FBF0
E1C3E24B972E91655403D0A9BB9A57C45FC36EDDBAC56C6C6CC811AF41E07B10
10505C5C9CAD385B3B3B3BB66FDF3E3FD02E83562A168BDFA9ADAD65BEBEBE4C
4B4BEB14D663C91260DD585A5A2A229ACA51A008C3D0D0500AC32710C687996D
9293933B07060664341E8FC76263634DF0ECC1E7087CC3283E3E5E6A6E6E4EC0
084496DC12B538822D29292992E1E1E19501387AF4A8B58686861842FA6062D3
C4C44425F6C0C040261008C450640D808EA03FA410B4B5B5657BF7EED5E772B9
F7C839B13F0CE199565252B23C00B1BA1E2F47DD8C6133B3B7B77F1B024A20A0
1C7FB89D12CEFC41494A4F4FAF083C9EE0F1E9E8E8B8A170382B2B2B0627F507
2D934214FB8500285D16C03FE48482D7964F692B1CB0D0F6828282721500D800
80F085038015BEABA9A939BE2C80475AAB78D70C6CC98918D2F0699830069B63
E17C090B938A9A9A1A333636FE043CF1E0F901611B035F99A3D3319A98987882
5E047A596B6BEB0E959D70FDFAF5CCC7C7E7276C8EC0E688FCFCFC54C4B412BB
A9A929454A1814FD0C9E94F2F2F28FAAAAAAE6E854CC6262622CE00B5DA077F7
F4F408540680F8673B77EE3C0F2121D81C92969676A1B7B757891DF5821D3E7C
9852723A78322A2A2A422B2B2B957800500DA1494969020074560A200DC283B1
3918002EFE078040F06480E70200842C04101212C2B3B0B098067D1200B4570A
2019C2C3B1393C2F2FEF7C5B5B9B123BF508E1E1E107E445291500221602A023
803FD111407F8FE5F2D550439F97CB336106060674C671107E849C1085256161
9D4792A266E563F02490133E7DFA344691296950B644CA563861797B7BFB7625
00280F7F4F334EA81A93A671197B5D660154C326544395E34BC50100DFDFBE7D
FBD81C002C34F4E819BF7BD7C2698F437F4781C340E7AF5C297BA3896FC7BB6F
E9F45212D1D5AB57CB39A79E35A565542A2BAC5D867B579937A949669B843DA2
68C7818E7CB196D15BBFE959CBCC871856A4E2B2E9E9E91D30B192503A263426
73A9B8BFBFFFC6CCCC8C8C6664644447A448C522EC5F2B4BC5B1424BE66AA4CB
2A9E0CB1660B27B679F3E60388E314EEECCCEF82C1EE0FC71EDC1BFFACAC5126
04C54800211D10D03F32326272EEDC39250001010194F3A929B1C21FBE7AF6EC
D9564A44541151A8F4F1138DF206251CFDE2F9EBD7AF2B3B1E75B99191915C24
8A2A307A80311B9D6E007531F0581616164656E801CD140A6C9392923A868686
647B29CBC1C3F9EAEAEA149BC3C892ABE3E2E2A4F4E7FEFEFE0C8DCC5C399E9D
9DDD929A9A2A210B2EF27C373737E6E9E9B906CCB59806D81007109F5EB97285
098542CA8897B1EE47B9A0A8A8E8624343836C1FB5EA50F40180FC02DA1F6848
BC6EDEBCC976EFDE4DCAE71A12CC8DD5D5D52234AAB27D8B0050BADCB56B1773
7474F4C62729D3244BE08FA3807804B17E086B67B0968772BB3F2B2B4BB6CFCB
CB8BC0FF08DA41D0BE84654EA03493D9955A3294F0E29C9C9CB93BC352F731AA
DBD44030642C6F6CCEC3D49777C35F605266A1223089352B34A583D494464545
6920C15083608CE982B98E2D684AF103C5D9D9D96C7E815A12000D4A2A7E7E7E
CCC1C1C1099F19F3DAF276522207F5359CF1243C5D82B38EC45A22FD29E8DDA4
58CE5F8BBF0DEAEAEA12D131CE57FEBF0014C7E1E1E1C1B66EDDCA8573ADF462
42ADFB0980CBA8ABAB93504A86F32DD6A18A308AEF4D9B36316767670E2CB30D
20E65FCD8C481F9B773583F24228AE686E6E96C2E1D8C27CB162008A410D07B5
DF4B5D4EA9CF479F27BB9CC23919F2FCA25BD052E35F02ED3A5D68222C670000
000049454E44AE426082}
Proportional = True
end
Now, at run-time, I try to save this image as a BITMAP image file (.bmp):
procedure TForm1.btnSaveTImageToBitmapClick(Sender: TObject);
begin
Image1.Picture.Bitmap.SaveToFile('Y:\Downloads\test.bmp');
end;
But when I execute this code at run-time, something very strange happens: The TImage component VANISHES (it becomes apparently INVISIBLE!) and the created .bmp file has a ZERO size (0 bytes).
However, when instead of the above code I execute this code:
procedure TForm1.btnSaveTImageToBitmapClick(Sender: TObject);
begin
Image1.Picture.SaveToFile('Y:\Downloads\test.bmp');
end;
...then the resulting file is a .PNG file with a WRONG .BMP file extension!
So how can I save this image as a valid BITMAP (.BMP) file?
EDIT: The answer by #Andreas Rejbrand and #Remy Lebeau has provided extensive explanations and ways to solve the problem.
You must create a TBitmap and assign the Picture.Graphic to it:
procedure TForm3.btnSaveClick(Sender: TObject);
var
bm: TBitmap;
begin
bm := TBitmap.Create;
try
bm.Assign(Image1.Picture.Graphic);
bm.SaveToFile('C:\Users\Andreas Rejbrand\Desktop\bitmap.bmp');
finally
bm.Free;
end;
end;
Your approach:
Image1.Picture.Bitmap.SaveToFile('Y:\Downloads\test.bmp');
doesn't work because the Picture doesn't contain a bitmap. From the documentation of the TPicture.Bitmap property:
Use Bitmap to reference the picture object when it contains a bitmap. If Bitmap is referenced when the picture contains a Metafile or Icon graphic, the graphic won't be converted (Types of Graphic Objects). Instead, the original contents of the picture are discarded and Bitmap returns a new, blank bitmap.
This approach:
Image1.Picture.SaveToFile('Y:\Downloads\test.bmp');
does exactly what it is supposed to do. It saves the Picture.Graphic as-is, which happens to be a PNG image in your case, to the file you specified. You chose a strange extension for a PNG image, but that's not something the VCL tries to correct.
Handling PNG transparency
If the PNG file has an alpha channel, bm.Assign will very faithfully create a bitmap image with an alpha channel. That's great, in one sense, because then you don't lose any information: the BMP you get contains all graphic data from the PNG, including the entire alpha channel. So you can, in principle, render this BMP onto any background and will look as nice as the PNG would look.
But in another way, it's not that great, after all. Because almost no image viewers or editors support BMPs with alpha channels. These applications will probably ignore the alpha channel, effectively making every pixel fully opaque. That will look horrible.
So if you want to create a normal BMP, without alpha channel, you need to "render" the PNG, using its alpha channel, onto a background of your choice, and then save the non-transparent result. The BMP you get will not contain the alpha channel of the original PNG, so you lose information. The BMP will not be transparent. For instance, if you draw it onto a white background, you will always have this white rectangle behind your icon/subject, even if you place it on a red area of the screen.
procedure TForm3.Image1Click(Sender: TObject);
var
bm: TBitmap;
begin
bm := TBitmap.Create;
try
bm.SetSize(Image1.Picture.Width, Image1.Picture.Height);
bm.Canvas.Brush.Color := clSkyBlue; {*}
bm.Canvas.FillRect(Rect(0, 0, bm.Width, bm.Height)); {*}
bm.Canvas.Draw(0, 0, Image1.Picture.Graphic);
bm.SaveToFile('C:\Users\Andreas Rejbrand\Desktop\bitmap2_1.bmp');
finally
bm.Free;
end;
end;
The lines with asterisks (*) can be omitted if you are happy with the default background color, which is white.

Why does rendered content of a TWebBrowser saved as JPEG loses quality?

I use the procedure below to create a JPG file from a TWebbrowser
That is resulting in a JPG looking OK
Then I load this JPG to a TcxImage control from DevExpress in order to print it. And that messes up my image so it isn't possible to see the map (it is a portion of a map from Google Maps)
The code for loading the image is
imgPrint.Picture.LoadFromFile(lImage);
I don't quite get why this is looking so bad already on screen.
I do it this way in order to be able to print the map.
It could also be done direct from the TWebBrowser but ther I have no control of the output size and adding my own headers and footers are tricky.
procedure TfrmJsZipExplorer.actSaveExecute(Sender: TObject);
var
ViewObject : IViewObject;
r : TRect;
Bitmap: TBitmap;
begin
if WebBrowser1.Document <> nil then
begin
WebBrowser1.Document.QueryInterface(IViewObject, ViewObject) ;
if Assigned(ViewObject) then
try
Bitmap := TBitmap.Create;
try
r := Rect(0, 0, WebBrowser1.Width, WebBrowser1.Height) ;
Bitmap.Height := WebBrowser1.Height;
Bitmap.Width := WebBrowser1.Width;
ViewObject.Draw(DVASPECT_CONTENT, 1, nil, nil, Application.Handle, bitmap.Canvas.Handle, #r, nil, nil, 0);
with TJPEGImage.Create do
try
Assign(Bitmap);
SaveToFile(lImagefile);
finally
Free;
end;
finally
Bitmap.Free;
end;
finally
ViewObject._Release;
end;
end;
end;
How to improve a saved JPEG image quality ?
You may set the CompressionQuality property of your saved image to the lowest compression, but highest image quality value. That will improve visual quality of the output image. Setting this property to 100 will result in better image quality, but larger file size:
with TJPEGImage.Create do
try
Assign(Bitmap);
CompressionQuality := 100;
SaveToFile(lImagefile);
finally
Free;
end;
It is necessary to use JPEG format for this image archive ?
If you're not limited only to JPEG format for you image archive, consider to use a different format, such as PNG. If you'd decide to use a PNG format with TPNGImage class, there's the CompressionLevel property, which allows you to specify the compression level of a saved image and which directly affects the size of the output file, but unlike the JPEG format compression with keeping the same visual quality. Setting this property to 9 will result in full compression to be used, which produces just smaller file size, the quality remains same as if no compression (0 value) would be used:
uses
PNGImage;
with TPNGImage.Create do
try
Assign(Bitmap);
CompressionLevel := 9;
SaveToFile(lImagefile);
finally
Free;
end;

How to load a transparent Image from ImageList?

I want to load a picture (32 bit-depth, transparent) from a TImageList to an TImage. The standard approach would be ImageList.GetBitmap(Index, Image.Picture.Bitmap);. However the GetBitmap method doesn't work with transparency, so I always get a non-transparent bitmap.
The workaround is rather simple - ImageList offers another method, GetIcon, which works OK with transparency. Code to load a transparent Image would be:
ImageList.GetIcon(Index, Image.Picture.Icon);
And don't forget to set proper ImageList properties:
ImageList.ColorDepth:=cd32bit;
ImageList.DrawingStyle:=dsTransparent;
I too have had various issues with passing in images from the a tImageList. So I have a simple wrapper routine that generally does the job and it enforces the transparency. The code below is Delphi 2005 and imlActiveView is the tImageList component that has my set of button glyph images.
procedure TfrmForm.LoadBitmap (Number : integer; bmp : tBitMap);
var
ActiveBitmap : TBitMap;
begin
ActiveBitmap := TBitMap.Create;
try
imlActiveView.GetBitmap (Number, ActiveBitmap);
bmp.Transparent := true;
bmp.Height := ActiveBitmap.Height;
bmp.Width := ActiveBitmap.Width;
bmp.Canvas.Draw (0, 0, ActiveBitmap);
finally
ActiveBitmap.Free;
end
end;
Here is an example of use where the 5th imlActiveView image is passed into the btnNavigate.Glyph.
LoadBitmap (5, btnNavigate.Glyph)

Delphi - Populate an imagelist with icons at runtime 'destroys' transparency

I've spended hours for this (simple) one and don't find a solution :/
I'm using D7 and the TImageList. The ImageList is assigned to a toolbar.
When I populate the ImageList at designtime, the icons (with partial transparency) are looking fine.
But I need to populate it at runtime, and when I do this the icons are looking pretty shitty - complete loose of the partial transparency.
I just tried to load the icons from a .res file - with the same result.
I've tried third party image lists also without success.
I have no clue what I could do :/
Thanks 2 all ;)
edit:
To be honest I dont know exactly whats going on. Alpha blending is the correkt term...
Here are 2 screenies:
Icon added at designtime:
(source: shs-it.de)
Icon added at runtime:
(source: shs-it.de)
Your comment that alpha blending is not supported just brought the solution:
I've edited the image in an editor and removed the "alpha blended" pixels - and now it looks fine.
But its still strange that the icons look other when added at runtime instead of designtime. If you (or somebody else ;) can explain it, I would be happy ;)
thanks for you support!
To support alpha transparency, you need to create the image list and populate it at runtime:
function AddIconFromResource(ImageList: TImageList; ResID: Integer): Integer;
var
Icon: TIcon;
begin
Icon := TIcon.Create;
try
Icon.LoadFromResourceID(HInstance, ResID);
Result := ImageList.AddIcon(Icon);
finally
Icon.Free;
end;
end;
function AddPngFromResource(ImageList: TImageList; ResID: Integer): Integer;
var
Png: TPngGraphic;
ResStream: TStream;
Bitmap: TBitmap;
begin
ResStream := nil;
Png := nil;
Bitmap := nil;
try
ResStream := TResourceStream.CreateFromID(HInstance, ResID, RT_RCDATA);
Png := TPNGGraphic.Create;
Png.LoadFromStream(ResStream);
FreeAndNil(ResStream);
Bitmap := TBitmap.Create;
Bitmap.Assign(Png);
FreeAndNil(Png);
Result := ImageList.Add(Bitmap, nil);
finally
Bitmap.Free;
ResStream.Free;
Png.Free;
end;
end;
// this could be e.g. in the form's or datamodule's OnCreate event
begin
// create the imagelist
ImageList := TImageList.Create(Self);
ImageList.Name := 'ImageList';
ImageList.DrawingStyle := dsTransparent;
ImageList.Handle := ImageList_Create(ImageList.Width, ImageList.Height, ILC_COLOR32 or ILC_MASK, 0, ImageList.AllocBy);
// populate the imagelist with png images from resources
AddPngFromResource(ImageList, ...);
// or icons
AddIconFromResource(ImageList, ...);
end;
I had the exact same problems a couple of years ago. It's a Delphi problem. I ended up putting the images in the list at design time, even though I really didn't want to. I also had to use a DevExpress image list to get the best results and to use 32 bit color images.
As Jeremy said this is indeed a Delphi limitation.
One work around I've used for images that I was putting onto buttons (PNGs with alpha transparency in my case) is to store the PNGs as resources, and at run time paint them onto a button sized bitmap filled with clBtnFace. The bitmap was then used as the control's glyph.
Delphi's built in support for icons with alpha masks is very limited, however there's an excellent icon library kicon which may help.

Resources