Envoi et réception d'une capture d'écran par streams avec les composants tcp indy

Description

Je dispose de Delphi 7 et je voulais créer une application capable d'envoyer une capture de mon écran à un ordinateur distant. Après avoir chercher un peu parmi les sources disponibles et après avoir tester quelques un, je n'ai pas trouver de solution convenant à mes besoins. Il y'a bien une source qui présente comment faire une application du style VNC mais il n'est pas précisé k'il faut pour pouvoir compiler ce code disposer de composants fastnet qui ont malheureusement disparus de la palette Delphi 7. Je propose donc ici un moyen très simple d'envoyer une capture d'écran par streaming à l'aide des composants Indy (fournis avec Delphi 7). Le principe est simple, le logiciel client crée une capture d'écran, la converti en jpg, l'enregistre dans un stream et l'envois par TCP. De son côté le logiciel serveur réceptionne le stream et le charge dans un coposant Timage. Le code présente juste la maniere d'envoyer et recevoir le stream, libre a vous de vous en servir comme bon vous semble, il est tt à fait possible de se servir du code dans l'autre sens, c'est à dire d'envoyer le stream depuis le serveur jusqu'au client après que le serveur ait recu une requette lui demandant d'envoyer l'image (moyennant peu être quelques modifications pas insurmontables même pour débutant). Le programme client se présente de cette maniere : c'est une form avec 2 boutons, un pour démarrer l'envois et l'autre pour l'arreter. Il y'a aussi 2 edits, un où l'on doit mettre l'ip du serveur distant et l'autre où l'on indique l'intreval des envois de capture d'écran "en ms" (la valeure de l'intreval de répétion du timer). dans le cas de l'envois du stream depuis le serveur jusqu'au client après la réception d'une requette il est plus commode de ne pas utiliser de timer, simplement d'envoyer une nouvelle requette pour une capture lors de la réception de la précédente. Attention ce deuxieme cas n'est pas abordé ici car ce n'est pas de cette fonction que j'avais besoin mais je la posterai sans doute en complément plus tard. Sinon le logiciel serveur contient un composant tcp server Indy et un composant Timage, c'est tout. Je sais je parle trop mais que voulez vous, on se refait pas ;)

Source / Exemple :


// Sources du client :

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
  IdTCPClient,jpeg, ExtCtrls;  //Ne pas oublier de déclarer la classe jpeg

type
  TForm1 = class(TForm)
    tcp: TIdTCPClient; //Composant tcp client de Indy
    Button1: TButton;
    Edit1: TEdit;
    Timer1: TTimer;
    Button2: TButton;
    Label1: TLabel;
    Edit2: TEdit;
    Label2: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure sendstr;
    procedure Timer1Timer(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.sendstr;  //Procedure de capture d'écran,conversion en jpg et envoi
var Img:TPicture;
MemStream:TMemoryStream; // Déclaration des variables
JPG:TJPEGImage;
Bmp :TBitMap;
Rect:TRect;

begin

   Img:=TPicture.Create;                         
   Bmp := TBitMap .Create; //Initialisation des variables qui doivent l'être
   MemStream:=TMemoryStream.Create;

     Img.Bitmap.Width:=Screen.Width;
       Img.Bitmap.Height:=Screen.Height;            
        BitBlt(Img.Bitmap.Canvas.Handle,0,0,Screen.Width,Screen.Height,GetDC(GetDesktopWindow),0,0,SrcCopy); //Capture de l'écran
                JPG:=TJPEGImage.Create;
             try
             JPG.Assign(Img.Bitmap);   //Conversion en jpg
             JPG.CompressionQuality:=15;
             Bmp.Width :=Jpg.Width -50;
             Bmp.Height :=Jpg.Height -50;
             Rect.Left :=0;
             Rect.Top :=0;
             Rect.Right :=Bmp.Width-1;
             Rect.Bottom:=Bmp.Height-1;
             Bmp.Canvas.StretchDraw(Rect,Jpg);
             Jpg.Assign(Bmp);
             jpg.savetostream(Memstream);//Chargement de l'image jpg dans le stream
             finally
             bmp.Free;
             img.free;
             JPG.Free;
        try
        with tcp do
        begin

        OpenWriteBuffer;
        WriteStream(memstream);//Envoi du stream
        CloseWriteBuffer;
        memstream.Free;
        disconnect; //Déconnexion
        end;
        except

        end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject); //Bouton pour démarrer l'envoi
begin
try
timer1.Interval:= strtoint(edit2.Text);//Définition de l'interval du timer
tcp.Host:= edit1.Text;  //Définition de l'hote (serveur)
timer1.Enabled:=true; //Démarrage du timer
except
end;
end;

procedure TForm1.Timer1Timer(Sender: TObject); //Procedure que le timer execute celon l                                                                              //'interval donné
begin
try
tcp.Connect; //Connexion du client tcp
form1.sendstr; //Execution de la procédure définie plus haut
except
timer1.Enabled:= false;  //Si la connexion est impossible on arrete le timer
showmessage('connextion impossible'); //On affiche une boite de dialogue qui nous informe

end;

end;

procedure TForm1.Button2Click(Sender: TObject); //Bouton qui arrete l'envoi
begin
timer1.Enabled:= false; //On arrete tout simplement le timer
end;

end.

//Sources du serveur

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdBaseComponent, IdComponent, IdTCPServer, ExtCtrls,jpeg; //Pas oublier jpeg

type
  TForm1 = class(TForm)
    tcp: TIdTCPServer;//Composant serveur TCP Indy
    Image1: TImage;
    procedure tcpExecute(AThread: TIdPeerThread);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.tcpExecute(AThread: TIdPeerThread); //procedure appellée lors de la 
var stream : tmemorystream; //réception des données  
jpg : tjpegimage; //Définition des variables
begin

jpg:= tjpegimage.Create; //Initialisation de jpg et stream
stream:= tmemorystream.Create;
athread.Connection.ReadStream(stream, -1, true); //réception du stream du début à la fin
Stream.Seek(0, soFromBeginning);  //On reset la position du pointer pour la lecture 
                                                      // Peut être remplacer par stream.position:=0;
jpg.LoadFromStream(stream);  //Chargement du stream dans la variable jpg
image1.Picture.Graphic:= jpg;  //Affichage de l'image contenue dans jpg sur le Timage
stream.free; //Purge de la mémoire du stream

end;

end.

Conclusion :


Voilà, pour précision, le composant serveur doit être activé pour pouvoir recevoir des informations, celà peut être fait de la maniere suivante "nomduserveur.active:=true;". Ce n'est pas apparent dans la source car je l'ai définit comme activé dans l'inspecteur d'objet avant l'execution. De même le port de communication n'est pas apparent dans la source non plus car je lui ai attribué une valeure arbitrairement dans l'inspecteur d'objet également.
Si vous avez des commentaire je suis preneur, sauf si c'est pour me dire que le code n'a rien à faire ici parce que c'est trop simple où je ne sais quoi (j'ai observé ca ici). Comme je l'ai précisé j'ai chercher une solution dans les sources proposée et je n'ai pas trouvé de sujet traitant de cette maniere relativement facile le problème. mauvaises langues s'abstenir merci.
Les commentaires du codes paraitront surement inutiles et dérisoires pour les programmeurs confirmés mais je suis sure que certains débutants aprécieront. C'est bon je me tais, j'ai fini lol.

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.