Screenshot direkt über Memory senden

Für allgemeine Fragen zur Programmierung mit PureBasic.
Moxl
Beiträge: 150
Registriert: 26.10.2012 13:19

Screenshot direkt über Memory senden

Beitrag von Moxl »

Hallo,

ich hab folgendes vor,
ich möchte bei meinem client ein screenshot machen und der screenshot soll direkt in den memory geschrieben und dann direkt mit sendnetworkdata() versendet werden.
vom server soll das dann empfangen und dann in eine datei geschrieben werden.

Das hab ich zurzeit aber es funktioniert irgendwie nicht:

server:

Code: Alles auswählen

InitNetwork()
If  CreateNetworkServer(0, 6700)<>0
  OpenWindow(0, 0, 0, 200, 20, "", #PB_Window_BorderLess)
  ProgressBarGadget(0, 0, 0, 200, 20, 0, 0)
  Repeat
    Delay(10)
    windowevent=WindowEvent()
    serverevent=NetworkServerEvent()
    If  serverevent=#PB_NetworkEvent_Connect
      Debug "Client connected"
    EndIf
    If  serverevent=#PB_NetworkEvent_Data
      Debug "Daten empfangen"
      result = ReceiveNetworkData(EventClient(), @Size, 4)
      Debug "Empfangene Bytes (Größe der Long (müssten 4 sein)): "+Str(result)
      Debug "Empfangene Bytes (Größe des Screenshots): "+Str(Size)
      If result = 4 And Size > 0
        SetGadgetAttribute(0, #PB_ProgressBar_Maximum, Size)
        ;Allokiere Speicher in dieser Größe
         *MemBuffer = AllocateMemory(Size)
         errorcounter = 0 
         ReceivedBytes = 0
         Repeat
           SetGadgetState(0, ReceivedBytes)
           ;Speicher die Anzahl der geladenen Bytes                                 {noch zu laden}
          result = ReceiveNetworkData(EventClient(), *MemBuffer + ReceivedBytes, Size - ReceivedBytes)
          If result = -1
           Delay(1) 
           errorcounter + 1
          Else
           ReceivedBytes + result
           errorcounter = 0
          EndIf
        Until ReceivedBytes = Size Or errorcounter > 6000 ; Abbruch nach 6 Sekunden
      EndIf
      If Size > 0 And ReceivedBytes = Size
        screenshot$=GetHomeDirectory()+"Screenshot "+FormatDate("%hh-%ii-%ss", Date())+".bmp"
        If  CreateFile(0, screenshot$)
          WriteData(0, *MemBuffer, Size)
          CloseFile(0)
          FreeMemory(*MemBuffer)
        Else
          Debug "datei konnte nicht erstellt werden"
        EndIf
      Else
        Debug "screenshot konnte nicht heruntergeladen werden"
      EndIf
    EndIf
    If  serverevent=#PB_NetworkEvent_Disconnect
      Debug "Client disconnected"
    EndIf
  Until windowevent=#PB_Event_CloseWindow
Else
  Debug "server konnte nicht erstellt werden"
EndIf
client:

Code: Alles auswählen

Procedure MakeDesktopScreenshot(ImageNr,x,y,Width,Height)
   hImage = CreateImage(ImageNr,Width,Height) 
   hDC    = StartDrawing(ImageOutput(ImageNr)) 
   DeskDC = GetDC_(GetDesktopWindow_()) 
      BitBlt_(hDC,0,0,Width,Height,DeskDC,x,y,#SRCCOPY) 
   StopDrawing() 
   ReleaseDC_(GetDesktopWindow_(),DeskDC) 
   ProcedureReturn hImage 
EndProcedure
Procedure CopyImageToMem(Img.l, mem.l)
  Protected bmi.BITMAPINFO
  Protected w.l, h.l, hBmp.l, hDC.l

  w = ImageWidth(Img)
  h = ImageHeight(Img)
  hBmp = ImageID(Img)
 
  bmi\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
  bmi\bmiHeader\biWidth       =  w
  bmi\bmiHeader\biHeight      = -h
  bmi\bmiHeader\biPlanes      =  1
  bmi\bmiHeader\biBitCount    = 32
  bmi\bmiHeader\biCompression = #BI_RGB
 
  hDC  = StartDrawing( ImageOutput(Img) )
  If GetDIBits_(hDC, hBmp, 0, h, mem, bmi, #DIB_RGB_COLORS)
    StopDrawing()
    ProcedureReturn #True
  Else
    StopDrawing()
    ProcedureReturn #False
  EndIf
EndProcedure

InitNetwork()
verbindung=OpenNetworkConnection("localhost", 6700)
If  verbindung<>0
  ExamineDesktops()
  MakeDesktopScreenshot(0, 0, 0, DesktopWidth(0), DesktopHeight(0))
  ResizeImage(0, 800, 600)
  *mem=AllocateMemory(ImageWidth(0)*ImageHeight(0)*4)
  If  CopyImageToMem(0, *mem)=0
    Debug "copy image to mem fail"
  Else
    Size.l=MemorySize(*mem)
    Debug "Größe vom Reservierten Speicher: "+Str(Size)
    x=SendNetworkData(verbindung, @Size, 4)
    Debug "Gesendete Bytes (Größe der Long (müssten 4 sein)): "+Str(x)
    y=SendNetworkData(verbindung, *mem, Size)
    Debug "Gesendete Bytes (Größe des Screenshots): "+Str(y)
    FreeMemory(*mem)
  EndIf
Else
  Debug "verbindung fehlgeschlagen"
EndIf
ich komm einfach net weiter und finde den fehler nich... :bluescreen:

danke schonmal im vorraus :allright:
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7039
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Screenshot direkt über Memory senden

Beitrag von STARGÅTE »

Was funktioniert denn nicht?

Du kannst ja auch erst mal selber auf Fehlersuche gehen:
  • Wird eine Verbindung aufgebaut?
  • Wird ein Screenshot gemacht?
  • Wird ein gültiges Image erzeugt?
  • Funktioniert die Umwandlung von Image zu Memory?
  • Würde das Bild auf dem selben PC wieder richtig erstellt werden?
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Moxl
Beiträge: 150
Registriert: 26.10.2012 13:19

Re: Screenshot direkt über Memory senden

Beitrag von Moxl »

hab ich doch :o

wird alles durch debug angezeigt... und die image wird auch auf dem selben pc mittels saveimage() erzeugt... nur wenn ich das image dort erzeuge hat die bilddatei weniger mb als die datei die man dann geschickt bekommt :|

also schätze ma es liegt am speicherplatz reservieren das es vllt die falsche größe ist oder so... aber wenn ich weniger mache dann klappts mitm copyimagetomem nicht
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7039
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Screenshot direkt über Memory senden

Beitrag von STARGÅTE »

Ich führe ja den Code nicht selber aus, deswegen sehe ich keine Debug-Ausgabe, denn das Problem hast du ja festgestellt.

Und das Problem hast du ja nun erkannt: Es kommt eine falsche Größe an.

Du sendest über das Netzwerk nur: ImageWidth(0)*ImageHeight(0)*4 Bytes, also die reinen Pixel.
Und am Ende speicherst du in deiner Datei auch nur die Pixel.
Zu einem Bild gehört aber noch ein Header, mit Infos zum Format usw. das speicherst du bei SaveImage, aber nicht bei deinem eigene CreateFile.

Also: Entweder kompletten Bild senden (mit Header), oder einfach die gesendeten Pixel in ein Image schreiben und dann das Image speichern.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Moxl
Beiträge: 150
Registriert: 26.10.2012 13:19

Re: Screenshot direkt über Memory senden

Beitrag von Moxl »

hm achso... ma so ne nebenfrage.. warum macht man eigentlich imagewidth*imageheight*4? also warum mal 4? hab das nur aus nem forum kopiert deswegen frag ich..

und ich glaub das mit dem pixel in ne image schreiben und diese speichern is ne gute idee.. meinst du du kannst mir mal kurz n beispiel machen wie das funzt? :/ kenn mich mit images und drawing gar nich aus :/
Benutzeravatar
jojo1541
Beiträge: 431
Registriert: 15.09.2007 17:12
Wohnort: Irgendwo im Nirgendwo

Re: Screenshot direkt über Memory senden

Beitrag von jojo1541 »

Du machst Breite*Höhe*Farbtiefe, weil ein Bild dann doch noch Speicherplatz für seine Pixel braucht.

Je nach Farbtiefe sind das eben 4bpp = 16 Farben, 8bpp = 256 Farben, 16bpp = 65k, 24bpp = 16Mille und 32bpp = 16 Mille + Alpha.
bpp (Bits per Pixel)

Da 32 Bits nunmal 4 Byte sind, musst du eben mal 4 nehmen. :wink:
Zuletzt geändert von jojo1541 am 27.12.2012 01:02, insgesamt 1-mal geändert.
Ich verkaufe Rechtschreibfehler und jede menge GROßBUCHSTABEN. Alles unbegrenzt zu haben.
Moxl
Beiträge: 150
Registriert: 26.10.2012 13:19

Re: Screenshot direkt über Memory senden

Beitrag von Moxl »

ahhh ok verstehe ;)

jetzt is nur noch die frage mit den pixel in ein image schreiben offen :D
Benutzeravatar
jojo1541
Beiträge: 431
Registriert: 15.09.2007 17:12
Wohnort: Irgendwo im Nirgendwo

Re: Screenshot direkt über Memory senden

Beitrag von jojo1541 »

Naja, Stargate hat es ja eigentlich schon gesagt.

Du sendest nur das Bild selber, nicht aber den Header.

Entweder du sendest einen Header mit und erstellst dann via CreateFile() oder du schreibst die Pixel aus dem Speicher in ein von dir via CreateImage() erstelltes Bild und speicherst dieses dann mit SaveImage().
Ich verkaufe Rechtschreibfehler und jede menge GROßBUCHSTABEN. Alles unbegrenzt zu haben.
Moxl
Beiträge: 150
Registriert: 26.10.2012 13:19

Re: Screenshot direkt über Memory senden

Beitrag von Moxl »

genau das habe ich ja vor^^ aber nach
CreateImage(0)
startdrawing(imageoutput(0))

weiß ich nichmehr weiter x)
Moxl
Beiträge: 150
Registriert: 26.10.2012 13:19

Re: Screenshot direkt über Memory senden

Beitrag von Moxl »

ok ich habs :)

gibt n befehl im codearchiv: CopyMemToImage()
Antworten