Delphi中保存图像列表

原创 2001年06月10日 23:28:00

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

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 中调试运行通过。

Delphi中保存图像列表

  • zgqtxwd
  • zgqtxwd
  • 2008年04月30日 22:42
  • 136

Delphi 对象列表使用

最近学习了ObjectList对象的使用方法,记录如下: 首先在单元头引入Contnrs单元 然后下面以一个简单的列子说明一下,示例:是创建多个TstringList对象,将每个对像放入对象列表中...
  • yolanda_luo
  • yolanda_luo
  • 2014年08月19日 10:53
  • 1137

GDI+ 在Delphi程序的应用 -- 多帧(页)图像的分解与合成

GDI+ 在Delphi程序的应用 -- 多帧(页)图像的分解与合成        在GDI+支持的各种图像格式,gif格式和tiff格式图像可包含多帧(页)图片,GDI+可以很方便的分解和合成多帧(...
  • maozefa
  • maozefa
  • 2007年12月21日 00:14
  • 6281

Delphi 字符串/内存流/文件的转换

Delphi 1 把字符串直接保存为文件的方法 2 将文件直接作为字符串读出的方法 3 把字符串转化为内存流的方法 4 把内存流转化为字符串的方法...
  • u011558122
  • u011558122
  • 2016年08月11日 16:27
  • 1185

delphi 把图片存入数据库

procedure TForm1.Button1Click(Sender: TObject); // 插入图片过程var  Stream:TMemoryStream;begin  try    Str...
  • wuheng66888
  • wuheng66888
  • 2006年05月10日 11:50
  • 2132

tchart 保存为图像

 很容易实现的,先用Chart1->TeeCreateBitmap()返回是BITMAP的类型,有这个不就成了吗?或者有个更好的的办法,  Chart1->CopyToClipboardBitmap(...
  • yunqian09
  • yunqian09
  • 2010年02月15日 16:25
  • 4102

Delphi中存储二维数组的方法

今天突然用到Delphi中的二维数组,本来想用二维数组来存储用户的权限去控制登陆界面后的若干菜单子项的,可是发现用数据库存储二维数组还需要经过一些转化,于是想了个笨方法,在数据库中把二维数组转换为St...
  • csli888
  • csli888
  • 2011年01月15日 10:13
  • 780

字符串保存为 TXT文件

procedure TForm1.Timer1Timer(Sender: TObject);var    afile:   TFileStream;    //DateTime : TDateTime...
  • yunqian09
  • yunqian09
  • 2010年02月21日 13:34
  • 4009

Delphi经典实例11------特殊字符处理

如下图所示建立工程:代码如下:unit mainunit;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics...
  • kunshan_shenbin
  • kunshan_shenbin
  • 2010年05月25日 14:42
  • 573

MFC控件(四)(图像列表控件CImageList)

CImageList图像列表控件: 用于为其他控件添加图标 以CImageList的形式存在,使用前先创建。 1、在全局区域或对话框类中定义一CImageList对象(常作为对话框成员变量) ...
  • m372897500
  • m372897500
  • 2012年03月08日 16:41
  • 1123
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Delphi中保存图像列表
举报原因:
原因补充:

(最多只允许输入30个字)