Seite 1 von 2

RGB-Bytearray konvertieren

Verfasst: 24.04.2005 04:02
von garfield9992003
Hallo miteinander.

Ein Grafikproblem zwingt mich zum wachbleiben :(

Ich habe ein RGB-Bytearray, zudem ist die Anzahl der Pixel pro Linie (*3=Bytes/Linie) und die Anzahl der Linien gegeben. (Farbtiefe=16bit)

Wie bewege ich Purebasic dazu, das Ganze in einem brauchbaren Format zu speichern? Mit CatchImage kam ich auf keine Ergebnisse.

Mit RGB() kann man ja die Farbwerte wandeln. Aber dann weis ich immer noch nicht so recht, wie ich das Bild als Bitmap oder JPG speichern könnte.

Hat vielleicht jemand eine Idee? Oder sehe ich den Wald vor lauter Bäumen nicht.

Grüße

Frank

Verfasst: 24.04.2005 15:14
von garfield9992003
Ergänzung:

Beispiel für meine gegebene Situation:
472 Pixel/Linie * 3 Bytes(RGB) ---> 1416 Bytes/Linie
945 Linien Bildhöhe
----> macht ein Bytearray mit 1338120 Bytes Rohdaten

Es sollen dann ggfs. Ausgaben in BMP, JPG, TIFF möglich sein.
Und das ohne kostenpflichtige 3rd Party-Tools.

Natürlich variiert später auch die Farbtiefe des Bildes und so - aber das ist kein Problem, wenn ich ersteinmal den Lösungsansatz für mein Beispiel habe.

Grüße

Verfasst: 24.04.2005 15:25
von Lukaso
Hier mal nen anstoß:

Code: Alles auswählen

img = CreateImage(0, BreiteInPixel, HoeheInPixel)
If img
  StartDrawing(ImageOutput())
  For y = 1 To HoeheInPixel
    For x = 1 To BreiteInPixel
      Plot(x, y RGB(r, g, b))
    Next
  Next
  StopDrawing()
  SaveImage(0, "C:\test.bmp", #PB_ImagePlugin_BMP)
EndIf
Code nicht getestet!

MFG Lukaso

Verfasst: 24.04.2005 15:31
von Danilo
garfield9992003 hat geschrieben:Ergänzung:
Jetzt hab ich es verstanden. :)
garfield9992003 hat geschrieben:Beispiel für meine gegebene Situation:
472 Pixel/Linie * 3 Bytes(RGB) ---> 1416 Bytes/Linie
945 Linien Bildhöhe
----> macht ein Bytearray mit 1338120 Bytes Rohdaten

Es sollen dann ggfs. Ausgaben in BMP, JPG, TIFF möglich sein.
Und das ohne kostenpflichtige 3rd Party-Tools.
CreateImage(1, 472, 945)

Danach alle Pixel des Arrays in einer Schleife auf das Bild
zeichnen, mit Plot(x,y,RGB( array(x,y)\r, array(x,y)\g, array(x,y)\b )).

Mit SaveImage und dem gewünschten Encoder (PNG,JPEG)
speichern.

Diese Methode sollte Platformunabhängig sein.

Auf Windows kannst Du das zeichnen der Pixel noch über
SetDIBits_() beschleunigen. Beispiele dazu findest Du im
CodeArchiv auf PureArea.net oder per Forensuche im alten
Forum.

Verfasst: 24.04.2005 15:54
von garfield9992003
Habt im Moment vielen Dank, ich werde mir das nun ansehen und berichten. Tempo spielt natürlich eine Rolle - Aber da bin ich von PureBasic noch nie enttäuscht worden :)

Grüße

Frank

Verfasst: 24.04.2005 22:16
von garfield9992003
Ich habe mich nun einige Stunden mit dem Thema beschäftigt.

Euer Vorschlag funktioniert auch im etwa so.
Nur verstehe ich nun nicht, warum alle weissen Pixel schwarz dargestellt werden... *kopfkratz*

Die schnellste Lösung wäre bestimmt mit Drawingbuffer/CopyMemory das Bytearray direkt in den Speicherbereich von Createimage zu kopieren- jedoch bei ImageOutput funktioniert der DrawingBuffer wohl nicht.

