24-Bit Farbe in 16-Bit-Farbe umwandeln

  • Hallo!

    Nachdem ich in den letzten Tagen ein wenig mit einem 5EUR-Arduino-SPI-Display von eBay rumgespielt habe, ist dieses Tool entstanden, um bequem "normale" Farbcodes in dafür passende umzuwandeln. An den definierten Farbkonstanten (Schwarz, Weiss, Rot, Grün, Blau) konnte ich ablesen, dass die Arduino-Library scheinbar einen 16-Bit-Farbcode erwartet, wobei Rot und Blau je mit 5 Bit und Grün mit 6 Bit angegeben werden. Da mir dieses Format bisher gänzlich unbekannt war, habe ich kurzerhand ein Konvertierungstool geschrieben.
    Der findige Leser wird sicherlich schon bemerkt haben, dass 16 Bit wesentlich weniger Informationen enthalten als 24 Bit. Natürlich sind die Unterschiede in der Farbdarstellung nur marginal, allerdings doch sichtbar. Damit man weiß, auf was man sich einlässt, wird daher die Originalfarbe mit der neu berechneten Farbe verglichen. Bei manchen Farben sieht man dann schon den Unterschied. ^^

    So, genug gequatscht, hier das Skript. Vielleicht kann es ja mal ein Arduino-Bastler gebrauchen.

    [autoit]


    #include <StaticConstants.au3>
    #include <EditConstants.au3>

    [/autoit][autoit][/autoit][autoit]

    Global Const $SS_ALLCENTER = $SS_CENTER + $SS_CENTERIMAGE

    [/autoit][autoit][/autoit][autoit]

    $hWnd = GUICreate("24bt16bcc", 400, 400)
    GUISetFont(8.5, 400, 0, "Segoe UI")
    GUICtrlCreateLabel("24 bit to 16 bit color converter", 0, 0, 400, 40, $SS_ALLCENTER)
    GUICtrlSetFont(-1, 12, 600)
    GUICtrlCreateLabel("developed for Arduino SPI displays", 0, 40, 400, 20, $SS_ALLCENTER)
    GUICtrlSetFont(-1, 10, 400)

    [/autoit][autoit][/autoit][autoit]

    GUICtrlCreateLabel("Input (24 bit hex color value):", 20, 100, 180, 20, $SS_CENTERIMAGE)
    $c24Bit = GUICtrlCreateInput("", 200, 100, 180, 20)
    GUICtrlCreateLabel("Output (16 bit hex color value):", 20, 140, 180, 20, $SS_CENTERIMAGE)
    $c16Bit = GUICtrlCreateInput("", 200, 140, 180, 20, $ES_READONLY)

    [/autoit][autoit][/autoit][autoit]

    GUICtrlCreateGroup("Color Preview", 20, 180, 360, 130)
    $cInputPreview = GUICtrlCreateLabel("Input", 30, 200, 170, 100, $SS_ALLCENTER)
    setPreviewColor($cInputPreview, 0x000000)
    $cOutputPreview = GUICtrlCreateLabel("Output", 200, 200, 170, 100, $SS_ALLCENTER)
    setPreviewColor($cOutputPreview, 0x000000)

    [/autoit][autoit][/autoit][autoit]

    $cConvert = GUICtrlCreateButton("Convert", 100, 330, 200, 50)
    Local $aAccelKeys[][] = [["{ENTER}", $cConvert]]
    GUISetAccelerators($aAccelKeys)
    GUISetState()

    [/autoit][autoit][/autoit][autoit]

    While True
    Switch GUIGetMsg()
    Case -3
    Exit
    Case $cConvert
    doConversation()
    EndSwitch
    WEnd

    [/autoit][autoit][/autoit][autoit]

    Func doConversation()
    ;read and clean input color value
    $s24BitColorRaw = GUICtrlRead($c24Bit)
    $aTemp = StringRegExp($s24BitColorRaw, "(?:(?:0x)|(?:#)|)([0-9a-fA-F]{6})", 3)
    If Not IsArray($aTemp) Then
    MsgBox(16, "24bt16bcc", "The input value is invalid. Please change.")
    Return
    EndIf
    $i24Bit = Int("0x" & $aTemp[0])
    ;convert input
    $i16Bit = generate16BitFrom24Bit($i24Bit)
    $i16BitPreview = @extended
    setPreviewColor($cInputPreview, $i24Bit)
    setPreviewColor($cOutputPreview, $i16BitPreview)
    ;write output back to GUI
    GUICtrlSetData($c16Bit, Hex($i16Bit, 4))
    EndFunc ;==>doConversation

    [/autoit][autoit][/autoit][autoit]

    Func setPreviewColor($cControl, $iColor)
    GUICtrlSetBkColor($cControl, $iColor)
    GUICtrlSetColor($cControl, 0xffffff - $iColor)
    EndFunc ;==>setPreviewColor

    [/autoit][autoit][/autoit][autoit]

    Func generate16BitFrom24Bit($i24Bit)
    $iRed = BitShift(BitAND($i24Bit, 0xff0000), 16)
    $iGreen = BitShift(BitAND($i24Bit, 0x00ff00), 8)
    $iBlue = BitAND($i24Bit, 0x0000ff)

    [/autoit][autoit][/autoit][autoit]

    $iNewRed = Int(($iRed / 255) * 31)
    $iNewGreen = Int(($iGreen / 255) * 63)
    $iNewBlue = Int(($iBlue / 255) * 31)

    [/autoit][autoit][/autoit][autoit]

    ;extra
    $iReRed = Int(($iRed / 255) * 31) * (255/31)
    $iReGreen = Int(($iGreen / 255) * 63) * (255/63)
    $iReBlue = Int(($iBlue / 255) * 31) * (255/31)
    $iRe24Bit = BitShift($iReRed, -16) + BitShift($iReGreen, -8) + $iReBlue
    ;end extra

    [/autoit][autoit][/autoit][autoit]

    $i16Bit = BitShift($iNewRed, -11) + BitShift($iNewGreen, -5) + $iNewBlue
    Return SetExtended($iRe24Bit, $i16Bit)
    EndFunc ;==>generate16BitFrom24Bit

    [/autoit]

    Grüße!

  • Hi,
    im Deskstream hatten wir das schon verwendet, um eine 32-Bit Farbe auf die Hälfte einzustampfen... DeskStream 2 Release Candidate 1.8
    Oder hier hatte ich auch mal 565 gefunden DTX Daten als Bild in GUI anzeigen
    oder hier... HQx, EPx, xBR... Grafikinterpolation !

    Für den Arduino hab ich das aber noch nicht gebraucht...welches Display hast du da?

  • Na gut, ich habe nur ganz kurz und oberflächlich gesucht, nachdem ich die Zusammensetzung der 16-Bit-Codes durchschaut hatte. Dann eben ein kleines Skript hingeklatscht, noch ohne GUI, mathematisch ist das ja nur Dreisatz. Der Aufwand war so geringer als beim Suchen. :D

    Das erstbeste 2.2"-SPI-Display. Auf jeden Fall ist es kompatibel mit der Adafruit_ILI9340-Library, was wahrscheinlich eher entscheidend ist. Ich weiß gar nicht, ob diese Einschränkung auf 16-Bit vom Display oder von der Library kommt. Jedenfalls benutzt die o.g. Bibliothek entsprechende Farbcodes.

  • Wie sieht das mit der Geschwindigkeit aus?
    Mir schwebt eine Anwendung für eine Waage/Zähler vor. Ich wollte erst eine zweizeilige LCD-Anzeige nutzen, aber das Display kostet fast das selbe, und ich hätte die Möglichkeit, je nach Anwendung die Taster/Schalter entsprechend zu "beschriften".

  • Also, schnell ist's nicht. Kann aber auch an dem Arduino Nano (Atmega 328) liegen. Wenn ich zuerst alles weiss einfärbe, dann alles schwarz, dann kann man mit bloßem Auge beobachten, wie der schwarze Balkon von oben nach unten durch das Bild fährt.
    Wenn du allerdings immer nur möglichst kleine Bildschirmbereiche aktualisierst, dann ist es annehmbar. Ich habe damit eine Quizanlage gebaut. Das funktioniert so, dass jeder der acht Spieler vier Taster (A, B, C und D) hat, mit denen er halt seine Antwort vermitteln kann. Auf dem Display der Haupteinheit werden diese Antworten dann visualisiert, dabei habe ich die Anzeige in acht Bereiche gegliedert. Wenn ich bei einem Tastendruck immer nur das zu verändernde Segment neuzeichne, gibt es keine merkliche Verzögerung. Also alles eine Frage der Anwendung. :D

    Edit: Schon mal als Vorwarnung... Die meisten dieser Displays arbeiten mit 3.3V Logikpegel, manche Arduinos aber mit 5V. Durch die dürftige Beschreibung auf eBay ist das leider nicht direkt ersichtlich. Im Zweifelsfall also Pegelwandler oder Spannungsteiler mit einplanen.

  • Ich habe mich von dem Pegelunterschied überraschen lassen und habe daher schnell ein paar Spannungsteiler auf einer Lochrasterplatine aufgebaut. Hatte nichts anderes da...

    Oh, das ist auch gut zu wissen. Obwohl es - wie gesagt - auch so ging, das Projekt ist mittlerweile voll funktionsfähig und wir wissen ja alle... Never change a running system. :D Aber danke trotzdem für den Tipp, kann man gewiss mal gebrauchen.