bitmap rotation



  • Hi.. Also mein Problem ist, dass ich ein Bild (bitmap) rotieren lassen will und es einfach nicht klappen will 🙂

    Zunächst hab ich es so versucht, wie es hier beschrieben wird: http://www.forumromanum.de/member/forum/forum.cgi?USER=user_18391&ACTION=view&ENTRY=1000650082&mainid=1000650082

    Wenn ich dies nun versuche (also rotateflag usw.), kommt zwar keine Fehlermeldung, aber ein Bild kommt auch nicht (schon garnicht ein rotiertest -.-)

    Nun war mein nächster Versuch es mit getPixel und setPixel zu probieren (also per Hand). Glücklicherweise hab ich gleich eine page gefunden, die dies (angeblich) beschreibt: http://www.codeguru.com/Cpp/G-M/bitmap/specialeffects/article.php/c1743/

    Dummweise benutzt das Programm CDC, was wohl ein typ ist, der in den MFC definiert wird. Da ich Borland c++ benutzte hab ich aber keine MFC classes (jedenfalls findet er keine AFXWIN.H -.-).

    Nach dieser (erneuten) Enttäuschung dacht ich mir einfach: "ach, mach ich einfach 2 bitmaps und dann mach ich meine rotation mit setPixel und getPixel. Den cdc quatsch lass ich einfach weg :)"
    Nachdem ich erfolgreich alles nach "CDC" anmutende aus dem Programm gelöscht hatte, fiel mir auf, dass setPixel und getPixel nicht funktioniert :o. Ich probierte zunächst eine BITMAP "test" zu machen und dann per test.setPixel(test,5,6,RGB(0,0,0)); einen schwarzen Pixel auf das Bild zu machen. Dies ergab (oder ergibt) den Fehler: "E2316 'setPixel' ist kein Element von 'tagBITMAP' in Funktion GetRotatedBitmap(HBITMAP__ ,float,unsigned long) in Zeile 76"
    Nun dacht ich mir: "naja versuchs mal mit HBITMAP". Bei HBITMAP ergibt das Ganze folgenden, interessanten Fehler: "E2294 Auf linker Seite der Struktur ist . oder .
    erforderlich in Funktion GetRotatedBitmap(HBITMAP__ *,float,unsigned long) in Zeile 76"

    Nach zahlreichen anderen Versuchen irgendwie das Bitmap gedreht zu kriegen, wende ich mich nun an Euch mit der Bitte:
    Kann mir hier vielleicht irgend einer erklären, wie zum teufel ich ein HBITMAP oder auch eine Surface mit BORLAND c++ drehen kann. Am besten so, dass ich als C++ newbie das auf verstehen (am besten auch umsetzen) kann 😉 Danke 🙂



  • Ich kann dir zwar keine fertige Lösung anbieten aber in der MSDN hab ich folgendes gefunden: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_0iwe.asp

    Es ist praktischerweise eine einzige API-Funktion (aber leider nur verfügbar auf NT-basierenden Systemen). Nur welche Parameter man übergeben muss damit es eine Bitmap rotiert weiß ich nicht...



  • ok .. nu hab ichs zwar geschafft mein rotes TEST-Bild zu rotieren, aber nachher ist es weiß -.-. Zum rotieren hab ich folgende Methode genutzt:

    HBITMAP GetRotatedBitmapNT( HBITMAP hBitmap, float radians, COLORREF clrBack )
    {
            // Create a memory DC compatible with the display
            HDC sourceDC, destDC;
            sourceDC = CreateCompatibleDC( NULL );
            destDC = CreateCompatibleDC( NULL );
    
            // Get logical coordinates
            BITMAP bm;
            ::GetObject( hBitmap, sizeof( bm ), &bm );
    
            float cosine = (float)cos(radians);
            float sine = (float)sin(radians);
    
            // Compute dimensions of the resulting bitmap
            // First get the coordinates of the 3 corners other than origin
            int x1 = (int)(bm.bmHeight * sine);
            int y1 = (int)(bm.bmHeight * cosine);
            int x2 = (int)(bm.bmWidth * cosine + bm.bmHeight * sine);
            int y2 = (int)(bm.bmHeight * cosine - bm.bmWidth * sine);
            int x3 = (int)(bm.bmWidth * cosine);
            int y3 = (int)(-bm.bmWidth * sine);
    
            int minx = min(0,min(x1, min(x2,x3)));
            int miny = min(0,min(y1, min(y2,y3)));
            int maxx = max(0,max(x1, max(x2,x3)));
            int maxy = max(0,max(y1, max(y2,y3)));
    
            int w = maxx - minx;
            int h = maxy - miny;
    
            // Create a bitmap to hold the result
            HBITMAP hbmResult = ::CreateCompatibleBitmap(CreateCompatibleDC( NULL ), w, h);
    
            HBITMAP hbmOldSource = (HBITMAP)SelectObject( sourceDC, hBitmap );
    
            HBITMAP hbmOldDest = (HBITMAP)SelectObject( destDC, hbmResult );
    
             //Draw the background color before we change mapping mode
            HBRUSH hbrBack = CreateSolidBrush( clrBack );
          HBRUSH hbrOld = (HBRUSH)SelectObject( destDC, hbrBack );
           PatBlt( destDC, 0, 0, w, h, PATCOPY );
            ::DeleteObject( SelectObject( destDC, hbrOld ) );
    
            // We will use world transform to rotate the bitmap
            SetGraphicsMode(destDC, GM_ADVANCED);
            XFORM xform;
            xform.eM11 = cosine;
            xform.eM12 = -sine;
            xform.eM21 = sine;
            xform.eM22 = cosine;
            xform.eDx = (float)-minx;
            xform.eDy = (float)-miny;
    
            SetWorldTransform( destDC, &xform );
    
            // Now do the actual rotating - a pixel at a time
            BitBlt(destDC,0,0,bm.bmWidth, bm.bmHeight,sourceDC, 0, 0, SRCCOPY );
    
            // Restore DCs
            ::SelectObject( sourceDC, hbmOldSource );
            ::SelectObject( destDC, hbmOldDest );
    
            return hbmResult;
    }
    

    die hier aufgerufen wird:

    BOOL LoadPic(LPCSTR lpcFileName, LPDIRECTDRAWSURFACE7 *lplpDestSurf7, DDSURFACEDESC2 *lpDestDesc2)
    {
            HBITMAP hbm;
            BITMAP  bm;
            HDC hdcPic, hdcSurf;
    
            hbm = (HBITMAP)LoadImage(NULL, lpcFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
    
            //hier wird Rotationsmethode aufgerufen
            hbm = GetRotatedBitmapNT(hbm,3.1415,NULL);
    
            if (hbm == NULL)
            {
                    MessageBox(NULL, "Konnte Bild nicht laden", NULL, MB_OK);
                    return FALSE;
            }
    
            GetObject(hbm, sizeof(bm), &bm);
    
            lpDestDesc2->dwSize = sizeof(DDSURFACEDESC2);
            lpDestDesc2->dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
            lpDestDesc2->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
            lpDestDesc2->ddsCaps.dwCaps2 = 0;
            lpDestDesc2->dwWidth  = bm.bmWidth;
            lpDestDesc2->dwHeight = bm.bmHeight;
    
            if (lpDirectDraw->CreateSurface(lpDestDesc2, lplpDestSurf7, NULL) != DD_OK)
            {
                    MessageBox(NULL, "Erzeugen der Bildzeichenfläche fehlgeschlagen!", NULL, MB_OK);
                    DeleteObject(hbm);
                    return FALSE;
            }
            if ((*lplpDestSurf7)->GetSurfaceDesc(lpDestDesc2) != DD_OK)
            {
                    MessageBox(NULL, "Konnte komplette Bildsurfacebeschreibung nicht hohlen", NULL, MB_OK);
                    DeleteObject(hbm);
                    return FALSE;
            }
    
            hdcPic = CreateCompatibleDC(NULL); //ein Gerät im Speicher erzeugen
    
        SelectObject(hdcPic, hbm); //diesem nun das Bild zuweisen, dabei
                                   //werden vom GDI die Farben angepasst
            //hohlen des Gerätehandels der Bildzeichenfläche
        if ((*lplpDestSurf7)->GetDC(&hdcSurf) != DD_OK)
        {
                    MessageBox(NULL, "GetDC der Bildzeichenfläche fehlgeschlagen", NULL, MB_OK);
                    DeleteDC(hdcPic);
                    DeleteObject(hbm);
                    return FALSE;
        }
            //das kopieren der Bildinhalte von einem Gerät zum anderen
            BitBlt(hdcSurf, 0, 0, bm.bmWidth, bm.bmHeight, hdcPic, 0, 0, SRCCOPY);
            //Gerätehandel der Bildzeichenfläche wieder freigeben
            (*lplpDestSurf7)->ReleaseDC(hdcSurf);
    
            //dieses Gerät wieder entfernen, da es nicht mehr benötigt wird
            DeleteDC(hdcPic);
    
            //das Bitmap wird nicht länger gebraucht -> Speicherfreigabe
            DeleteObject(hbm);
            return TRUE;
    }
    

    die wiederrum in winmain aufgerufen wird

    LoadPic("Test.bmp",&lpddsBitmap,&bitmapsurface);
    SetRect(&rectbitmap, 220, 165, 420, 315);
    

    und später dann

    lpddsBack->Blt(&rectbitmap, lpddsBitmap, NULL, DDBLT_WAIT, NULL);
    

    wenn ich ein buntes auto-bild reinmache, bleibt nur ein weißer strich vom vorher so bunten auto übrig oo


Anmelden zum Antworten