Problem mit StretchBlt von einem CBitmap aus einem CImage



  • Hallo,

    mein Problem ist ähnlich der im Beitrag https://www.c-plusplus.net/forum/341836 dargestellten Problematik.
    In meinem Programm soll ein Firmenlogo auf einem Briefkopf oben rechts dargestellt werden. Dazu liegt die Datei im BMP-Format vor und wird auf eine feste Höhe (150 logische Einheiten, Abbildungsmodus MM_LOMETRIC) skaliert und mittels StretchBlt in den DC gezeichnet. Folgender Code funktioniert soweit einwandfrei:

    if (IfPathFileExist(ExpandGlobalAppDataPath(File_Firmenlogo_RGB)))
    	{
            CDC memDC;
    		CSize ptSize, ptOrg;
    		memDC.CreateCompatibleDC(pDC);
    		CBitmap* oldBitmap;
    		HBITMAP hBmp = (HBITMAP)::LoadImage(NULL,static_cast<LPCTSTR>(ExpandGlobalAppDataPath(File_Firmenlogo_RGB)),IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
    		CBitmap Firmenlogo;
    		Firmenlogo.Attach(hBmp);
    
    		oldBitmap = memDC.SelectObject(&Firmenlogo);
    
    		BITMAP bi;
    		Firmenlogo.GetBitmap(&bi);
    		ptSize.cx=bi.bmWidth;
    		ptSize.cy=bi.bmHeight;
    		pDC->DPtoLP(&ptSize);
    
    		double dNewLogoWidth=dNewLogoHeight*static_cast<double>(ptSize.cx)/static_cast<double>(ptSize.cy);
    		iLogoHeight=static_cast<int>(dNewLogoHeight);
    		iLogoWidth=static_cast<int>(dNewLogoWidth);
    		ptOrg.cx=0;
    		ptOrg.cy=0;
    		memDC.DPtoLP(&ptOrg);
    		m_rcPrintDataRect.top=m_rcPrintRect.top-iLogoHeight;
    		m_rcPrintDataRect.bottom=m_rcPrintRect.bottom+iLogoHeight;
    
    		pDC->StretchBlt(m_rcPrintRect.right-iLogoWidth,m_rcPrintRect.top,iLogoWidth,-iLogoHeight,&memDC,ptOrg.cx,ptOrg.cy,bi.bmWidth,bi.bmHeight,SRCCOPY);	 
    		memDC.SelectObject(oldBitmap);
    
    	}
    

    Jetzt soll das so umgestellt werden, dass auch andere Dateitypen (vorrangig jpg) geladen werden können. Ich habe die Anmerkungen im o.g. Betrag wie folgt umgesetzt:

    if(IfPathFileExist(ExpandGlobalAppDataPath(File_Firmenlogo_RGB)))
    	{
    		CDC memDC;
    		CSize ptSize, ptOrg;
    		memDC.CreateCompatibleDC(pDC);
    		CBitmap* oldBitmap;
    		CImage Image;
    		Image.Load(ExpandGlobalAppDataPath(File_Firmenlogo_RGB));
    		CBitmap Firmenlogo;
    		Firmenlogo.Attach(Image.Detach());
    
    		oldBitmap = memDC.SelectObject(&Firmenlogo);
    
    		BITMAP bi;
    		Firmenlogo.GetBitmap(&bi);
    		ptSize.cx = bi.bmWidth;
    		ptSize.cy = bi.bmHeight;
    		pDC->DPtoLP(&ptSize);
    
    		double dNewLogoWidth = dNewLogoHeight*static_cast<double>(ptSize.cx) / static_cast<double>(ptSize.cy);
    		iLogoHeight = static_cast<int>(dNewLogoHeight);
    		iLogoWidth = static_cast<int>(dNewLogoWidth);
    		int Test = 150 * ptSize.cx / ptSize.cy;
    		ptOrg.cx = 0;
    		ptOrg.cy = 0;
    		memDC.DPtoLP(&ptOrg);
    		m_rcPrintDataRect.top = m_rcPrintRect.top - iLogoHeight;
    		m_rcPrintDataRect.bottom = m_rcPrintRect.bottom + iLogoHeight;
    
    		pDC->StretchBlt(m_rcPrintRect.right - iLogoWidth, m_rcPrintRect.top, iLogoWidth, -iLogoHeight, &memDC, ptOrg.cx, ptOrg.cy, bi.bmWidth, bi.bmHeight, SRCCOPY);
    		memDC.SelectObject(oldBitmap);
    
    	}
    

    Hier soll ja die Datei in ein CImage geladen werden und dies dann an die CBitmap übergeben werden. Auch dieser Code funktioniert, wenn die Bilddatei als Bitmap vorliegt. Nehme ich dann eine jpg-Datei der gleichen Größe, dann wird in der Ausgabe das Bild auf ein Viertel verkleinert in der linken oberen Ecke des eigentlichen Ausgabebereiches gezeichnet und der Rest des Ausgabebereiches ist schwarz. Das hatte der andere Threadersteller auch geschrieben. Beim Debuggen sieht man, dass StretchBlt() in beiden Fällen die gleichen Parameter übergeben bekommt. Daher vermute ich den Fehler bei Firmenlogo.Attach(Image.Detach()), da sich offensichtlich jpg-Dateien hier anders verhalten. Kann mir hier jemand weiterhelfen?


  • Mod

    Warum der Umweg?
    Warum benutzt Du nicht CImage::StretchBlt?



  • Martin Richter schrieb:

    Warum der Umweg?
    Warum benutzt Du nicht CImage::StretchBlt?

    Das war jetzt mal auf die Schnelle gestrickt. Müsste ja aber funktionieren. Komisch ist, dass der andere Threadersteller offensichtlich das gleiche Problem hatte nur das es dann bei ihm weg war. Hab das jetzt mal geändert:

    if(IfPathFileExist(ExpandGlobalAppDataPath(File_Firmenlogo_RGB)))
    	{
    		CDC memDC;
    		CSize ptSize, ptOrg;
    		memDC.CreateCompatibleDC(pDC);
    
    		CImage Image;
    		Image.Load(ExpandGlobalAppDataPath(File_Firmenlogo_RGB));
    		ptSize.cx = Image.GetWidth();
    		ptSize.cy = Image.GetHeight();
    		pDC->DPtoLP(&ptSize);
    
    		// Skalieren des Firmenlogos auf cFirmenlogo_maxHeight
    		dNewLogoWidth = dNewLogoHeight*static_cast<double>(ptSize.cx) / static_cast<double>(ptSize.cy);
    
    		if (dNewLogoWidth > cFirmenlogo_maxWidth)	// falls durch die Skalierung der Höhe die Breite jetzt größer als cFirmenlogo_maxWidth geworden ist, muss das Logo wieder verkleinert werden
    		{
    			dNewLogoHeight = dNewLogoHeight * (cFirmenlogo_maxWidth / dNewLogoWidth);
    			dNewLogoWidth = cFirmenlogo_maxWidth;
    		}
    		iLogoHeight = static_cast<int>(dNewLogoHeight);
    		iLogoWidth = static_cast<int>(dNewLogoWidth);
    
    		ptOrg.cx = 0;
    		ptOrg.cy = 0;
    		memDC.DPtoLP(&ptOrg);
    		m_rcPrintDataRect.top = m_rcPrintRect.top - iLogoHeight;
    		m_rcPrintDataRect.bottom = m_rcPrintRect.bottom + iLogoHeight;
    
    		Image.StretchBlt(*pDC, m_rcPrintRect.right - iLogoWidth, m_rcPrintRect.top, iLogoWidth, iLogoHeight, ptOrg.cx, ptOrg.cy, Image.GetWidth(), Image.GetHeight());
    
    	}
    

    Jetzt ist das Bild zwar so Breit wie man es braucht, jedoch ist es nur 2-3 Zeilen hoch.


  • Mod

    Sind denn die Werte plausibel, die ermittelst und berechnest?



  • Martin Richter schrieb:

    Sind denn die Werte plausibel, die ermittelst und berechnest?

    Ja die sind plausibel. Das veränderte Beriten-/Höhenverhältnis stimmt und bei der ersten, von als Umweg bezeichneten Variante, funktionierte ja das auch mit CImage und einer Bitmap-Datei. Irgendwas scheint bei JPG anders zu laufen. Bei der letzten Variante läuft aber alles an den Baum, egal ob JPG oder BMP. Die Breite scheint zu stimmen nur die Höhe ergibt einen leicht gemusterten Strich. Wenn ich beide Ausdrucke übereinander lege, dann sieht man, dass exakt nur die oberste Zeile des Bildes gedruckt wird wenn man eine BMP-Datei nimmt. Ist die Vorlage eine JPG-Datei, dann ist diese Strichstruktur wieder auch ein Viertel verkürzt und der Rest des Striches ist komplett schwarz.



  • Ich hab jetzt herausgefunden, dass sich das Zeichnen offensichtlich mit dem Abbildungsmodus behakt. Ich habe pDC->SetMapMode(MM_LOMETRIC) gesetzt. Nehme ich das raus zeichnet er wunderbar (natürlich ist der Rest dann auch verschoben). Mir ist aufgefallen, dass CImage::StretchBlt keine negativen Werte bei den Zeichenbereichen zulässt.

    ATLASSUME( m_hBitmap != NULL );
    	ATLENSURE_RETURN_VAL( hDestDC != NULL, FALSE );
    	ATLASSERT( nDestWidth > 0 );
    	ATLASSERT( nDestHeight > 0 );
    	ATLASSERT( nSrcWidth > 0 );
    	ATLASSERT( nSrcHeight > 0 );
    

    Bei MM_LOMETRIC sind ja aber die Y-Werte negativ. Hat es damit was zu tun? Nur warum klappt dann das Darstellem von Bitmaps und eben nicht von JPGs?


Log in to reply