Laden...

Tiff --> MemoryStream löst Generic GDI+ Exception aus

Erstellt von Platoon vor 2 Jahren Letzter Beitrag vor 2 Jahren 1.101 Views
P
Platoon Themenstarter:in
57 Beiträge seit 2017
vor 2 Jahren
Tiff --> MemoryStream löst Generic GDI+ Exception aus

Hallo zusammen,

ich möchte über ein TIFF dass ich vorher in einen MemoryStream lade OCR drüber laufen lassen.
Dazu nehme ich eine Abwandlung von 2 Methoden die ich dazu nutze um mir eine PDF in ein TIFF zu exportieren.
Das klappt super --> auch ohne den Generic GDI+ Fehler.

Das sind die Original Methoden:


List<MemoryStream> inMS;
        private void SaveAsImages(string path)
        {
            inMS = new List<MemoryStream>();
            try
            {
                System.Drawing.Image image = null;
                for (var i = 0; i < Renderer.PageCount; i++)
                {
                    var size = Renderer.Document.PageSizes[i];
                    image = Renderer.Document.Render(i, (int)size.Width , (int)size.Height, 300, 300, false);
                    MemoryStream ms = new MemoryStream();
                    image.Save(ms, ImageFormat.Tiff);
                    inMS.Add(ms);
                }
                SaveAsMultiPageTiff(path, inMS);
            }
            catch (Exception ex)
            {
                Cts.Cancel();
                Debug.Fail(ex.Message);
            }
        }

        private void SaveAsMultiPageTiff(string sOutFile, List<MemoryStream> inMS)
        {
            Mouse.OverrideCursor = Cursors.Wait;
            System.Drawing.Imaging.Encoder encoder = System.Drawing.Imaging.Encoder.SaveFlag;
            ImageCodecInfo encoderInfo = ImageCodecInfo.GetImageEncoders().First(i => i.MimeType == "image/tiff");
            EncoderParameters encoderParameters = new EncoderParameters(1);
            encoderParameters.Param[0] = new EncoderParameter(encoder, (long)EncoderValue.MultiFrame);

            Bitmap firstImage = null;
            try
            {

                using (MemoryStream ms = new MemoryStream())
                {
                    System.Drawing.Image.FromStream(inMS.First()).Save(ms, ImageFormat.Tiff);
                    firstImage = (Bitmap)System.Drawing.Image.FromStream(ms1);
                  
                    firstImage.Save(sOutFile, encoderInfo, encoderParameters); 
                }


                encoderParameters.Param[0] = new EncoderParameter(encoder, (long)EncoderValue.FrameDimensionPage);

                Bitmap imagePage;
            
                for (int i = 1; i < inMS.Count; i++)
                {

                    using (MemoryStream ms = new MemoryStream())
                    {
                        System.Drawing.Image.FromStream(inMS[i]).Save(ms, ImageFormat.Tiff);
                            imagePage = (Bitmap)System.Drawing.Image.FromStream(ms1);
                        

                        firstImage.SaveAdd(imagePage, encoderParameters); //throws Generic GDI+ error if the memory streams are not open when this is called
                    }
                }

            }
            catch (Exception)
            {
               
                throw;
            }
            finally
            {
            
                encoderParameters.Param[0] = new EncoderParameter(encoder, (long)EncoderValue.Flush);
                firstImage.SaveAdd(encoderParameters);
                MessageBox.Show("Dokument wurde erfolgreich nach " + sOutFile + " exportiert.", "Dokument export...", MessageBoxButton.OK);
                Mouse.OverrideCursor = Cursors.Arrow;
            }
        }

