分享
 
 
 

Delphi中保存图像列表

王朝delphi·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

原作发表在计算机世界日报:

http://www.ccw.com.cn/htm/app/aprog/01_6_5_2.asp

Delphi中保存图像列表

蔡健

01-6-5 下午 02:07:11

最近在做项目时遇到将图像列表(TImageList)中一系列的图像保存到指定的文件或二进制流中,以便在需要时进行动态恢复的情况。于是在Delphi的帮助中查找TImageList类相关的属性、方法,遗憾的是Delphi在TImageList中并未提供SaveToFile和SaveToStream方法,所以针对TImageList目前的限制,必须采取其它的办法来扩展TImageList的功能,以满足实际项目的需要。

解决方法

方法一:

使用API函数ImageList_Write和ImageList_Read。二者都需要指定一个类型为IStream的参数,前者的作用是将指定句柄的图像列表保存到类型为IStream的二进制流中;后者是从类型为IStream的二进制流中读出原先保存的图像列表,并且返回指向这个图像列表的句柄。IStream是一个OLE对象,它在Delphi中的声明为TStreamAdapter = class(TInterfacedObject, IStream),意为TStreamAdapter是从TInterfacedObject继承下来的操纵 IStream接口的对象。通过TStreamAdapter对象可以实现Delphi内部TStream对象对ISTream接口对象的操纵。

方法二:

从TImageList继承一个子类TImageListEx,实现自定义的SaveToFileEx和SaveToStreamEx方法。在默认情况下TImageList中保存的图像是由普通图像及其掩码图像组合而成,所以必须调用其基类TCustomImageList的Protected部分提供的GetImages(Index: Integer; Image, Mask: TBitmap)方法,以获得图像列表中指定索引号的位图及其掩码位图,之后分别保存到自定义的文件或二进制流中,此外还需提供LoadFromFileEx和LoadFromStreamEx方法从自定义的文件或二进制流中恢复图像集合。

实现步骤

自定义的TImageListEx控件在Public部分一并实现了对上述两种方法的封装。

TImageListEx类源代码如下:

unit ImageListEx;

interface

uses Windows, SysUtils, Classes, Graphics, Controls, Commctrl, ImgList, Consts;

type

TImageListEx = class(TImageList)

public

procedure LoadFromFile(const FileName: string);//实现API方式保存

procedure LoadFromStream(Stream: TStream);

procedure SaveToFile(const FileName: string);

procedure SaveToStream(Stream: TStream);

procedure LoadFromFileEx(const FileName: string);//实现自定义方式保存

procedure LoadFromStreamEx(Stream: TStream);

procedure SaveToFileEx(const FileName: string);

procedure SaveToStreamEx(Stream: TStream);

end;

procedure Register;

implementation

procedure Register;

begin

RegisterComponents('ImageListEx', [TImageListEx]);

end;

{ TImageListEx }

procedure TImageListEx.LoadFromFile(const FileName: string);

var

Stream: TStream;

begin

Stream := TFileStream.Create(FileName, fmOpenRead);

try

LoadFromStream(Stream);

finally

Stream.Free;

end;

end;

procedure TImageListEx.LoadFromFileEx(const FileName: string);

var

Stream: TStream;

begin

Stream := TFileStream.Create(FileName, fmOpenRead);

try

LoadFromStreamEx(Stream);

finally

Stream.Free;

end;

end;

procedure TImageListEx.LoadFromStream(Stream: TStream);

var

SA: TStreamAdapter;

begin

SA := TStreamAdapter.Create(Stream);

try

Handle := ImageList_Read(SA);//将当前图像列表的句柄指向从二进制流中得到的句柄

if Handle = 0 then

raise EReadError.CreateRes(@SImageReadFail);

finally

SA.Free;

end;

end;

procedure TImageListEx.LoadFromStreamEx(Stream: TStream);

var

Width, Height: Integer;

Bitmap, Mask: TBitmap;

BinStream: TMemoryStream;

procedure LoadImageFromStream(Image: TBitmap);

var

Count: DWORD;

begin

Image.Assign(nil);

Stream.ReadBuffer(Count, SizeOf(Count));//首先读出位图的大小

BinStream.Clear;

BinStream.CopyFrom(Stream, Count);//接着读出位图

BinStream.Position := 0;//流指针复位

Image.LoadFromStream(BinStream);

end;

begin

Stream.ReadBuffer(Height, SizeOf(Height));

Stream.ReadBuffer(Width, SizeOf(Width));

Self.Height := Height;

