Seite 1 von 3

SaveImageToMemory() [Windows-Only]

Verfasst: 14.04.2009 20:13
von cxAlex
Nachdem ich eine Featurerequest im englishen Forum gemacht hab, Bilder direkt in den Speicher zu sichern, hat mir srod einen Tip gegeben, den ich nun zu einer Procedure verwurstet hab:

http://www.purebasic.fr/english/viewtop ... 247#283247

Code: Alles auswählen

Procedure SaveImageToMemory(Image, *MemSize, Format = #PB_ImagePlugin_BMP, Compression = 7)
  Protected *Mem, MemSize, ImageDataPipe
  MemSize = ImageDepth(Image)*ImageHeight(Image)*ImageWidth(Image)
  *Mem = AllocateMemory(MemSize)
  ImageDataPipe = CreateNamedPipe_("\\.\pipe\ImageDataPipe", #PIPE_ACCESS_INBOUND | #FILE_FLAG_OVERLAPPED, #PIPE_TYPE_BYTE | #PIPE_READMODE_BYTE | #PIPE_NOWAIT, 1, MemSize, MemSize, #NMPWAIT_USE_DEFAULT_WAIT, #Null)
  SaveImage(Image, "\\.\pipe\ImageDataPipe", Format, Compression)
  ReadFile_(ImageDataPipe, *Mem, MemSize, *MemSize, #Null)
  CloseHandle_(ImageDataPipe)
  ProcedureReturn *Mem
EndProcedure
Ich brauch sowas immer wieder, ganz nützlich.

Verfasst: 15.04.2009 00:32
von KeyKon
Klasse :allright:
Lass mich raten, das ganze läuft auch in deinem DesktopStreamer^^

Verfasst: 15.04.2009 06:35
von cxAlex
KeyKon hat geschrieben:Klasse :allright:
Lass mich raten, das ganze läuft auch in deinem DesktopStreamer^^
exakt, in der nächsten Version ists drin ^^

Verfasst: 15.04.2009 11:34
von KeyKon
Btw, ich bin zwar kein Englisch-Guru, aber ich meine der Topic müsste SaveImageToMemory() heißen ;-)

Verfasst: 15.04.2009 11:47
von DarkDragon
Hmm... das müsste so ähnlich sicher auch unter Linux gehen.

Verfasst: 15.04.2009 16:29
von Andesdaf
KeyKon hat geschrieben:Btw, ich bin zwar kein Englisch-Guru, aber ich meine der Topic müsste SaveImageToMemory() heißen ;-)
Nur der Threadtitel ist falsch (meiner Meinung nach), die Procedure an sich ist richtig.

Verfasst: 15.04.2009 16:43
von cxAlex
Jo mein Fehler :oops:.

Beim Programmieren kam mir PB mit der Autovervollständigung entgegen, im Titel hat sich mein schlechtes Englisch durchgesetzt :mrgreen: .

Verfasst: 15.04.2009 18:11
von Andesdaf
allgemein zur Procedure :allright:

Verfasst: 25.04.2009 00:17
von cxAlex
Update:

Das ganze ist nun Thread-Safe, bei massiver verwendung in Threads konnte es zu Kollisionen mit der Pipe kommen:

Code: Alles auswählen

Procedure SaveImageToMemory(Image, *MemSize, Format = #PB_ImagePlugin_JPEG, Compression = 9)
  Protected *Mem, MemSize, ImageDataPipe, PipeName$
  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

Verfasst: 25.04.2009 22:04
von mpz
Hi cxAlex,

der Code sieht gut aus. Wie genau wende ich Ihn den Code praktisch an? Ich weis nicht wie ich den Wert "*MemSize" ermitteln muss den ich der Prozedur übergebe. Wenn ich meine Code durch Deinen ersetze kommt immer eine Fehlermeldung in der folgender Zeile:

> ReadFile_(ImageDataPipe, *Mem, MemSize, *MemSize, #Null) > invalid memory access

Mein Code zur Übergabe eines Image in einen Speicherbereich:

Code: Alles auswählen


 w = ImageWidth(Img) 
  h = ImageHeight(Img) 
  hBmp = ImageID(Img) 
  
  bmi\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER) 
  bmi\bmiHeader\biWidth       =  w 

  If direction = 0
     bmi\bmiHeader\biHeight      =  h ; -h dreht das Bild als Textur
  Else
     bmi\bmiHeader\biHeight      =  -h 
  EndIf

  bmi\bmiHeader\biPlanes      =  1 
  bmi\bmiHeader\biBitCount    = 32 
  bmi\bmiHeader\biCompression = #BI_RGB 
  

  width = w 
  height = h 

  bitcount = 32 ; Should be 24 bits for this example 
  ; Rows need to be a multiple of 4 bytes so calculate extra bytes needed 
  extrabytesperrow = (4 - (width * bitcount / 8) % 4) % 4 

  ; Allocate memory for bitmap 
  sizeheaders = SizeOf(BITMAPFILEHEADER) + SizeOf(BITMAPINFOHEADER) 
  sizeimage = (width * bitcount / 8 + extrabytesperrow) * height 

  *bitmap = AllocateMemory(sizeheaders + sizeimage) 

  If *bitmap = 0
    ProcedureReturn #False 
    ;Debug("Couldn't allocate memory for bitmap") 
    ;End 
  EndIf 

  ; Set bitmap headers 
  *bitmapfile.BITMAPFILEHEADER = *bitmap 
  *bitmapfile\bfType = Asc("B") + Asc("M") << 8 
  *bitmapfile\bfSize = sizeheaders +sizeall 
  *bitmapfile\bfOffBits = sizeheaders 

  *bitmapinfo.BITMAPINFOHEADER = *bitmap + SizeOf(BITMAPFILEHEADER) 
  *bitmapinfo\biSize = SizeOf(BITMAPINFOHEADER) 
  *bitmapinfo\biWidth = width 
  *bitmapinfo\biHeight = height 
  *bitmapinfo\biPlanes = 1 
  *bitmapinfo\biBitCount = bitcount 
  *bitmapinfo\biCompression = 0 
  *bitmapinfo\biSizeImage = sizeimage 

  *bitmapdata = *bitmap + sizeheaders 

; Create 24 bit image in bitmap 
  *bitmapdatapos = *bitmapdata 


  hDC  = StartDrawing( ImageOutput(Img) ) 
  If GetDIBits_(hDC, hBmp, 0, h, *bitmapdatapos , bmi, #DIB_RGB_COLORS) 
     StopDrawing() 
  Else 
     StopDrawing()  
  EndIf