如何使用 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 复制来实现,类似于在你的问题中输入代码。