Pixel auf dem Desktop ändern ohne setpixel



  • Hallo Leute,
    ich habe ein Problem und zwar versuche ich verschiedene Pixel auf dem Desktop zu ändern. Das funktioniert auch schon mit setpixel aber das ist viel zu langsam.
    Jetzt wollte ich es so machen, dass man zuerst den Desktop als Bitmap?! speichert und dann in dem Bitmap die entsprechenden Pixel ändert.
    Dann wir das Bitmap wieder auf den Desktop geschrieben.

    so weit bin ich bereits:

    #include <iostream>
    #include <windows.h>
    using namespace std;
    
    int main()
    {
        HDC hDesktopDC = GetDC(0);
        HDC hMemoryDC  = CreateCompatibleDC(hDesktopDC);
        HBITMAP hBM = CreateCompatibleBitmap(hDesktopDC, iXmax, iYmax);
        SelectObject(hMemoryDC, hBM);
    }
    

    aber wie schaffe ich es jetzt die Pixel schnell zu verändern und wieder auf dem Desktop auszugeben? 🙂



  • Man könnte den Desktop auch in Ruhe lassen und ein transparentes Fenster drüber legen und da rein zeichen. Man hätte allerdings etwas Aufwand, dass das Fenster auch oben bleibt und keine Klicks wegfängt.

    Ansonsten: Schau dir mal CreateDIBSection() oder GetDIBits()/SetDIBits() an.
    Hier danach suchen dürfte auch Treffer bringen.



  • Sorry wen ich jetzt nach Code fage aber ich bekomme es einfach nicht hin auch nur ansatzweise einen Pixel zu ändern 😞
    Wäre echt cool wen du mir einen kleines Programm geben könntest 🙂


  • Mod

    HDC hDC = GetDC(NULL);
    SetPixel(hDC,0,0,0);
    DeleteDC(hDC);
    

    Das Pixel ist zwar nicht bleibend verändert, aber wo ist nun die Schwierigkeit gewesen?



  • @Martin Richter
    Er schreibt ja dass er es mit SetPixel schon hinbekommen hat, aber was schnelleres sucht 😉


  • Mod

    OK... gebe mich geschlagen...



    • Bitmap mit CreateDIBSection() erzeugen (Pixel direkt via ppvBits manipulierbar)
    • Bitmap in einen Memory-DC selektieren (CreateCompatibleDC+SelectObject)
    • Desktop in Bitmap kopieren (BitBlt)
    • Pixeldaten via ppvBits anpassen
    • Bitmap via BitBlt zurückkopieren


  • geeky schrieb:

    • Bitmap mit CreateDIBSection() erzeugen (Pixel direkt via ppvBits manipulierbar)
    • Bitmap in einen Memory-DC selektieren (CreateCompatibleDC+SelectObject)
    • Desktop in Bitmap kopieren (BitBlt)
    • Pixeldaten via ppvBits anpassen
    • Bitmap via BitBlt zurückkopieren

    Und das soll schneller als SetPixel sein?



  • Das hängt davon ab wie viele Pixel man ändern möchte 😉

    (Ich persönlich halte ja eigentlich gar nichts davon, direkt auf dem Screen rumzumalen)



  • geeky schrieb:

    • Bitmap mit CreateDIBSection() erzeugen (Pixel direkt via ppvBits manipulierbar)
    • Bitmap in einen Memory-DC selektieren (CreateCompatibleDC+SelectObject)
    • Desktop in Bitmap kopieren (BitBlt)
    • Pixeldaten via ppvBits anpassen
    • Bitmap via BitBlt zurückkopieren

    So das habe ich jetzt soweit (ich hoffe mal das alles richtig ist)
    aber wie kann ich jetzt die einzelnen Pixel an z.B. X=200, Y=250 und RGB... verändern? 🙂

    #include <iostream>
    #include <windows.h>
    using namespace std;
    
    int main()
    {
        int X = GetSystemMetrics(SM_CXSCREEN);
        int Y = GetSystemMetrics(SM_CYSCREEN);
    
        HDC hDesktopDC = GetDC(0);
        HDC hMemoryDC = CreateCompatibleDC(hDesktopDC);
        HBITMAP MemoryBitmap; // = CreateCompatibleBitmap(hDesktopDC, X, Y);
    
        BITMAPINFO bitmapInfo;
        bitmapInfo.bmiHeader.biSize         = sizeof(BITMAPINFOHEADER);
        bitmapInfo.bmiHeader.biWidth        = X;
        bitmapInfo.bmiHeader.biHeight       = Y;
        bitmapInfo.bmiHeader.biBitCount     = 24; //32 farbe
        bitmapInfo.bmiHeader.biPlanes       = 1;
        bitmapInfo.bmiHeader.biCompression  = BI_RGB;
        bitmapInfo.bmiHeader.biSizeImage    = X * Y; //nötig?
    
        MemoryBitmap = CreateDIBSection(hDesktopDC, &bitmapInfo,DIB_RGB_COLORS ,0 , 0,0);
        SelectObject(hMemoryDC,MemoryBitmap);
        BitBlt(hMemoryDC,0,0,X,Y,hDesktopDC,0,0,SRCCOPY); //stimmen die Werte wo null steht was ist "The x-coordinate, in logical units, of the upper-left corner of the destination rectangle."
    
        ///ppvBits wie einzelne pixel verändern?
    
        BitBlt(hDesktopDC,0,0,X,Y,hMemoryDC,0,0,SRCCOPY);
    }
    


  • http://msdn.microsoft.com/en-us/library/windows/desktop/dd183494.aspx schrieb:

    ppvBits [out]
    A pointer to a variable that receives a pointer to the location of the DIB bit values.

    ...über den Parameter denn du aus irgendwelchen nicht gesetzt hast bekommst du einen Zeiger direkt auf die Pixelwerte.

    .biSizeImage: "The size, in bytes, of the image."
    (Ich
    Wäre bei 24bit (=3 Byte pro Pixel) bei 16x16er Auflösung: 16*16*3

    Hier muss allerdings aufgepasst werden: Die Breite bei DIBs muss DWORD-aligned sein (also ein Vielfaches von 4 Bytes sein). Ist die Bitmap z.B. 322x640 groß, wird sie tatsächlich als 324x640 gespeichert - mit unbenutztem "Rand"
    Die Berechnung für biSizeImage für 24bit findet man z.B. hier:
    http://msdn.microsoft.com/en-us/library/windows/desktop/dd145119.aspx
    ...einfacher wäre allerdings die DIB-Section-Bitmap mit 32bit Farbtiefe anzulegen, was ohnehin üblicherweise die Desktop-Farbtiefe ist (genau genommen 24bit mit ungenutztem Alpha-Kanal). Verschwendet zwar ein wenig mehr RAM, macht aber die Berechnung von .biSizeImage sehr einfach (Breite*Höhe*4), da jede Auflösung dann automatisch DWORD-aligned ist und vermutlich BitBlt weniger Arbeit macht 😉

    Die Pixel liegen im Speicherbereich auf den ppvBits zeigt, einfach hintereinander, bei 32bit glaube ich als: (Alpha,Blue,Green,Red)
    (Welche Reihenfolge genau - Ob die unterste Zeile oder die oberste Zeile zuerst und in welcher Reihenfolge die Farbkanäle genau kommen, weiß ich grad spontan nicht)

    Angenommen der Zeiger auf die Pixeldaten heisst pBits, würde man quasi über
    pBits[0] <- Alpha des 1. Pixels
    pBits[1] <- Blue des 1. Pixels
    pBits[2] <- Green des 1. Pixels
    pBits[3] <- Red des 1. Pixels
    pBits[4] <- Alpha des 2. Pixels
    pBits[5] <- Blue des 2. Pixels
    ...
    auf die Pixeldaten zugreifen.



  • Hallo Leute jetzt habe ich nur noch ein Problem und zwar wenn ich jetzt den Pixel X = 5 und Y = 9 auf dem Desktop andern will mus ich ja in dem Zeiger den wert an der Stelle ? ändern und die 3 darrauffolgende Werde auch also
    für blau grün rot Alpha

    aber wie mache ich die umrechnung?
    Es muss ja auch funktionieren wenn ich z.B. den pixel 5,0 ändern will
    (Y*(Xmax+1)+X+1)*4+3 war mein ansatzt aber es geht leider nicht 😞



  • MaxundTutorials schrieb:

    ... aber wie mache ich die umrechnung?
    Es muss ja auch funktionieren wenn ich z.B. den pixel 5,0 ändern will
    (Y*(Xmax+1)+X+1)*4+3 war mein ansatzt aber es geht leider nicht 😞

    Ich würde das nett als Funktion verpacken:

    ///ppvBits wie einzelne pixel verändern? 
    
    for(int i=0 ;i<200; i++) {
      bool r = bmpsetpixel(&bitmapInfo, ppvBits, x, y+i, farbe);
      }
    
    chk = BitBlt(hDesktopDC,0,0,X,Y,hMemoryDC,0,0,SRCCOPY);
    

    Auf die Pixel selbst kann man einfach zugreifen mit:

    ppvBits[pos].rgbBlue = (unsigned char)(farbe & 0xff);  // Blau
    

    Wobei pos meist links unten anfängt ...

    Wenn man den Desktop anschliessend mit BitBlt neu plakatiert, wird es nicht auf Dauer sein.


Anmelden zum Antworten