Ich habe die an den markierten Stellen angepasst --> wo der Fehler auftritt schreibe ich mal in großen Lettern mit dabei:


   List<MemoryStream> inMS;
        
        private void SaveAsImages(string path)
        {
            inMS = new List<MemoryStream>();
            PdfiumViewer.PdfRenderer Renderer = new PdfiumViewer.PdfRenderer();
            try
            {
                Renderer.OpenPdf(path);
                System.Drawing.Image image = null;
                for (var i = 0; i < Renderer.PageCount; i++)
                {
                    var size = Renderer.Document.PageSizes[i];
                    image = Renderer.Document.Render(i, (int)size.Width, (int)size.Height, 300, 300, false);
                    MemoryStream ms = new MemoryStream();
                    image.Save(ms, System.Drawing.Imaging.ImageFormat.Tiff);
                    inMS.Add(ms);
                }
                SaveAsMultiPageTiff(path, inMS);
            }
            catch (Exception ex)
            {
            }
        }

        private void SaveAsMultiPageTiff(string sOutFile, List<MemoryStream> inMS)
        {
            Mouse.OverrideCursor = Cursors.Wait;
            System.Drawing.Imaging.Encoder encoder = System.Drawing.Imaging.Encoder.SaveFlag;
            ImageCodecInfo encoderInfo = ImageCodecInfo.GetImageEncoders().First(i => i.MimeType == "image/tiff");
            EncoderParameters encoderParameters = new EncoderParameters(1);
            encoderParameters.Param[0] = new EncoderParameter(encoder, (long)EncoderValue.MultiFrame);

            Bitmap firstImage = null;
            try
            {

                using (MemoryStream ms1 = new MemoryStream())
                {
                    System.Drawing.Image.FromStream(inMS.First()).Save(ms1, System.Drawing.Imaging.ImageFormat.Tiff);
                    firstImage = (Bitmap)System.Drawing.Image.FromStream(ms1);
                    MemoryStream ms2 = new MemoryStream();
                    firstImage.Save(ms2, encoderInfo, encoderParameters); //throws Generic GDI+ error if the memory streams are not open when this is called
                    
                }


                encoderParameters.Param[0] = new EncoderParameter(encoder, (long)EncoderValue.FrameDimensionPage);

                Bitmap imagePage = null;
                for (int i = 1; i < inMS.Count; i++)
                {

                    using (MemoryStream ms1 = new MemoryStream())
                    {
                        System.Drawing.Image.FromStream(inMS[i]).Save(ms1, System.Drawing.Imaging.ImageFormat.Tiff);
                        imagePage = (Bitmap)System.Drawing.Image.FromStream(ms1);


                        firstImage.SaveAdd(imagePage, encoderParameters); //throws Generic GDI+ error if the memory streams are not open when this is called
                    }
                }
                encoderParameters.Param[0] = new EncoderParameter(encoder, (long)EncoderValue.Flush);
                firstImage.SaveAdd(encoderParameters);
                ÄNDERUNGEN AB HIER
                var img = firstImage.Clone();
                firstImage.Dispose();
                using (MemoryStream ms = new MemoryStream())
                {
                    ((Bitmap)img).Save(ms, ((Bitmap)img).RawFormat); ==> UND HIER KNALLT ES 
                    DoOCR(ms.ToArray());
                }
                ÄNDERUNGEN BIS HIER
                


            }
            catch (Exception ex)
            {
                //ensure the errors are not missed while allowing for flush in finally block so files dont get locked up.
                throw;
            }
            finally
            {
                // Close out the file
                Mouse.OverrideCursor = Cursors.Arrow;

            }
        }

Als Fehler bekomme ich folgendes:> Fehlermeldung:

A generic error occurred in GDI+.

Im StackTrace steht folgendes:

Fehlermeldung:
bei System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
bei System.Drawing.Image.Save(Stream stream, ImageFormat format)
bei DoSSuiteV2.Models.DMSModel.SaveAsMultiPageTiff(String sOutFile, List`1 inMS) in ...

Ich weiß leider nicht mehr weiter - hat jemand eine Idee für diese mehr oder weniger nichts-sagende Meldung?

.....an unhandled exception is the first way to think about your pattern of programming....
.....nur weil ich nicht weiß was dort passiert, bedeutet es nicht, dass ich nicht weiß, wie man es lösen kann - aber das ist wahrscheinlich....

16.828 Beiträge seit 2008
vor 2 Jahren

Vom Stil her ist der Quellcode nach dem Motto: Augen zu und durch - wird schon irgendwie funktionieren.
Das ist an vielen Stellen weit weg von einem Stil wie Defensives Programmieren bzw. struktureller Architektur.

Generic GDI Errors gibts immer dann, wenn in GDI selbst etwas schief gelaufen ist.
Die Ursache ist i.d.R. dass es strukturelle Fehler sind, dass es banale Fehler sind (zB. schon das Encoding), dass Du GDI ungültiges Zeugs übergibst - oder kann aber auch ein Permission Problem sein, sobald Du auf physikalische Ressourcen wie Pfade zugreifen willst. Wahrscheinlich hast Du was bei den Änderungen verballert, was für GDI wichtig ist.

Schaut man sich die Dokumentation von Bitmap.Clone() an, so macht die Methode kein Deep Copy sondern ein Shallow Copy.
Damit dürfest Du IIRC das Quell-Bitmap auch nicht disposen. Da Du danach zugreifst dürfte das zumindest einer der Fehler sein - vielleicht gibts da auch noch mehr.
Ein Deep Copy geht mit Bitmap deepCopy = new Bitmap(original);

Modernes Image Processing in .NET macht man eigentlich auch nicht mehr mit GDI, sondern zB über Wege, wie es GitHub - SixLabors/ImageSharp: A modern, cross-platform, 2D Graphics library for .NET macht.
Aber ja - hier benötigt man für kommerzielle Zwecke eine Lizenz, leider.

P
Platoon Themenstarter:in
57 Beiträge seit 2017
vor 2 Jahren

Hallo Abt,

Danke für das Feedback - den Quellcode werde ich einem Refactoring unterziehen.

Danke für den GitHub-Link - den werde ich mir ansehen. Was das DeepCopy angeht - auch hierfür danke für die Info. Werde das entsprechend ändern (im Refactoring) und für die Zukunft berücksichtigen 🙂.

.....an unhandled exception is the first way to think about your pattern of programming....
.....nur weil ich nicht weiß was dort passiert, bedeutet es nicht, dass ich nicht weiß, wie man es lösen kann - aber das ist wahrscheinlich....