ein Bild skalieren...



  • in C# kein Problem, versuchte es in C++ auf ähnliche Weise aber schaffe es einfach nicht.
    Die Qualität sollte so hoch wie möglich sein (versuchte daher zuerst den InterpolationMode aber der wird nun nirgends eingesetzt da die Klasse atl::CImage ist und ich ihn da nirgends einsetzen kann), zuerst versuchte ich einfach mal etwas funktionierendes hinzubekommen:

    CImage img;
    
    CRect originalclientrect;
    int dGroessenFaktor;
    
    inline void Resize(int width, int height) {
    
    	Gdiplus::InterpolationMode mode=Gdiplus::InterpolationModeHighQualityBicubic;
    	CBitmap b;
    	CDC c;
    	CDC* imgDC=(CDC*)img.GetDC();
    	c.CreateCompatibleDC(NULL);
    
    	b.CreateBitmap(width, height, 1, 32, NULL);
    
    	c.SelectObject(b);
    	//img.Draw(c.m_hDC,0,0,width, height,0,0,img.GetWidth(), img.GetHeight());
        img.StretchBlt(c.m_hDC,0,0,width, height,HALFTONE);
    
    	img.Attach((HBITMAP)b.Detach());
    	c.DeleteDC();
    //  c.BitBlt(0,0,width,height,imgDC,0,0,SRCCOPY);
    
    	/*
    	Gdiplus::Graphics g(img2.GetDC());
    	g.SetInterpolationMode(mode);
    	g.DrawImage(reinterpret_cast<Gdiplus::Image*>(&img), 1,1,width, height);
    	*/
    
    }
    

    Das resultiert in 1, 2 Debug-Assertion Fehlern sowie dass ein Bildausschnitt gemacht wird, anstatt das Bild skaliert!
    Vorhergehende Versuche sind teilweise noch als Kommentare vorhanden.
    Wie mache ich das richtig (und so gut wie möglich)
    Danke 🙂



  • Das Problem wird in Zeile 21 entstehen, da das Bitmap was du detachen willst, ja noch im CDC selectiert ist. Dies kann durchaus 1-2 Debug-Fehler bringen. Aber getestet hab ich das nicht, ich vermute das nur.

    Gruß Matthias



  • Ach so! Wie bekomme ich es dann vom CDC los vorher?
    Könnte es sein dass dadurch das Bild nicht neu gezeichnet wird und nur der Bereich verkleinert, so dass ein Ausschnitt entsteht?



  • Los bekommste das wie immer, indem du das alte Bitmap wieder in den DC selectierst, ob sich dein Problem mit dem Zeichnen lösst weiss ich net, aber vielleicht das problem das dir dir GDI-Handels ausgehen.

    Also in Zeile 16 dir die Rückgabe merken und dann wieder Reinselektieren, oder SaveDC und RestoreDC (glaub heisst so) benutzen.

    Gruß Matthias



  • Habe den Code nun folgendermassen abgeändert:

    HGDIOBJ restore=c.SelectObject(b);
    	//img.Draw(c.m_hDC,0,0,width, height,0,0,img.GetWidth(), img.GetHeight());
        img.StretchBlt(c.m_hDC,0,0,width, height,HALFTONE);
    	c.SelectObject(restore);
    	img.Attach((HBITMAP)b.Detach());
    

    es passiert aber noch immer genau das Selbe wie vorher



  • Da mir nicht ganz klar is was du mit den DCs und bitmaps machst, hab ich das mal weggelassen.

    das entscheidente sind eh nur 2 Zeilen:

    Gdiplus::InterpolationMode mode=Gdiplus::InterpolationModeHighQualityBicubic;
    
    		CImage img;
    		img.Load("C:\\Sonstige_006.jpg");
    
    		dc.SetStretchBltMode(HALFTONE);
    
    		img.StretchBlt(dc.m_hDC,0,0,rect.Width(),rect.Height(),SRCCOPY );
    

    und so Funktioniert das dann auch.

    dc = der CPaintDC meines Testdialoges, ich hab das Stück gleich in der OnPaint getestet

    Rest wirst du bestimmt selbst rausfinden .

    Gruß Matthias



  • Das ist soweit klar; vielen Dank. In OnPaint und OnPrint hatte ich damit keine Probleme (dort wird das Bild auch skaliert um eine zoombare Ansicht zu erhalten).

    Nun hier ist's

    inline void Resize(int width, int height)
    

    eine Funktion ausserhalb einer Paint-Methode um das Bild zu skalieren und so zu speichern, und da muss ein (unabhängiger) DC selbst besorgt werden, darum das Ganze mit den Bitmaps etc. Vielleicht habe ich da etwas falsch gemacht?
    Da das Bild definitiv verändert werden sollte, soll es auch wieder in das CImage img zurückgespeichert werden, wo es herkommt.



  • So vielleicht?

    void CTest100Dlg::OnBnClickedTest()
    {
    	Gdiplus::InterpolationMode mode=Gdiplus::InterpolationModeHighQualityBicubic;
    
    	CImage img,img1;
    	img.Load("C:\\Sonstige_006.jpg");
    
    	img1.Create(300,300,32);
    
    	CDC dc;
    	dc.Attach(img1.GetDC());
    
    	dc.SetStretchBltMode(HALFTONE);
    
    	img.StretchBlt(dc,0,0,300,300,SRCCOPY );
    
    	dc.Detach();
    
    	img1.ReleaseDC();
    
    	img = img1; 
    
    	img.Save("C:\\Sonstige_006_1.jpg");
    }
    

    Gruß Matthias



  • Das werde ich bald ausprobieren; schaut jedenfalls einfacher aus als meine Versuche (der

    g.DrawImage(reinterpret_cast<Gdiplus::Image*>(&img), 1,1,width, height);
    

    war ja am besten 😃 ) und genau wie ich brauche.

    HALFTONE ist schon der beste Modus oder? InterpolationModeHighQualityBicubic bringt in diesem Fall wohl nichts da eine andere Methode verwendet wird ...
    Vielen vielen Dank, werde dann über den Erfolg berichten 🙂



  • Das Programm lässt sich zwar kompilieren, aber erzeugt einen Debug Assertion Fehler in atlimage.h Zeile 1217, Expression: hBitmap==m_hBitmap

    Danach wird kein Bild mehr angezeigt, bei Neuzeichnen des Views erscheint die Meldung jeweils wieder.

    Das Projekt ist hier zu finden: http://rebenstudio-it.ch/~daten/mfcBildbearbeitung.zip



  • Hab mal dein Projekt runtergeladen, der Stiel den du da verfolgst, na ja ich will mich mal net aufregen, aber warum benutzt du andauernd wsprintf und char und lauter solche sachen wenn es doch einfacher mit SetDlgItemInt geht? Aber das nur am Rande. Des weiternen würde ich aus der ImageDeklaration schon mal eine richtige Klasse machen, ich welcher Du alle Funktionen Deklkarierst die mit dem Image zusammenhängen. Als letztes würde ich mir nur einen Zeiger auf das Image merken, den kannste einfach austauschen und Abfragen und so haste erst mal einen Teil geschafft, denn Arbeit hast du noch genug, Hintergrund Löschen usw.

    Das alles ist nur konstrucktive Kritik, ich wollte auf keinen Fall über dich herziehen.

    Gruß Matthias



  • Danke, ja SetDlgItemInt kannte ich nicht; scheint dies zu vereinfachen. Ich verwende auch ziemlich oft SendMessage und sonst "altmodischen C-Stil", bin ich mir besser gewohnt in diesem Zusammenhang irgendwie.
    EIne eigene Klasse habe ich mir auch schon überlegt, so wie beim C#-Projekt:

    namespace Bildbearbeitungsprogramm
    {///<summary>
        ///Dieses Interface definiert die grundlegensten Methoden der Version 1.6 (Okt. 2008)
        ///</summary>
        #region Interface
        public interface IBildbearbeitung
        {
            Bitmap GetBitmap();
            void addFile(string Filename);
            Bitmap GetBitmapZoom(int percent);
            Bitmap Bildverkleinern(int height, int width);
            Size Bildgroesse();
            Bitmap Bilddrehen();
        #endregion
    
        }
    
        /// <summary>
        /// Dieses Interface implementiert die Erweiterungen für die Versionen nach 1.6
        /// </summary>
        public interface IBildbearbeitung2
        {
            void replaceBitmap(Bitmap neuesBild);
            Bitmap Brighten(int nBrightness);
        }
    
        ///<summary>
        ///In dieser Klasse wird die gesamte Funktionalität des Programmes bereitgestellt
        ///   </summary>
        #region Class Bildbearbeitung Basisklasse
    
        public class Bildbearbeitung : IBildbearbeitung
        {
            protected Bitmap bild; //enthält das Bild; dieses wird bearbeitet, keine Kopie des Originales behalten.
            public Bildbearbeitung(string Filename)
            {
                string Dateiname = Filename;
                bild = new Bitmap(Dateiname, true);
    
            }
            public Bildbearbeitung(Bitmap BildBitmap)
            {
                bild = BildBitmap;
            }
            public Bildbearbeitung() { }
    
            ///<summary>
            ///Datei hinzufügen (öffnen)
            ///</summary>
            public void addFile(string Filename)
            {
                string Dateiname = Filename;
                bild = new Bitmap(Dateiname, true);
            }
    
            /// <summary>
            /// Das Bild wird als Bitmap zurückgeliefert (wenn bearbeitet dann die bearbeitete Version)
            /// </summary>
            /// <returns>Bitmap-Objekt (ggf. gedreht, ggf. bearbeitet)</returns>
            public Bitmap GetBitmap()
            {
                return bild;
            }
            /// <summary>
            /// Liefert das Bitmap verkleinert/vergrössert zurück; falls es gedreht wurde dann in der Bearbeiteten Version; int-Wert=Faktor. Die Originalversion bleibt bestehen! Für Zoom-Ansicht
            /// </summary>
            /// <param name="percent"></param>
            /// <returns>verkleinertes/vergrössertes Bitmap-Obj</returns>
            public Bitmap GetBitmapZoom(int percent)
            {
                int pSize = percent;
                /*Bitmap bild2 = (Bitmap)bild.GetThumbnailImage((bild.Width * 100) / percent, (bild.Height * 100) / percent, null, IntPtr.Zero);
                return bild2;
                  */
                Bitmap pImage = bild;
                int x, y;
    
                if (pImage.Width > pImage.Height)
                {
                    x = pSize;
                    y = Convert.ToInt32(((float)pImage.Height / (float)pImage.Width * pSize));
                }
                else
                {
                    y = pSize;
                    x = Convert.ToInt32(((float)pImage.Width / (float)pImage.Height * pSize));
                }
                Image ret = new Bitmap(x, y);
                Graphics g = Graphics.FromImage(ret);
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.DrawImage(pImage, 0, 0, x, y);
                g.Dispose();
    
                return ret as Bitmap;
            }
            /// <summary>
            /// Verkleinert/vergrössert das Bild nach Höhe/Breite DEFINITIV (keine Kopie wird behalten)
            /// </summary>
            /// <param name="height"></param>
            /// <param name="width"></param>
            /// <returns>Bearbeitetes Bitmap-Obj</returns>
            public Bitmap Bildverkleinern(int height, int width)
            {
                int x, y;
    
                x = width;
                y = height;
    
                Image ret = new Bitmap(x, y);
                Graphics g = Graphics.FromImage(ret);
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.DrawImage(bild, 0, 0, x, y);
    
                g.Dispose();
                bild = ret as Bitmap;
                return bild;
            }
    
            /// <summary>
            /// Dreht das Bild (Original) um 90 Grad und liefert es zurück
            /// </summary>
            /// <returns>Gedrehtes Bitmap-Obj</returns>
            public Bitmap Bilddrehen()
            {
    
                bild.RotateFlip(RotateFlipType.Rotate90FlipNone);
                return bild;
            }
    
            /// <summary>
            /// Liefert Bildgrösse zurück
            /// </summary>
            /// <returns>Size-Objekt</returns>
            public Size Bildgroesse()
            {
                return bild.Size;
            }
    
        }
        #endregion
    
        /// <summary>
        /// Dies ist die erweiterte Klasse der Versionen über 1.6 (bis auf Weiters)
        /// </summary>
        public class Bildbearbeitung_extended : Bildbearbeitung, IBildbearbeitung2
        {
            public Bildbearbeitung_extended(string Filename) : base(Filename) { }
            public Bildbearbeitung_extended(Bitmap BildBitmap) : base(BildBitmap) { }
            public Bildbearbeitung_extended() { }
    
            /// <summary>
            /// Fügt ein neues Bitmap hinzu resp. ersetzt das Bild in der Objektinstanz
            /// </summary>
            /// <param name="neuesBild"></param>
            public void replaceBitmap(Bitmap neuesBild)
            {
                bild = neuesBild;
    
            }
            /// <summary>
            /// Verändert die Helligkeit. Verwendet unsafe-Code! Rückgabewert ist das veränderte Bitmap. Verändert Bild definitiv.
            /// </summary>
            public Bitmap Brighten(int nBrightness)
            {
    
                System.Drawing.Imaging.BitmapData bmData
                = bild.LockBits(new Rectangle(0, 0, bild.Width, bild.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                int stride = bmData.Stride;
                System.IntPtr Scan0 = bmData.Scan0;
                unsafe
            usw.......
    

    vorerst entschloss ich mich in C++ noch dies nicht so zu tun, aber je nach Funktionsumfang welchen ich in der C++-Version dann anstrebe werde ich es noch tun; bin halt in C++ weniger gut wie in C# 🙂


Anmelden zum Antworten