Bei einer DinA4-Seite mit 300 dpi dauert das For-Plot-Next jedoch :(

Tipps, wie es mit CopyMem doch gehen könnte?

Grüße

Frank

Verfasst: 24.04.2005 22:56
von Lukaso
garfield9992003 hat geschrieben:Nur verstehe ich nun nicht, warum alle weissen Pixel schwarz dargestellt werden... *kopfkratz*
Vll. verwächselst du RGB(0, 0, 0) mit RBG(255, 255, 255)? Einfach ne If Abfrage um es wieder gerade zu biegen :wink:

MFG Lukaso

Verfasst: 25.04.2005 13:24
von NicTheQuick
Das Problem wird sicherlich sein, dass ein Image im Speicher pro Bildpunkt immer 32 Bit verwendet und dann funktioniert das mit dem [c]CopyMemory()[/c] nicht so einfach.

Also entweder musst du die Struktur des Arrays auf 4 Bytes erhöhen oder du musst Danilos Methode benutzen.

Und für Danilos Methode hätte ich noch eine Ergänzung. Wenn die Bytes
[c]r.b[/c], [c]g.b[/c] und [c]b.b[/c] in der Struktur sind, sind sie in Purebasic somit auch signed. Das heißt, das müssen wir nch ändern. Also so:

Code: Alles auswählen

Plot(x,y,RGB(array(x,y)\r & $FF, array(x,y)\g & $FF, array(x,y)\b & $FF))

Verfasst: 25.04.2005 14:20
von garfield9992003
Danke für den Hinweis mit dem Signed Byte.... Klar, nun sind meine schwarzen Pixel auch weiss. Da hätte ich nun nicht mehr dran gedacht.

Frank

Verfasst: 25.04.2005 14:37
von Danilo
garfield9992003 hat geschrieben:Bei einer DinA4-Seite mit 300 dpi dauert das For-Plot-Next jedoch :(
Sagte ich doch, weshalb ich Dir oben schon SetDIBits_()
vorschlug.

Code: Alles auswählen

;
; by Danilo, 25.04.2005
;
#ImageWidth  = 500
#ImageHeight = 255


Procedure Mem2Image(Image,Width,Height,mem)
  Structure _LTI_BITMAPINFO
    bmiHeader.BITMAPINFOHEADER
    bmiColors.RGBQUAD[1]
  EndStructure

  hBmp = UseImage(Image)
  If hBmp
    hDC  = StartDrawing(ImageOutput())
    If hDC
      bmi._LTI_BITMAPINFO
      bmi\bmiHeader\biSize   = SizeOf(BITMAPINFOHEADER)
      bmi\bmiheader\biWidth  = Width
      bmi\bmiheader\biHeight = Height
      bmi\bmiheader\biPlanes = 1
      bmi\bmiheader\biBitCount = 24
      bmi\bmiheader\biCompression = #BI_RGB
      If SetDIBits_(hDC,hBmp,0,ImageHeight(),mem,bmi,#DIB_RGB_COLORS) <> 0
        Result = hBmp
      EndIf
      StopDrawing()
    EndIf
  EndIf
  ProcedureReturn Result
EndProcedure


Structure _RGB
  r.b
  g.b
  b.b
EndStructure

; alloc memory array
mem = AllocateMemory(#ImageWidth*#ImageHeight*SizeOf(_RGB))
If mem=0 : MessageRequester("ERROR","Cant allocate memory!"):End : EndIf

; fill memory array
For y = 0 To #ImageHeight-1
  RtlFillMemory_(mem+y*#ImageWidth*SizeOf(_RGB),#ImageWidth*SizeOf(_RGB),y)
Next

; create image
image1 = CreateImage(1,#ImageWidth,#ImageHeight)
If image1
  
  ; copy memory array to image
  Mem2Image(1,#ImageWidth,#ImageHeight,mem)

  OpenWindow(0,0,0,ImageWidth(),ImageHeight(),#PB_Window_ScreenCentered|#PB_Window_SystemMenu,"Image")
    CreateGadgetList(WindowID())
    ImageGadget(0,0,0,ImageWidth(),ImageHeight(),image1)
    Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Else
  MessageRequester("ERROR","Cant load image!",#MB_ICONERROR)
EndIf
Dabei solltest Du beachten das dieses Bild falschrum ist,
d.h. die erste Zeile im Bild ist im SpeicherArray die unterste
Zeile.

PB-Arrays kann man aber nicht einfach so als geradlinigen
Speicher ansprechen, da in PB x und y verkehrt herum sind.
Deshalb kann man PB-Arrays mit C oder mit WinAPI nicht
einfach nutzen.