SaveImageToMemory() [Windows-Only]

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Beitrag von cxAlex »

Ich hab dir mal ein Demo gemacht, hoffentlich hilft die das:

Code: Alles auswählen

UseJPEGImageEncoder()

Procedure SaveImageToMemory(Image, *MemSize, Format = #PB_ImagePlugin_JPEG, Compression = 9)
  Protected *Mem, MemSize, ImageDataPipe, PipeName$, RealMemSize
  PipeName$ = "\\.\pipe\ImageDataPipe_" + Str(GetCurrentThreadId_()) ; <- Threadsicher
  MemSize = ImageDepth(Image)*ImageHeight(Image)*ImageWidth(Image)
  *Mem = AllocateMemory(MemSize)
  ImageDataPipe = CreateNamedPipe_(PipeName$, #PIPE_ACCESS_INBOUND | #FILE_FLAG_OVERLAPPED, #PIPE_TYPE_BYTE | #PIPE_READMODE_BYTE | #PIPE_NOWAIT, 1, MemSize, MemSize, #NMPWAIT_USE_DEFAULT_WAIT, #Null)
  SaveImage(Image, PipeName$, Format, Compression)
  ReadFile_(ImageDataPipe, *Mem, MemSize, *MemSize, #Null)
  CloseHandle_(ImageDataPipe)
  ProcedureReturn *Mem
EndProcedure

Define Image, MemSize, *ImageMemory
; Image erstellen
Image = CreateImage(#PB_Any, 1024, 768, 32)
; Image in Speicher sichern
*ImageMemory = SaveImageToMemory(Image, @MemSize)
; Größe des Speichers
Debug MemSize
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Benutzeravatar
mpz
Beiträge: 505
Registriert: 14.06.2005 15:53
Computerausstattung: Win 11 Pro, 48 GB Ram, Intel I7 CPU und RX4070 Grafikkarte, PB (4/5) 6.12LT
Wohnort: Berlin, Tempelhof

Beitrag von mpz »

Hi cxAlex,

Ja jetzt habe ich es verstanden und gleich richtig eingesetzt. Funktioniert super, Danke.

Ich muss nur noch ermitteln ob die erzeugte Exe damit kleiner und schneller ist als mit meinem Code...

Gruß Michael
Working on :lol: - LibSGD - MP3D Engine - 8)
Benutzeravatar
mpz
Beiträge: 505
Registriert: 14.06.2005 15:53
Computerausstattung: Win 11 Pro, 48 GB Ram, Intel I7 CPU und RX4070 Grafikkarte, PB (4/5) 6.12LT
Wohnort: Berlin, Tempelhof

Beitrag von mpz »

Hi cxAlex,

kleines Messprotokoll:

Pipemethode
bei 1000 Durchgängen 13,2 S Dauer, +600 Bytes mehr in der Exe Datei

GetDIBits_ Methode
bei 1000 Durchgängen 12,3 S Dauer

Vorteil der Pipemethode: Image kann auch als jpg und Png Datei in den Speicher gelegt werden. Übersichtlicher Code

Nachteil der Pipemethode, Geringfügig langsamer und grössere Exe

Gruß Michael
Working on :lol: - LibSGD - MP3D Engine - 8)
davidpsd
Beiträge: 10
Registriert: 25.04.2010 10:26

Re: SaveImageToMemory() [Windows-Only]

Beitrag von davidpsd »

Hallo!

Ich habe Probleme, das im Memory gespeicherte Image wieder zu laden. Ich habe das Beispiel von oben benutzt und dann noch meinen Code dazu:

Code: Alles auswählen

Img2 = CatchImage(#PB_Any, *ImageMemory, MemSize)

If OpenWindow(0, 10, 10, 1280, 1024, "Screenshot", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
  ImageGadget(0, 0, 0, 1280, 1024, ImageID(Img2)) 
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
  CloseWindow(0)
EndIf
Bei ImgageID(Img2) sagt der Debugger, das angegebene #Image wurde nicht initialisiert!

Wie kann ich dann das Image wieder auslesen?

lG davidpsd
Christian+
Beiträge: 213
Registriert: 13.07.2008 10:05
Computerausstattung: Windows 8.1 Pro
AMD Phenom II X4 955 @ 3.2 GHz
4GB RAM
NVIDIA GeForce GTX 660

Re: SaveImageToMemory() [Windows-Only]

Beitrag von Christian+ »

Hast du auch eine UseJPEGImageDecoder() eingebaut denn sonst geht es nicht mit habe ich keine Probleme funktioniert dann super.
Windows 8.1 Pro 64Bit | AMD Phenom II X4 955 @ 3.2 GHz | 4GB RAM | NVIDIA GeForce GTX 660
davidpsd
Beiträge: 10
Registriert: 25.04.2010 10:26

Re: SaveImageToMemory() [Windows-Only]

Beitrag von davidpsd »

Ja habe ich. Mein ganzer Code:

Code: Alles auswählen

UseJPEGImageDecoder()

Procedure SaveImageToMemory(Image, *MemSize, Format = #PB_ImagePlugin_JPEG, Compression = 9)
  Protected *Mem, MemSize, ImageDataPipe, PipeName$, RealMemSize
  PipeName$ = "\\.\pipe\ImageDataPipe_" + Str(GetCurrentThreadId_()) ; <- Threadsicher
  MemSize = ImageDepth(Image)*ImageHeight(Image)*ImageWidth(Image)
  *Mem = AllocateMemory(MemSize)
  ImageDataPipe = CreateNamedPipe_(PipeName$, #PIPE_ACCESS_INBOUND | #FILE_FLAG_OVERLAPPED, #PIPE_TYPE_BYTE | #PIPE_READMODE_BYTE | #PIPE_NOWAIT, 1, MemSize, MemSize, #NMPWAIT_USE_DEFAULT_WAIT, #Null)
  SaveImage(Image, PipeName$, Format, Compression)
  ReadFile_(ImageDataPipe, *Mem, MemSize, *MemSize, #Null)
  CloseHandle_(ImageDataPipe)
  ProcedureReturn *Mem
EndProcedure

Define Image, MemSize, *ImageMemory
; Image erstellen
Image = CreateImage(#PB_Any, 1024, 768, 32)
; Image in Speicher sichern
*ImageMemory = SaveImageToMemory(Image, @MemSize)
; Größe des Speichers
Debug MemSize

Img2 = CatchImage(#PB_Any, *ImageMemory, MemSize)

If OpenWindow(0, 10, 10, 1280, 1024, "Screenshot", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
  ImageGadget(0, 0, 0, 1280, 1024, ImageID(Img2))
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
  CloseWindow(0)
EndIf
Fehler bei: ImageGadget(0, 0, 0, 1280, 1024, ImageID(Img2))

lG davidpsd
Christian+
Beiträge: 213
Registriert: 13.07.2008 10:05
Computerausstattung: Windows 8.1 Pro
AMD Phenom II X4 955 @ 3.2 GHz
4GB RAM
NVIDIA GeForce GTX 660

Re: SaveImageToMemory() [Windows-Only]

Beitrag von Christian+ »

Mach noch ein UseJPEGImageEncoder() rein, denn zum in Memory speichern braucht man den Encoder und zum auslesen dann den Decoder du hast jetzt aber nur den Decoder eingebaut.
Windows 8.1 Pro 64Bit | AMD Phenom II X4 955 @ 3.2 GHz | 4GB RAM | NVIDIA GeForce GTX 660
davidpsd
Beiträge: 10
Registriert: 25.04.2010 10:26

Re: SaveImageToMemory() [Windows-Only]

Beitrag von davidpsd »

ah, danke das wars
jetzt hab ich nur noch probleme, nach dem versenden des memory-teils an einen client das bild komplett darzustellen (hab nur ein halbes bild)

mal schauen, ob ich den fehler finde...

lG davidpsd
davidpsd
Beiträge: 10
Registriert: 25.04.2010 10:26

Re: SaveImageToMemory() [Windows-Only]

Beitrag von davidpsd »

Was mach ich falsch?
Es kommt nur 1/4 des Screenshots an.

Ich mach den Screenshot, speicher ihn in den Memory und sende ihn an den Client:

Code: Alles auswählen

Define MemSize, *ImageMemory
         ;Screenshot machen
         hImage = CreateImage(0,1280,1024)
         hdc    = StartDrawing(ImageOutput(0))
         DeskDC = GetDC_(GetDesktopWindow_())
         BitBlt_(hdc,0,0,1280,1024,DeskDC,0,0,#SRCCOPY)
         StopDrawing()
         ReleaseDC_(GetDesktopWindow_(),DeskDC)
         
         ResizeImage(0, 1280/2, 1024/2)

         ;Screenshot in Memory speichern
         *ImageMemory = SaveImageToMemory(0, @MemSize)

         ;sendet die Größe an den Client ( Eigene Funktion, vereinfacht SendNetworkString() )
         sendmsg(ClientIP$, "screenshot|"+Str(MemSize))

         ConnectionID = OpenNetworkConnection(ClientIP$, 6832)
         If ConnectionID
           SendNetworkData(ConnectionID, *ImageMemory, MemSize)
           CloseNetworkConnection(ConnectionID)
           PrintN("Screenshot gesendet! (Groesse: "+Str(MemSize)+")")
         Else
           PrintN("ERROR: Konnte den Client nicht finden!")
         EndIf
und der Client empfängt mit:

Code: Alles auswählen

;screensize ist die Größe des Bildes, wurde vorher empfangen
         ReceiveNetworkData(ClientID, *Buffer, screensize)
         CatchImage(0,*Buffer,screensize)
CatchImage beim Server liefert das ganze Bild, beim Client nur mehr 1/4.
Warum??

lG davidpsd
pyromane
Beiträge: 276
Registriert: 09.09.2010 14:10

Re: SaveImageToMemory() [Windows-Only]

Beitrag von pyromane »

Hallo cxAlex,
echt eine gute Funktion die mir schon oft gefehlt hat. Allerdings hat sie einen Nachteil.

Code: Alles auswählen

MemSize = ImageDepth(Image)*ImageHeight(Image)*ImageWidth(Image)
Das macht aus meinem Bild, welches als PNG ~ 200kb groß ist 52 MB im Ram. Das du dir die 52 MB reservierst macht ja Sinn, da das Bild ja auch unkomprimiert sein kann. Das aber nach dem Abspeichern der Rest nicht freigegeben wird stört etwas. In dem Code wird RealMemSize definiert aber nie verwendet (Wahrscheinlich hattest du genau das oben beschriebene vor). Allerdings fällt mir gerade auch nicht ein, wie ich ermittle, wieviel davon nun effektiv genutzt wurden. Bzw ich könnte schauen ab wann nur noch Nullen im Ram stehen aber das ist wahrscheinlich enorm ineffizent.

Aber ich bin mir ganz sicher das es einige aus dem Forum wissen.

Lg,
pyromane
PureBasic 5.21 LTS auf Windows 7 x64 (Intel i5 2500K, 8GB Ram, Nvidia GTX 780)
Antworten