Laden...

Grafik strecken und pictureBox skalieren

Erstellt von CsharpFan vor 2 Jahren Letzter Beitrag vor 2 Jahren 1.246 Views
C
CsharpFan Themenstarter:in
2 Beiträge seit 2021
vor 2 Jahren
Grafik strecken und pictureBox skalieren

Hallo an alle,
unter WinForms wende ich zum Zeichnen u.a. die StretchBlt-Funktion an, um eine Grafik möglichst schnell zu skalieren:


        void DrawBitmap(Bitmap bmp, IntPtr hwndTarget, Rectangle rectTarget)
        {
            const int SRCCOPY = 0x00CC0020;
            const int HALFTONE = 4;

            IntPtr hdcTarget = GetDC(hwndTarget);
            IntPtr hdcSource = CreateCompatibleDC(hdcTarget);
            SelectObject(hdcSource, bmp.GetHbitmap());
            SetStretchBltMode(hdcTarget, HALFTONE);
            StretchBlt(hdcTarget, rectTarget.X, rectTarget.Y, rectTarget.Width, rectTarget.Height, hdcSource, 0, 0, bmp.Width, bmp.Height, SRCCOPY);
            DeleteDC(hdcSource);
            ReleaseDC(hwndTarget, hdcTarget);
        }

        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        public static extern bool StretchBlt(IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest, IntPtr hdcSrc, int xSrc, int ySrc, int wSrc, int hSrc, uint rop);

        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        static extern IntPtr CreateCompatibleDC(IntPtr hdc);

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern IntPtr GetDC(IntPtr hWnd);

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        static extern bool DeleteDC(IntPtr hdc);

        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        public static extern bool SetStretchBltMode(IntPtr hdc, int mode);

Wende ich meine Funktion an, passt sich die PictureBox nicht an.
Mit anpassen meine ich, dass eine Scrollbar erscheinen sollte, wenn die Grafik über die PictureBox hinausragt.
So erscheint eine Scrollbar, bei größeren Grafiken: pictureBox1.Image = bmp;

Die PictureBox liegt dabei auf einem Panel und und die Eigenschaften sind folgendermaßen gesetzt:
PictureBox Dock = None
PictureBox.SizeMode = AutoSize
Panel.AutoScroll = True

Die Frage ist, wie kann ich zur Laufzeit eine Grafik auswählen, welche um einen Faktor skaliert wird und entsprechend auf der PictureBox abgebildet wird, welche sich mit anpasst (Scrollbars), und das möglichst schnell?

5.658 Beiträge seit 2006
vor 2 Jahren

Wenn du das Bild selber zeichnest, dann mußt du auch selbst die PictureBox skalieren und die Scrollbars anpassen. Oder andersherum das Bild skalieren, damit es in die PictureBox paßt.

Warum sollte die PictureBox eigentlich zu langsam sein, um ein Bild anzuzeigen? Sie wird ja auch nur die GDI-Funktionen des Betriebssystem dafür aufrufen.

Weeks of programming can save you hours of planning

C
CsharpFan Themenstarter:in
2 Beiträge seit 2021
vor 2 Jahren

Nicht die PictureBox, sondern Graphics-Klasse ist m.M.n. langsam.
In einem anderen Projekt habe ich hunderte Vorschaubilder (in Miniaturansicht), die gleichzeitig aufgelistet und nach Änderung des Originals neu geladen werden.
Das Neuladen - in einem separaten Thread - dauerte mir viel zu lange, also habe ich mich, so wie hier, der GDI-Funktionen bedient und dann lief es etwas schneller (laut Zeitmessung).

Ich denke, Graphics.DrawImage() und DrawBitmap() nehmen sich nicht viel, mit dem Unterschied, dass Letzteres nicht nur zeichnet sondern auch skaliert.
Dein Hinweis hat mich weiter gebracht.
Wenn ich vor dem Zeichnen PictureBox.Width und PictureBox.Height passend setze, erscheinen die Scrollbars. Setze ich hingegen PictureBox.Size, wird die Grafik nicht gezeichnet.
Was genau macht die Eigenschaft Size beim Setzen?

16.835 Beiträge seit 2008
vor 2 Jahren

Render-Settings machen generell viel aus, wenns um Geschwindigkeit geht.
GDI+ ist aber technologiebedingt sowieso nicht das aller schnellste, egal wie Du es ansprichst.

Platte Zeitmessungen sind meist falsch. Willst Du was belastbares, dann brauchst nen Benchmark.
Und ja, DrawImage kann langsam sein, vor allem bei großen Bildern wie zB auf einer Zeichenfläche; wie Paint.NET.
Rick Brewster, der Typ hinter Paint.NET hat dazu viel geschrieben.

Wenn Du starke Performance-Einbusen bei WinForms GDI hast, dann liegt das meist an Deinem Code.
Paint.NET verwendet ebenfalls diese Schnittstellen - und hat ganz offenbar kein solchen Issue 🙂

Ich vermute, dass Du Dir unnötig viel Arbeit machst, weil Dein Code selbst ein Fehler/Bottleneck hast/hat und Du nun eben das Einhorn jagst.
Wärst da ehrlich gesagt auch nich der erste 😉