Self.Width := Width;//恢复图像列表原来的高度、宽度

Bitmap := TBitmap.Create;

Mask := TBitmap.Create;

BinStream := TMemoryStream.Create;

try

while Stream.Position <> Stream.Size do

begin

LoadImageFromStream(Bitmap);//从二进制流中读出位图

LoadImageFromStream(Mask);//从二进制流中读出掩码位图

Add(Bitmap, Mask);//将位图及其掩码位图合并添加到图像列表中

end;

finally

Bitmap.Free;

Mask.Free;

BinStream.Free;

end;

end;

procedure TImageListEx.SaveToFile(const FileName: string);

var

Stream: TStream;

begin

Stream := TFileStream.Create(FileName, fmCreate);

try

SaveToStream(Stream);

finally

Stream.Free;

end;

end;

procedure TImageListEx.SaveToFileEx(const FileName: string);

var

Stream: TStream;

begin

Stream := TFileStream.Create(FileName, fmCreate);

try

SaveToStreamEx(Stream);

finally

Stream.Free;

end;

end;

procedure TImageListEx.SaveToStream(Stream: TStream);

var

SA: TStreamAdapter;

begin

SA := TStreamAdapter.Create(Stream);

try

if not ImageList_Write(Handle, SA) then//将当前图像列表保存到二进制流中

raise EWriteError.CreateRes(@SImageWriteFail);

finally

SA.Free;

end;

end;

procedure TImageListEx.SaveToStreamEx(Stream: TStream);

var

I: Integer;

Width, Height: Integer;

Bitmap, Mask: TBitmap;

BinStream: TMemoryStream;

procedure SetImage(Image: TBitmap; IsMask: Boolean);

begin

Image.Assign(nil);//清除上一次保存的图像,避免出现图像重叠

with Image do

begin

if IsMask then Monochrome := True;//掩码位图必须使用单色

Height := Self.Height;

Width := Self.Width;

end;

end;

procedure SaveImageToStream(Image: TBitmap);

var

Count: DWORD;

begin

BinStream.Clear;

Image.SaveToStream(BinStream);

Count := BinStream.Size;

Stream.WriteBuffer(Count, SizeOf(Count));//首先保存位图的大小

Stream.CopyFrom(BinStream, 0);//接着保存位图

end;

begin

Height := Self.Height;

Width := Self.Width;

Stream.WriteBuffer(Height, SizeOf(Height));//保存原图像列表的高度

Stream.WriteBuffer(Width, SizeOf(Width));//保存将原图像列表的宽度

Bitmap := TBitmap.Create;

Mask := TBitmap.Create;

BinStream := TMemoryStream.Create;

try

for I := 0 to Count - 1 do//遂一保存图像列表中的图像

begin

SetImage(Bitmap, False);

SetImage(Mask, True);

GetImages(I, Bitmap, Mask);//取得指定索引号的位图及其掩码位图

SaveImageToStream(Bitmap);//保存位图到二进制流中

SaveImageToStream(Mask);//保存掩码位图到二进制流中

end;

finally

Bitmap.Free;

Mask.Free;

BinStream.Free;

end;

end;

end.

下面示范在Delphi中的使用方法:

首先在Delphi中新建一个项目,然后在Form1上放置一个ImageListEx控件,一个TreeView控件和四个Button控件。将TreeView控件的Images属性与ImageListEx相关联,在ImageListEx中任意添加几幅图像,在TreeView中添加相应数量的项目,项目的ImageIndex属性分别对应于ImageListEx中图像的索引号。现在TreeView中每个项目之前已经能够显示出相应的图标。

最后,在Button1的OnClick事件中写上:

ImageListEx1.SaveToFile('C:\CJ.dat');

ImageListEx1.SaveToFileEx('C:\CJEx.dat');

在Button2的OnClick事件中写上:ImageListEx1.Clear;

在Button3的OnClick事件中写上:ImageListEx1.LoadFromFile('C:\CJ.dat');

在Button4的OnClick事件中写上:ImageListEx1.LoadFromFileEx('C:\CJEx.dat');

运行程序,首先单击Button1,之后单击Button2,最后任意单击Button3或Button4,可以看到程序能够将图像列表中的图像保存到指定的文件中,可以从指定的文件中正确的恢复并显示。

结束语

本文介绍的内容已用于解决本人在实际项目中遇到的情况,也希望同样遇到此问题的程序员能够从中找到答案。以上代码在 Delphi5.0、Windows2000 Server 中调试运行通过。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有