RGB-Bytearray konvertieren

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
garfield9992003
Beiträge: 35
Registriert: 24.04.2005 03:49

RGB-Bytearray konvertieren

Beitrag 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
garfield9992003
Beiträge: 35
Registriert: 24.04.2005 03:49

Beitrag 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
Benutzeravatar
Lukaso
Beiträge: 720
Registriert: 08.09.2004 18:51
Wohnort: Oberkirch
Kontaktdaten:

Beitrag 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
Nextgen Guild Wars Fanseite: Guild Wars Tactics (Pseudo-Admin + Developer)
"Das Fluchen ist die einzige Sprache, die jeder Programmierer beherrscht." - Unbekannter Autor
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Beitrag 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.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
garfield9992003
Beiträge: 35
Registriert: 24.04.2005 03:49

Beitrag 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
garfield9992003
Beiträge: 35
Registriert: 24.04.2005 03:49

Beitrag 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
Benutzeravatar
Lukaso
Beiträge: 720
Registriert: 08.09.2004 18:51
Wohnort: Oberkirch
Kontaktdaten:

Beitrag 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
Nextgen Guild Wars Fanseite: Guild Wars Tactics (Pseudo-Admin + Developer)
"Das Fluchen ist die einzige Sprache, die jeder Programmierer beherrscht." - Unbekannter Autor
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8812
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Beitrag 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))
garfield9992003
Beiträge: 35
Registriert: 24.04.2005 03:49

Beitrag 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
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Beitrag 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.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Antworten