在 Delphi 10.4 中流式传输的阵列
Array to Stream in Delphi 10.4
如何将“Array[0..9] of TJpegImage”保存并加载到 MemoryStream。
有很多示例将一个图像保存到流中,但没有一个保存数组。
我需要它将 Stream 保存到数据库 Blob 字段,然后将 BlobField 加载回我的数组。
数组中的所有图像具有相同的大小。
也许 TByte 流可以做到这一点?
但是如何将 TByte-Stream 转换回数组?
更新:
非常感谢 MBo 的示例。
我尝试使用它并遇到了一些问题。
我使用 Paintbox 绘制图片并在地址 0x000 的 0x0062b9ab:read 处发生访问冲突....
这是我尝试的代码:
单位PicToMemStream;
界面
使用
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls、Vcl.Forms、Vcl.Dialogs、Vcl.Imaging.jpeg、Vcl.ExtCtrls;
type
TForm1 = class(TForm)
Image1: TImage;
PaintBox: TPaintBox;
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
ms, temp: TMemoryStream;
jps: array of TJpegImage;
i, n, sz: Integer;
ProgPath: String;
begin
ProgPath := ExtractFilePath(Application.ExeName);
n := 3;
SetLength(jps, n);
ms := TMemoryStream.Create;
temp := TMemoryStream.Create;
for i := 0 to n - 1 do
begin
jps[i] := TJpegImage.Create;
jps[i].LoadFromFile(Format(ProgPath + '%s.jpg', [Chr(Ord('a') + i)]));
// in my case loads files a.jpg, b.jpg, c.jpg
end;
// Save Pictures to Stream and later in BlobField (100kByte)
try
ms.Write(n, SizeOf(n));
for i := 0 to n - 1 do
begin
temp.Clear;
// Save Image Data first here
jps[i].SaveToStream(temp); // jpeg data here
sz := temp.Size;
// Save length second here
ms.Write(sz, SizeOf(sz)); // size of image
temp.Position := 0;
ms.CopyFrom(temp, sz); // image data to final destination
end;
ms.SaveToFile(ProgPath + 'base.dat'); // for control // later here Write Data to BLob
// Read Picture and show it in a Paintbox or Image
// revert to empty stream
ms.Clear;
ms.LoadFromFile(ProgPath + 'base.dat'); // load from "base" // later here Read Data from Blob
ms.Read(n, SizeOf(n));
// here some actions to setup array
for i := 0 to n - 1 do // Read 3 times a picture
begin
ms.Read(sz, SizeOf(sz)); // Read Lenth of Picturedata first
temp.Clear; // Read Picturedata in jps[i]
temp.CopyFrom(ms, sz);
temp.Position := 0;
jps[i].LoadFromStream(temp);
Form1.PaintBox.Canvas.Draw(0, 0, jps[i]); // Show Picture with Error
//Form1.Image1.Picture.Bitmap.LoadFromStream(temp);
Sleep(2000); // To see the Picture for 2 seconds (Test)
end;
finally
ms.Free;
temp.Free;
for i := 0 to n - 1 do
jps[i].Free;
end;
end.
更新2:
我将代码放在 ButtomClick 过程中并更改:
temp.Position := 0;
jps[i].LoadFromStream(temp);
Form1.PaintBox.Canvas.Draw(0, 0, jps[i]); // Show Picture in Paintbox
Form1.Image1.Picture.Assign(jps[i]); // Show Picture in TImage
Application.ProcessMessages;
Sleep(500); // To see the Picture for 2 seconds (Test)
end;
我还将使用 Master-Detail Table 或 TFDMemTable 或 Encoding to Text 来测试其他想法,看看哪个最适合我。
感谢所有帮助者。
All Images in the Array has the same Size
- 也许维度 (width/height) 相同,但 jpeg 图像的大小(以字节为单位)因图片和压缩而异。所以我假设你需要存储图像数据和数据大小。
可能的方法:
- 将整数值 - 数组长度 - 写入内存流
ms
- 将每个数组元素保存到临时内存流
temp_ms
- 将整数值
sz = ms.size
写入主内存流ms
- 将
temp_ms.Position
重置为 0
- 复制 (
CopyFrom
) sz
个字节,从 temp_ms
到 ms
- 清楚
temp_ms
- 对所有数组元素重复
现在 ms
内容如下所示:
10 14212 FFD8....D9 31234 FFD8....D9
10 images
1st image size
1st image contents
2nd image size
2nd image contents
要检索图像,执行反向操作:
- 重置
ms
位置(如果需要)
- 从
ms
中读取图像数量 n
- 设置数组大小(如果数组是动态的)
n
次:
- 读取图片大小
sz
- 将
sz
字节复制到 temp_ms
- 重置
temp_ms.Position
- 从
temp_ms
加载 array[i]
工作示例:
var
ms, temp: TMemoryStream;
jps: array of TJpegImage;
i, n, sz: Integer;
begin
n := 3;
SetLength(jps, n);
ms := TMemoryStream.Create;
temp := TMemoryStream.Create;
for i := 0 to n - 1 do begin
jps[i] := TJpegImage.Create;
jps[i].LoadFromFile(Format('h:\%s.jpg', [Chr(Ord('a') + i)]));
//in my case loads files a.jpg, b.jpg, c.jpg
end;
try
ms.Write(n, SizeOf(n));
for i :=0 to n - 1 do begin
temp.Clear;
jps[i].SaveToStream(temp); //jpeg data here
sz := temp.Size;
ms.Write(sz, SizeOf(sz)); //size of image
temp.Position := 0;
ms.CopyFrom(temp, sz); //image data to final destination
end;
ms.SaveToFile('h:\base.dat'); //for control
//revert to empty stream
ms.Clear;
ms.LoadFromFile('h:\base.dat'); //load from "base"
ms.Read(n, SizeOf(n));
//here some actions to setup array
for i :=0 to n - 1 do begin
ms.Read(sz, SizeOf(sz));
temp.Clear;
temp.CopyFrom(ms, sz);
temp.Position := 0;
jps[i].LoadFromStream(temp);
Canvas.Draw(i * 200, 0, jps[i]); //control shot
end;
finally
ms.Free;
temp.Free;
for i := 0 to n - 1 do
jps[i].Free;
end;
你为什么不使用 TFDMemTable?
另一个选项可以是,TStringList使用System.NetEncoding.TNetEncoding.Base64编码
因为 TStringList 非常像一个超级向量
如何将“Array[0..9] of TJpegImage”保存并加载到 MemoryStream。 有很多示例将一个图像保存到流中,但没有一个保存数组。 我需要它将 Stream 保存到数据库 Blob 字段,然后将 BlobField 加载回我的数组。 数组中的所有图像具有相同的大小。 也许 TByte 流可以做到这一点? 但是如何将 TByte-Stream 转换回数组?
更新: 非常感谢 MBo 的示例。 我尝试使用它并遇到了一些问题。 我使用 Paintbox 绘制图片并在地址 0x000 的 0x0062b9ab:read 处发生访问冲突....
这是我尝试的代码:
单位PicToMemStream; 界面
使用 Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls、Vcl.Forms、Vcl.Dialogs、Vcl.Imaging.jpeg、Vcl.ExtCtrls;
type
TForm1 = class(TForm)
Image1: TImage;
PaintBox: TPaintBox;
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
ms, temp: TMemoryStream;
jps: array of TJpegImage;
i, n, sz: Integer;
ProgPath: String;
begin
ProgPath := ExtractFilePath(Application.ExeName);
n := 3;
SetLength(jps, n);
ms := TMemoryStream.Create;
temp := TMemoryStream.Create;
for i := 0 to n - 1 do
begin
jps[i] := TJpegImage.Create;
jps[i].LoadFromFile(Format(ProgPath + '%s.jpg', [Chr(Ord('a') + i)]));
// in my case loads files a.jpg, b.jpg, c.jpg
end;
// Save Pictures to Stream and later in BlobField (100kByte)
try
ms.Write(n, SizeOf(n));
for i := 0 to n - 1 do
begin
temp.Clear;
// Save Image Data first here
jps[i].SaveToStream(temp); // jpeg data here
sz := temp.Size;
// Save length second here
ms.Write(sz, SizeOf(sz)); // size of image
temp.Position := 0;
ms.CopyFrom(temp, sz); // image data to final destination
end;
ms.SaveToFile(ProgPath + 'base.dat'); // for control // later here Write Data to BLob
// Read Picture and show it in a Paintbox or Image
// revert to empty stream
ms.Clear;
ms.LoadFromFile(ProgPath + 'base.dat'); // load from "base" // later here Read Data from Blob
ms.Read(n, SizeOf(n));
// here some actions to setup array
for i := 0 to n - 1 do // Read 3 times a picture
begin
ms.Read(sz, SizeOf(sz)); // Read Lenth of Picturedata first
temp.Clear; // Read Picturedata in jps[i]
temp.CopyFrom(ms, sz);
temp.Position := 0;
jps[i].LoadFromStream(temp);
Form1.PaintBox.Canvas.Draw(0, 0, jps[i]); // Show Picture with Error
//Form1.Image1.Picture.Bitmap.LoadFromStream(temp);
Sleep(2000); // To see the Picture for 2 seconds (Test)
end;
finally
ms.Free;
temp.Free;
for i := 0 to n - 1 do
jps[i].Free;
end;
end.
更新2: 我将代码放在 ButtomClick 过程中并更改:
temp.Position := 0;
jps[i].LoadFromStream(temp);
Form1.PaintBox.Canvas.Draw(0, 0, jps[i]); // Show Picture in Paintbox
Form1.Image1.Picture.Assign(jps[i]); // Show Picture in TImage
Application.ProcessMessages;
Sleep(500); // To see the Picture for 2 seconds (Test)
end;
我还将使用 Master-Detail Table 或 TFDMemTable 或 Encoding to Text 来测试其他想法,看看哪个最适合我。 感谢所有帮助者。
All Images in the Array has the same Size
- 也许维度 (width/height) 相同,但 jpeg 图像的大小(以字节为单位)因图片和压缩而异。所以我假设你需要存储图像数据和数据大小。
可能的方法:
- 将整数值 - 数组长度 - 写入内存流
ms
- 将每个数组元素保存到临时内存流
temp_ms
- 将整数值
sz = ms.size
写入主内存流ms
- 将
temp_ms.Position
重置为 0 - 复制 (
CopyFrom
)sz
个字节,从temp_ms
到ms
- 清楚
temp_ms
- 对所有数组元素重复
现在 ms
内容如下所示:
10 14212 FFD8....D9 31234 FFD8....D9
10 images
1st image size
1st image contents
2nd image size
2nd image contents
要检索图像,执行反向操作:
- 重置
ms
位置(如果需要) - 从
ms
中读取图像数量 - 设置数组大小(如果数组是动态的)
n
次:- 读取图片大小
sz
- 将
sz
字节复制到temp_ms
- 重置
temp_ms.Position
- 从
temp_ms
加载
n
array[i]
工作示例:
var
ms, temp: TMemoryStream;
jps: array of TJpegImage;
i, n, sz: Integer;
begin
n := 3;
SetLength(jps, n);
ms := TMemoryStream.Create;
temp := TMemoryStream.Create;
for i := 0 to n - 1 do begin
jps[i] := TJpegImage.Create;
jps[i].LoadFromFile(Format('h:\%s.jpg', [Chr(Ord('a') + i)]));
//in my case loads files a.jpg, b.jpg, c.jpg
end;
try
ms.Write(n, SizeOf(n));
for i :=0 to n - 1 do begin
temp.Clear;
jps[i].SaveToStream(temp); //jpeg data here
sz := temp.Size;
ms.Write(sz, SizeOf(sz)); //size of image
temp.Position := 0;
ms.CopyFrom(temp, sz); //image data to final destination
end;
ms.SaveToFile('h:\base.dat'); //for control
//revert to empty stream
ms.Clear;
ms.LoadFromFile('h:\base.dat'); //load from "base"
ms.Read(n, SizeOf(n));
//here some actions to setup array
for i :=0 to n - 1 do begin
ms.Read(sz, SizeOf(sz));
temp.Clear;
temp.CopyFrom(ms, sz);
temp.Position := 0;
jps[i].LoadFromStream(temp);
Canvas.Draw(i * 200, 0, jps[i]); //control shot
end;
finally
ms.Free;
temp.Free;
for i := 0 to n - 1 do
jps[i].Free;
end;
你为什么不使用 TFDMemTable?
另一个选项可以是,TStringList使用System.NetEncoding.TNetEncoding.Base64编码 因为 TStringList 非常像一个超级向量