当我第一次从 TClientDataSet 中读出图片数据时, 发现不是图片!
慢慢观察发现是前面多了 8 个字节(前 4 个字节是 01 00 00 01, 估计是格式标识和头大小; 后 4 个字节是后面图片文件的大小), 去掉这个 8 个字节就是图片文件了.
下面的例子先是检索了 20 个示例文件的所有图片字段, 并把其中的图片提取到指定文件夹;
还把一个指定字段中的图片显示在了窗体上.
//先在窗体上放 ClientDataSet1 和两个 Button uses IOUtils, Types; { 把示例文件中的所有图片提取到 C:\Temp\ } procedure TForm1.Button1Click(Sender: TObject); const DestPath = 'C:\Temp\'; var PathArr: TStringDynArray; Dir, Path: string; Field: TField; BmpName: string; begin { 获取范例文件列表 } Dir := GetEnvironmentVariable('CommonProgramFiles') + '\CodeGear Shared\Data\'; PathArr := TDirectory.GetFiles(Dir, '*.cds'); for Path in PathArr do { 分别处理每个文件 } begin ClientDataSet1.LoadFromFile(Path); for Field in ClientDataSet1.Fields do { 遍历每个字段 } begin Tag := 0; if (Field.DataType = ftGraphic) then { 如果是图片字段 } begin ClientDataSet1.First; while not ClientDataSet1.Eof do { 遍历每个记录 } begin if not Field.IsNull then { 如果字段不为空 } begin { 确定要保存的目录和文件名 } BmpName := TPath.GetFileNameWithoutExtension(Path); { 不带后缀的文件名 } BmpName := Format('%s%s_%.2d.bmp', [DestPath, BmpName, Tag]); Tag := Tag + 1; { 把图片数据提取到流, 删除前 8 个字节后保存 } with TBytesStream.Create(Field.AsBytes) do begin Move(Bytes[8], Bytes[0], Size - 8); SetSize(Size - 8); SaveToFile(BmpName); Free; end; end; ClientDataSet1.Next; end; end; end; end; end; { 把示范文件 biolife.xml 第一个记录中 Graphic 字段中的图片画在窗体上 } procedure TForm1.Button2Click(Sender: TObject); var Stream: TBytesStream; Bitmap: TBitmap; Path: string; begin Path := GetEnvironmentVariable('CommonProgramFiles') + '\CodeGear Shared\Data\biolife.xml'; ClientDataSet1.LoadFromFile(Path); Stream := TBytesStream.Create(ClientDataSet1.FieldByName('Graphic').AsBytes); Stream.Position := 8; Bitmap := TBitmap.Create; Bitmap.LoadFromStream(Stream); Canvas.Draw(10, 10, Bitmap); Bitmap.Free; Stream.Free; end;
这是提取到的图片: