BitMap Resize klappt nicht...

NetBull

Erfahrenes Mitglied
#1
Moin,

bekomme ein Bild nicht in den Dimensionen verändert.

Code:
private void resize(String aFile, int aSize) {
            Bitmap bmpInput = (Bitmap)Image.FromFile(aFile);
            var resizedImage = new Bitmap(300, 200, PixelFormat.Format24bppRgb);
            resizedImage.SetResolution(bmpInput.HorizontalResolution / 2, bmpInput.VerticalResolution / 2);
            var graphics = Graphics.FromImage(resizedImage);
            var destRect = new Rectangle(0, 0, 300, 200);
            var brush = new SolidBrush(System.Drawing.Color.White);
            graphics.FillRectangle(brush, destRect);
            graphics.DrawImage(bmpInput, destRect, new Rectangle(0, 0, 300, 200), GraphicsUnit.Pixel);
            resizedImage.Save(@"D:\users\dml\Desktop\Test\test.jpg");
        }
Mach ein kleines Bild, aber der Inhalt ist nur abgeschnitten, nicht verkleinert.
Was fehlt mir da oder wie müsste ich das angehen?

cu deAndro!
 
#3
Hallo deAndro

Siehe: Graphics.DrawImage

Parameter 3:
srcRect
Type: System.Drawing.Rectangle
Rectangle structure that specifies the portion of the image object to draw.
Du gibst da also an welchen Teil aus dem Ursprungsbild du zeichnen willst. Da wählst du auch den kleinen Abschnitt 0/0 - 300/200 aus. Entsprechend erhälst du hier lediglich den Ausschnitt aus dem Bild. Du willst aber das ganze Bild auf das kleine zeichnen. Entsprechend muss destRect das kleine sein, srcRect muss das ganze Ursprungsbild sein.

Andere Frage:
Warum setzt du die Auflösung des Bildes auf eine so hohe Anzahl DPI?

Viele Grüsse
Cromon
 

NetBull

Erfahrenes Mitglied
#4
Hmm... wo setze ich die Hohe DPI? Ist mir gerade nicht bewusst.

Code sieht nun so aus:
Code:
private void resizeImage(String aFile, double aNewSize)
        {
            Bitmap bmpInput = (Bitmap)Image.FromFile(aFile);
            double newH = 0;
            double mPercent = 0;
            double newW = 0;            
            FileInfo fi = new FileInfo(aFile);
            String newFilePath = this.txtDestination.Text + "\\" + fi.Name;
            this.txtMessagePanel.AppendText(newFilePath + Environment.NewLine);
            if (bmpInput.Size.Height > bmpInput.Size.Width)
            {
                mPercent = 100.0 / bmpInput.Size.Height * bmpInput.Size.Width;
                newH = aNewSize;                
                newW = newH / 100 * (mPercent);
            }
            else 
            {                
                mPercent = (100.0 / bmpInput.Size.Width) * bmpInput.Size.Height; 
                newW = aNewSize;
                newH = newW / 100 * (mPercent);
            }
            Bitmap newImage = new Bitmap((int)newW, (int)newH);            
            using (Graphics g = Graphics.FromImage(newImage))
            {
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.DrawImage(bmpInput, new Rectangle(0, 0, (int)newW, (int)newH));
            }
            if (!File.Exists(newFilePath))
                newImage.Save(newFilePath);
        }
Und es funktioniert. Wenn ich die Methode nun in einer Schleife ausführe, dann bekomme ich aber nach ca 200 Bildern einen Fehler bei
Code:
g.DrawImage(bmpInput, new Rectangle(0, 0, (int)newW, (int)newH));
Exception:
Code:
System.OutOfMemoryException was unhandled
  HResult=-2147024882
  Message=Nicht genügend Arbeitsspeicher.
  Source=System.Drawing
  StackTrace:
       bei System.Drawing.Graphics.CheckErrorStatus(Int32 status)
       bei System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y, Int32 width, Int32 height)
       bei System.Drawing.Graphics.DrawImage(Image image, Rectangle rect)
       bei ImageResizer.ImageResizer.resizeImage(String aFile, Double aNewSize) in D:\users\dml\documents\visual studio 2010\Projects\ImageResizer\ImageResizer\Form1.cs:Zeile 115.
       bei ImageResizer.ImageResizer.startResizerProgress() in D:\users\dml\documents\visual studio 2010\Projects\ImageResizer\ImageResizer\Form1.cs:Zeile 150.
       bei ImageResizer.ImageResizer.btnStart_Click(Object sender, EventArgs e) in D:\users\dml\documents\visual studio 2010\Projects\ImageResizer\ImageResizer\Form1.cs:Zeile 50.
       bei System.Windows.Forms.Control.OnClick(EventArgs e)
       bei System.Windows.Forms.Button.OnClick(EventArgs e)
       bei System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
       bei System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       bei System.Windows.Forms.Control.WndProc(Message& m)
       bei System.Windows.Forms.ButtonBase.WndProc(Message& m)
       bei System.Windows.Forms.Button.WndProc(Message& m)
       bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       bei System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       bei System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       bei System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       bei System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       bei System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       bei System.Windows.Forms.Application.Run(Form mainForm)
       bei ImageResizer.Program.Main() in d:\users\dml\documents\visual studio 2010\Projects\ImageResizer\ImageResizer\Program.cs:Zeile 18.
       bei System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       bei System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       bei System.Threading.ThreadHelper.ThreadStart()
  InnerException:
cu deAndro....
 

NetBull

Erfahrenes Mitglied
#6
Ah, Garbage Collection war mein Problem.. Klasse,... läuft jetzt.
Hab vier Jahre nur PHP und Java gemacht. Mein Windows Form ist eingefroren wenn ich das in einer rekursiven Schleife für mehrere Verzeichnisse (ca. 30.000 Bilder) starte. Ich vermute weil die Schleife und das Form im gleichen Thread sind, oder? Wie kann ich das aktualisieren in einen anderen Thread verlegen?
 
#7
Hallo deAndro

Starte das Konvertieren der Bilder in einem neuen Thread (System.Threading.Thread) und sämtliche Interationen mit Steuerelementen musst du dann über die Invoke-Methode machen.

Viele Grüsse
Cromon
 
#9
Na ja, halt alles was den UI-Thread blockiert blockiert auch deine Form. Also wenn du irgendwas im Hauptthread deiner Anwendung machst (sofern die GUI darin läuft) ist die Form so lange blockiert bis diese Aufgabe beendet ist.