如何使用App Tethering从服务器获取图像

时间:2017-02-10 06:53:28

标签: delphi firemonkey delphi-xe8

我有2个应用程序让我们打电话给服务器和客户端。

我正在使用Delphi-xe8。应用程序 - >多设备应用程序

在双方使用:App tethering [tManager,tAProfile],SQLite数据库。

在Server SQLite数据库中,我有6张图片。我想在客户端查看该图像。

在客户端我已经6 [TImage]。

当我点击按钮'获取图像列表'时,我得到6张具有相同视图的图像。

我希望以不同的方式查看6张图片.-> [从服务器数据库获取]

Client Side

客户端“获取图片列表”按钮代码:

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;

1 个答案:

答案 0 :(得分:2)

更新:我从您最近的评论中收集到您要发送的内容 图像一个接一个。

问题是Delphi数据集的TGraphicField支持多种格式 它可能是可变大小的,所以如果你只是把它们写到服务器的出站 流,客户端没有办法知道,在读取流时,在哪里 一个图像的数据结束,下一个图像的数据开始。一个简单的解决方案就是拥有 服务器在写入图像之前将图像的大小写入流中 数据到流,并获取客户端的代码来读取图像大小 知道后面有多少是图像的数据。

我回到我发布到您使用TClientDataSets的其他q(Delphi: How to Get All Images From Server Database by using App tethering?)的答案, 但要对其进行调整,使其仅在流中发送图像(及其大小)。该 代码仍然非常简单,原则上与使用FireDAC数据集和Sqlite数据表没有区别:

服务器

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;

原始答案如下

我已经向您展示了一种在我对q Delphi: How to Get All Images From Server Database by using App tethering?的回答中使用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;

当然,在客户端,如果由于某种原因你想要将图像(但不是其他服务器数据)复制到另一个数据集中,你可以通过逐行复制来实现,类似于你的qs。