Bitshifting



  • Hi,

    ich muss für ne uni abgabe ein 16bit bitmap file manipulieren. Ich hab die Pixeldaten in ein char* array geladen. Jeweils 2 hintereinanderliegende bytes enthalten die 3 farbwerte für einen pixel, also 3 x 5 Bits (wobei das letzte glaub ich ein padding bit enthält um auf 16 bit zu kommen).

    Die einzige Möglichkeit die mir einfällt, um jeweils 5 bits im Buffer zu schreiben ist Bitshifting, leider hab ich damit keine Erfahrung.

    Kann mir vielleicht jemand nen Tip geben, wie man sowas macht ?

    Vielen Dank !



  • Ich würde je 2 array Elemente in einen 2 Byte Datentyp casten (z.B. short) bzw das ganze array in ein short array.

    char* array = ...
    short* bits = reinterpret_cast<short*>(array);
    for(size_t i=0;i<pixelCount;++i)
    {
      char component_1 = bits[i] & 0x001F;       // untere 5 bit
      char component_2 = (bits[i] & 0x03E0)>>5;  // mittlere 5 bit
      char component_3 = (bits[i] & 0x7C00)>>10; // obere 5 bit
    }
    

    Ungetestet 🙂



  • Bist du sicher, das da ein Paddingbit enthalten ist?
    Imho werden für rot und blau jeweils 5 bit verwendet, für grün 6 bit da das Auge für grün am empfindlichsten ist.



  • @anonymus

    Ich hab mich damit noch nicht im detail auseinandergesetzt, da ich erstmal die hürde mit der bitmanipulation schaffen möchte. Laut unserer Angabe ist aber das 6. bit beim blauwert einfach nur ein padding bit und wird nicht verwendet.

    @ihoernchen

    danke für den tip. Ich hab versucht die einzelnen komponenten so zu manipulieren

    component_1 = 0xff>>3;
    component_2 = 0x00>>3;
    component_3 = 0x00>>3;
    

    Wenn ich mir die 3 variablen im debugger in binärform anschaue steht die erste auf 11111 und die beiden anderen auf 0. Wenn ich das mit dem shiften richtig verstanden habe müsste das passen.

    Leider krieg ich das schreiben der 3 werte in das short array nicht hin, hier mein Versuch:

    testData[0] = component_1 & 0x001F;
    testData[0] = (component_2 & 0x03E0)>>5;
    testData[0] = (component_2 & 0x7C00)>>10;
    

    Das scheint aber nicht zu funktionieren, zumindest krieg ich immer nen schwarzen Pixel. Eigentlich sollte er ja rot sein. Zumindest manipuliere ich nur einen Pixel, also das müsste schon mal passen 😉



  • pulse00 schrieb:

    Ich hab versucht die einzelnen komponenten so zu manipulieren

    component_1 = 0xff>>3;
    component_2 = 0x00>>3;
    component_3 = 0x00>>3;
    

    Wenn ich mir die 3 variablen im debugger in binärform anschaue steht die erste auf 11111 und die beiden anderen auf 0. Wenn ich das mit dem shiften richtig verstanden habe müsste das passen.

    Mit dem Shift Operator schiebst du die Bits um X Positionen nach Links oder Rechts.

    char c = 0x01; // binär 0000 0001
    char s = c << 1; // schiebe alle bits von c um 1 nach links
    // s = 0000 0010
    s = c >> 1; // schiebe alle bits von c um 1 nach rechts
    // s = 0000 0000, das bit ganz rechts wird "raus-geshiftet"
    
    c = 0x10; // 0001 0000
    s = c << 1;
    // s = 0010 0000
    
    s = c >> 1;
    // s = 0000 1000
    

    pulse00 schrieb:

    Leider krieg ich das schreiben der 3 werte in das short array nicht hin, hier mein Versuch:

    testData[0] = component_1 & 0x001F;
    testData[0] = (component_2 & 0x03E0)>>5;
    testData[0] = (component_2 & 0x7C00)>>10;
    

    Das scheint aber nicht zu funktionieren, zumindest krieg ich immer nen schwarzen Pixel. Eigentlich sollte er ja rot sein. Zumindest manipuliere ich nur einen Pixel, also das müsste schon mal passen 😉

    Ich meinte nicht, dass du die in das short array schreiben sollst. Sondern von da holen. Das sollte nur das spätere bearbeiten vereinfachen. Einfach, weil du 2 byte pro pixel hast und nicht einen.

    Was du da in dem Beispiel machst verstehe ich nicht.
    Mein Beispiel oben soll, sofern es richtig ist, die 3 5-Bit Farbwerte aus deinem array extrahieren.
    Was hast du denn vor...?



  • ich muss die 3 Farbwerte extrahieren, verändern, und dann wieder in das short* array schreiben.

    Hier meine Pixel Klasse:

    CPixelFormat_16::CPixelFormat_16(BITMAP_HEADER &header, char* data) {
    
      m_header = header;
      testData = reinterpret_cast<short*>(data); // -> testdata ist so definiert: short* testData
    
    }
    

    in der klasse habe ich eine methode um einem einzelnen Pixel einen Farbwert zuzuweisen. So wie ich das verstanden hab muss ich erst aus dem short array ein short holen und mit bitshifting den 3 chars zuweisen:

    char component_1 = testData[pixel] & 0x001F;
    char component_2 = (testData[pixel] & 0x03E0)>>5;
    char component_3 = (testData[pixel] & 0x7C00)>>10;
    

    Hier greife ich ja immer auf das gleiche short zu (1 pixel), und shifte nur die bits so, damit ich die entsprechenden farbwerte extrahiere.

    Danach manipuliere ich die 3 einzelnen werte:

    component_1 = 0xff>>3;
    component_2 = 0x00>>3;
    component_3 = 0x00>>3;
    

    Das >> 3 verwende ich, weil ein char ja 8 bit hat und ich aber nur 5 verwenden kann... Bin mir nicht sicher ob das so funktioniert.

    Wenn das erledigt ist, muss ich die 3 chars irgendwie wieder in das pixel (ein element im short array) schreiben:

    testData[pixel] = component_1 & 0x001F;
    testData[pixel] = (component_2 & 0x03E0)>>5;
    testData[pixel] = (component_2 & 0x7C00)>>10;
    

    Wie ich das mache scheint aber offenbar ein Blödsinn zu sein. Mir ist nur nicht ganz klar, wie ich die 3 chars wieder in ein short zurückcasten kann um es dann ins array zu schreiben...

    Um das ganze zusammenzufassen:

    1. Ich caste das char* array in ein short* array, somit habe ich in einem short 16 bits -> 3 farbwerte -> 1 pixel.
    2. Aus dem short Wert hol ich mir per bitshifting die einzelnen farbwerte (2x5 + 1x6 bits)
    3. Farbwerte manipulieren
    4. Die 3 Farbwerte wieder in einem short unterbringen, um sie im pixelArray schreiben zu können.



  • Du musst die Bits an die richtige Position shiften und mit Bitweisem-Oder (|) verknüpfen.

    bits[i] = (component_3<<10) | (component_2<<5) | component_1;
    
    Da component ein char ist es möglich, dass die Bits rausgeshiftet werden.
    bits[i] = (((short)component_3)<<10) | (((short)component_2)<<5) | component_1;
    Sollte klappen. Oder vielleicht sind einzel Schritte besser.
    

    Bedeutet: nimm component_3, schiebe die Bits 10 Positionen nach links. Bitweise verknüpfen (|) mit component_1 und component_2.

    Schau dir am besten mal ein Tutorial zu dem Bitshift kram an.



  • unsigned short farbe;
    unsigend char b=farbe;
    unsigend char g=farbe>>5;
    unsigend char r=farbe>>11;
    //hier manipulieren, dabei immer den maximalwert im auge behalten
    farbe=b|(g<<5)|(r<<11);
    

    Das hier sollte eigentlich hinkommen für das was du da willst, zum Glück gibts 32bit Farben, die sind einfacher.



  • das mit dem bitweise verknüpfen war der springende Punkt, danke Dir.

    Werd mir ein tutorial ansehen um das ganze auch wirklich zu verstehen. Danke vielmals für die Hilfe.


Anmelden zum Antworten