如何使用 App Tethering 从服务器获取图像
How to Get Images From Server using App Tethering
我有 2 个应用程序让我们调用服务器和客户端。
我正在使用 Delphi-xe8。应用程序 -> 多设备应用程序
双方使用:App tethering[tManager,tAProfile]、SQLite 数据库。
在服务器 SQLite 数据库中,我有 6 张图片。我想在客户端查看该图像。
在客户端我有 6 个 [TImage]。
当我单击按钮时 'Get Image List' 我得到 6 张具有相同视图的图像。
我想要 6 张图像以不同的方式查看。->[从服务器数据库获取]
客户端"Get Image List"按钮代码:
procedure TForm1.GetImgLstClick(Sender: TObject);
begin
tAProfile.SendString(tManager.RemoteProfiles.First,'GetImages','');
end;
服务器收到代码:
procedure TForm2.tAProfileResourceReceived(const Sender: TObject;
const AResource: TRemoteResource);
var
MS1:TMemorystream;
begin
if AResource.Hint='GetImages' then
begin
MS1:=TMemorystream.Create;
rQuery.Close;
rQuery.SQL.Clear;
rQuery.SQL.Add('select image from users');
rQuery.Open;
while not rQuery.Eof do
begin
tblobField(rQuery.FieldByName('image')).SaveToStream(MS1);
Image1.Bitmap:=nil;
rQuery.Next;
end;
tAProfile.SendStream(tManager.RemoteProfiles.First,'SendImages',MS1);
end;
end;
客户收到代码:
procedure TForm1.tAProfileResourceReceived(const Sender: TObject;
const AResource: TRemoteResource);
var
MS:TMemoryStream;
begin
if AResource.Hint='SendImages' then
begin
Image1.Bitmap.LoadFromStream(AResource.Value.AsStream);
Image2.Bitmap.LoadFromStream(AResource.Value.AsStream);
Image3.Bitmap.LoadFromStream(AResource.Value.AsStream);
Image4.Bitmap.LoadFromStream(AResource.Value.AsStream);
Image5.Bitmap.LoadFromStream(AResource.Value.AsStream);
Image6.Bitmap.LoadFromStream(AResource.Value.AsStream);
end;
end;
更新: 我从你最近的评论中得知你想发送你的
图片 one-by-one.
一个问题是 Delphi 数据集的 TGraphicField 支持多种格式
这可能是可变大小的,所以如果你只是将它们写入服务器的出站
流,客户端无法知道在读取流时,
一个图像的数据结束,下一个图像开始。一个简单的解决方案是
服务器在写入图像的大小之前将图像的大小写入流
数据到流中,并获取客户端的代码来读取图像大小,以便它
知道后面有多少是图像的数据。
我要回到我发布给你的另一个问题 () 的答案,它使用 TClientDataSets,
但对其进行调整,使其仅发送流中的图像(及其大小)。这
代码仍然非常简单,原则上应该与使用 FireDAC 数据集和 Sqlite 数据没有什么不同 table:
服务器
procedure TApp1Form.SendImageStream;
var
StreamToSend,
ImageStream : TMemoryStream;
StreamedImageSize : Integer;
begin
StreamToSend := TMemoryStream.Create;
ImageStream := TMemoryStream.Create;
try
CDS1.DisableControls;
CDS1.First;
while not CDS1.Eof do begin
ImageStream.Clear;
CDS1Graphic.SaveToStream(ImageStream);
ImageStream.Position := 0;
StreamedImageSize := ImageStream.Size;
StreamToSend.Write(StreamedImageSize, SizeOf(Integer));
StreamToSend.CopyFrom(ImageStream, StreamedImageSize);
CDS1.Next;
end;
StreamToSend.Position := 0;
TetheringAppProfile1.Resources.FindByName('BioLife').Value := StreamToSend;
finally
CDS1.EnableControls;
ImageStream.Free;
end;
end;
客户
// Note: In the client, CDS1 has only two fields, one named ID which is an
// ftAutoInc field, and Graphic, which is a TGraphicField
procedure TApp2Form.TetheringAppProfile1Resources0ResourceReceived(const Sender:
TObject; const AResource: TRemoteResource);
var
ReceivedStream : TStream;
ImageStream : TMemoryStream;
ImageSize : Integer;
begin
AResource.Value.AsStream.Position := 0;
ReceivedStream := AResource.Value.AsStream;
ImageStream := TMemoryStream.Create;
try
if CDS1.Active then
CDS1.EmptyDataSet // discard existing data
else
CDS1.CreateDataSet;
CDS1.DisableControls;
while ReceivedStream.Position < ReceivedStream.Size - 1 do begin
ImageStream.Clear;
ReceivedStream.ReadBuffer(ImageSize, SizeOf(Integer));
ImageStream.CopyFrom(ReceivedStream, ImageSize);
CDS1.Insert;
TGraphicField(CDS1.FieldByName('Graphic')).LoadFromStream(ImageStream);
CDS1.Post;
end;
CDS1.First;
finally
ImageStream.Free;
CDS1.EnableControls;
end;
end;
原回答如下
我已经在回答您的问题 时向您展示了一种使用 TClientDataSets 在服务器和客户端应用程序之间移动图像的非常简单的方法。我假设您对 Delphi 编程有足够的了解,能够将数据从您的 Sqlite 数据库获取到 TCIentDataSet 中,但也许不是。
下面是我的另一个答案的服务器+客户端的代码,适用于使用 FireDAC 组件而不是 TClientDataSets。同样,它使用服务器数据集的 SaveToStream
方法将其数据保存到来自服务器的流和客户端的 LoadFromStream
。
请注意,客户端应用程序中只有两行代码。
FDApp1 代码:
type
TApp1Form = class(TForm)
TetheringManager1: TTetheringManager;
TetheringAppProfile1: TTetheringAppProfile;
DBImage1: TDBImage;
btnConnect: TButton;
Label1: TLabel;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
DBNavigator1: TDBNavigator;
btnSendStream: TButton;
FDConnection1: TFDConnection;
FDQuery1: TFDQuery;
FDGUIxWaitCursor1: TFDGUIxWaitCursor;
FDStanStorageBinLink1: TFDStanStorageBinLink;
procedure btnConnectClick(Sender: TObject);
procedure btnSendStreamClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure TetheringManager1PairedToRemote(const Sender: TObject; const
AManagerInfo: TTetheringManagerInfo);
private
procedure DataSetToStream;
end;
[...]
procedure TApp1Form.btnConnectClick(Sender: TObject);
begin
TetheringManager1.AutoConnect;
end;
procedure TApp1Form.btnSendStreamClick(Sender: TObject);
begin
DataSetToStream;
end;
procedure TApp1Form.FormCreate(Sender: TObject);
begin
Caption := Format('App1 : %s', [TetheringManager1.Identifier]);
FDQuery1.LoadFromFile('D:\D10\Samples\Data\BioLife.FDS');
end;
procedure TApp1Form.TetheringManager1PairedToRemote(const Sender: TObject; const
AManagerInfo: TTetheringManagerInfo);
begin
Label1.Caption := Format('Connected : %s %s',
[AManagerInfo.ManagerIdentifier,
AManagerInfo.ManagerName]);
end;
procedure TApp1Form.DataSetToStream;
var
Stream : TMemoryStream;
begin
Stream := TMemoryStream.Create;
FDQuery1.SaveToStream(Stream);
Stream.Position := 0;
TetheringAppProfile1.Resources.FindByName('BioLife').Value := Stream;
end;
FDApp2 代码:
type
TApp2Form = class(TForm)
TetheringManager1: TTetheringManager;
TetheringAppProfile1: TTetheringAppProfile;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
DBNavigator1: TDBNavigator;
DBImage1: TDBImage;
FDGUIxWaitCursor1: TFDGUIxWaitCursor;
FDMemTable1: TFDMemTable;
FDStanStorageBinLink1: TFDStanStorageBinLink;
procedure TetheringAppProfile1Resources0ResourceReceived(const Sender: TObject;
const AResource: TRemoteResource);
public
end;
[...]
procedure TApp2Form.TetheringAppProfile1Resources0ResourceReceived(const Sender:
TObject; const AResource: TRemoteResource);
begin
AResource.Value.AsStream.Position := 0;
FDMemTable1.LoadFromStream(AResource.Value.AsStream);
end;
当然,在客户端,如果出于某种原因你想要将图像(而不是其他服务器数据)复制到另一个数据集中,你可以通过 row-by-row 复制来实现,类似于在你的问题中输入代码。
我有 2 个应用程序让我们调用服务器和客户端。
我正在使用 Delphi-xe8。应用程序 -> 多设备应用程序
双方使用:App tethering[tManager,tAProfile]、SQLite 数据库。
在服务器 SQLite 数据库中,我有 6 张图片。我想在客户端查看该图像。
在客户端我有 6 个 [TImage]。
当我单击按钮时 'Get Image List' 我得到 6 张具有相同视图的图像。
我想要 6 张图像以不同的方式查看。->[从服务器数据库获取]
客户端"Get Image List"按钮代码:
procedure TForm1.GetImgLstClick(Sender: TObject);
begin
tAProfile.SendString(tManager.RemoteProfiles.First,'GetImages','');
end;
服务器收到代码:
procedure TForm2.tAProfileResourceReceived(const Sender: TObject;
const AResource: TRemoteResource);
var
MS1:TMemorystream;
begin
if AResource.Hint='GetImages' then
begin
MS1:=TMemorystream.Create;
rQuery.Close;
rQuery.SQL.Clear;
rQuery.SQL.Add('select image from users');
rQuery.Open;
while not rQuery.Eof do
begin
tblobField(rQuery.FieldByName('image')).SaveToStream(MS1);
Image1.Bitmap:=nil;
rQuery.Next;
end;
tAProfile.SendStream(tManager.RemoteProfiles.First,'SendImages',MS1);
end;
end;
客户收到代码:
procedure TForm1.tAProfileResourceReceived(const Sender: TObject;
const AResource: TRemoteResource);
var
MS:TMemoryStream;
begin
if AResource.Hint='SendImages' then
begin
Image1.Bitmap.LoadFromStream(AResource.Value.AsStream);
Image2.Bitmap.LoadFromStream(AResource.Value.AsStream);
Image3.Bitmap.LoadFromStream(AResource.Value.AsStream);
Image4.Bitmap.LoadFromStream(AResource.Value.AsStream);
Image5.Bitmap.LoadFromStream(AResource.Value.AsStream);
Image6.Bitmap.LoadFromStream(AResource.Value.AsStream);
end;
end;
更新: 我从你最近的评论中得知你想发送你的 图片 one-by-one.
一个问题是 Delphi 数据集的 TGraphicField 支持多种格式 这可能是可变大小的,所以如果你只是将它们写入服务器的出站 流,客户端无法知道在读取流时, 一个图像的数据结束,下一个图像开始。一个简单的解决方案是 服务器在写入图像的大小之前将图像的大小写入流 数据到流中,并获取客户端的代码来读取图像大小,以便它 知道后面有多少是图像的数据。
我要回到我发布给你的另一个问题 (
服务器
procedure TApp1Form.SendImageStream;
var
StreamToSend,
ImageStream : TMemoryStream;
StreamedImageSize : Integer;
begin
StreamToSend := TMemoryStream.Create;
ImageStream := TMemoryStream.Create;
try
CDS1.DisableControls;
CDS1.First;
while not CDS1.Eof do begin
ImageStream.Clear;
CDS1Graphic.SaveToStream(ImageStream);
ImageStream.Position := 0;
StreamedImageSize := ImageStream.Size;
StreamToSend.Write(StreamedImageSize, SizeOf(Integer));
StreamToSend.CopyFrom(ImageStream, StreamedImageSize);
CDS1.Next;
end;
StreamToSend.Position := 0;
TetheringAppProfile1.Resources.FindByName('BioLife').Value := StreamToSend;
finally
CDS1.EnableControls;
ImageStream.Free;
end;
end;
客户
// Note: In the client, CDS1 has only two fields, one named ID which is an
// ftAutoInc field, and Graphic, which is a TGraphicField
procedure TApp2Form.TetheringAppProfile1Resources0ResourceReceived(const Sender:
TObject; const AResource: TRemoteResource);
var
ReceivedStream : TStream;
ImageStream : TMemoryStream;
ImageSize : Integer;
begin
AResource.Value.AsStream.Position := 0;
ReceivedStream := AResource.Value.AsStream;
ImageStream := TMemoryStream.Create;
try
if CDS1.Active then
CDS1.EmptyDataSet // discard existing data
else
CDS1.CreateDataSet;
CDS1.DisableControls;
while ReceivedStream.Position < ReceivedStream.Size - 1 do begin
ImageStream.Clear;
ReceivedStream.ReadBuffer(ImageSize, SizeOf(Integer));
ImageStream.CopyFrom(ReceivedStream, ImageSize);
CDS1.Insert;
TGraphicField(CDS1.FieldByName('Graphic')).LoadFromStream(ImageStream);
CDS1.Post;
end;
CDS1.First;
finally
ImageStream.Free;
CDS1.EnableControls;
end;
end;
原回答如下
我已经在回答您的问题
下面是我的另一个答案的服务器+客户端的代码,适用于使用 FireDAC 组件而不是 TClientDataSets。同样,它使用服务器数据集的 SaveToStream
方法将其数据保存到来自服务器的流和客户端的 LoadFromStream
。
请注意,客户端应用程序中只有两行代码。
FDApp1 代码:
type
TApp1Form = class(TForm)
TetheringManager1: TTetheringManager;
TetheringAppProfile1: TTetheringAppProfile;
DBImage1: TDBImage;
btnConnect: TButton;
Label1: TLabel;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
DBNavigator1: TDBNavigator;
btnSendStream: TButton;
FDConnection1: TFDConnection;
FDQuery1: TFDQuery;
FDGUIxWaitCursor1: TFDGUIxWaitCursor;
FDStanStorageBinLink1: TFDStanStorageBinLink;
procedure btnConnectClick(Sender: TObject);
procedure btnSendStreamClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure TetheringManager1PairedToRemote(const Sender: TObject; const
AManagerInfo: TTetheringManagerInfo);
private
procedure DataSetToStream;
end;
[...]
procedure TApp1Form.btnConnectClick(Sender: TObject);
begin
TetheringManager1.AutoConnect;
end;
procedure TApp1Form.btnSendStreamClick(Sender: TObject);
begin
DataSetToStream;
end;
procedure TApp1Form.FormCreate(Sender: TObject);
begin
Caption := Format('App1 : %s', [TetheringManager1.Identifier]);
FDQuery1.LoadFromFile('D:\D10\Samples\Data\BioLife.FDS');
end;
procedure TApp1Form.TetheringManager1PairedToRemote(const Sender: TObject; const
AManagerInfo: TTetheringManagerInfo);
begin
Label1.Caption := Format('Connected : %s %s',
[AManagerInfo.ManagerIdentifier,
AManagerInfo.ManagerName]);
end;
procedure TApp1Form.DataSetToStream;
var
Stream : TMemoryStream;
begin
Stream := TMemoryStream.Create;
FDQuery1.SaveToStream(Stream);
Stream.Position := 0;
TetheringAppProfile1.Resources.FindByName('BioLife').Value := Stream;
end;
FDApp2 代码:
type
TApp2Form = class(TForm)
TetheringManager1: TTetheringManager;
TetheringAppProfile1: TTetheringAppProfile;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
DBNavigator1: TDBNavigator;
DBImage1: TDBImage;
FDGUIxWaitCursor1: TFDGUIxWaitCursor;
FDMemTable1: TFDMemTable;
FDStanStorageBinLink1: TFDStanStorageBinLink;
procedure TetheringAppProfile1Resources0ResourceReceived(const Sender: TObject;
const AResource: TRemoteResource);
public
end;
[...]
procedure TApp2Form.TetheringAppProfile1Resources0ResourceReceived(const Sender:
TObject; const AResource: TRemoteResource);
begin
AResource.Value.AsStream.Position := 0;
FDMemTable1.LoadFromStream(AResource.Value.AsStream);
end;
当然,在客户端,如果出于某种原因你想要将图像(而不是其他服务器数据)复制到另一个数据集中,你可以通过 row-by-row 复制来实现,类似于在你的问题中输入代码。