Zamknięcie strumienia przed zapisem obrazu

0

Cześć,

Mam metodę która kompresuje zdjęcie i je zwraca, używam do tego również strumienia MemmoryStream. Problem pojawia się taki, że jeżeli zwracam zdjęcie i zamknę strumie to wyskakuje error przy zapisie zdjęcia poza metodą "System.Runtime.InteropServices.ExternalException: „A generic error occurred in GDI+.”". Jedni mówią, że strumienia zamykać nie trzeba, lecz niestety mam taki wymóg aby go zamknąć. Jeżeli zdjęcie zapiszę do bitmapy to wszystko działa, lecz jest większy rozmiar niż jakbym samo zdjęcie zwrócił. Czy ma ktoś jakąś wskazówkę aby lepiej to zrobić?

Cała metoda odpowiedzialna za kompresje(w której zwracam obraz i występuje error przy zapisie poza metodą)

        public static Image Compress(this Image img, string format, long compression)
        {
            if (compression <= 0 || compression > 100)
            {
                throw new ArgumentException("Wartość kompresji wykracza poza skalę <1-100>", nameof(compression));
            }

            Encoder enc;
            EncoderParameters encoderParameters;
            EncoderParameter encoderParameter;
            Image compressedImg;
            ImageCodecInfo ImgFormat;

          

            using (Bitmap bmp = new Bitmap(img))
            {
               


                    switch (format)
                    {

                        case "tiff":
                        case "tif":
                            
                            enc = Encoder.Compression;
                            encoderParameters = new EncoderParameters(1);
                            encoderParameter = new EncoderParameter(enc, (long)EncoderValue.CompressionLZW);
                            encoderParameters.Param[0] = encoderParameter;

                            ImgFormat = GetEncoder(ImageFormat.Tiff);

                            break;

                        default:
                           
                            enc = Encoder.Quality;
                            encoderParameters = new EncoderParameters(1);
                            encoderParameter = new EncoderParameter(enc, compression);
                            encoderParameters.Param[0] = encoderParameter;
                            ImgFormat = GetEncoder(ImageFormat.Jpeg);

                            break;

                    }
                    var flipTypeValue = img.PropertyItems.SingleOrDefault(x => x.Id == 0x0112)?.Value;
                    if (flipTypeValue != null && flipTypeValue.Length > 0)
                    {
                        var flipType = DecodeImageRotateFlipType(flipTypeValue[0]);
                        bmp.RotateFlip(flipType);

                    }
                MemoryStream ms = new MemoryStream();
                
                    if (format.Equals("png"))
                    {
                       
                        bmp.Save(ms, ImageFormat.Png);
                    }
                    else
                    {
                     
                        bmp.Save(ms, ImgFormat, encoderParameters);
                    }


                    compressedImg = Image.FromStream(ms);
                 

                ms.Dispose();

                    return compressedImg;
                }
            
        }

Jeżeli końcówkę zamienię na coś takiego, to wszystko działa ale niestety obrazy są kompresowane ale wyniki są większe niż przy zwracaniu jak wyżej (pewnie bitmapa zajmuje miejsce)

                                MemoryStream ms = new MemoryStream();
                
                    if (format.Equals("png"))
                    {
                        Console.WriteLine("test3");
                        bmp.Save(ms, ImageFormat.Png);
                    }
                    else
                    {
                        Console.WriteLine("test4");
                        bmp.Save(ms, ImgFormat, encoderParameters);
                    }


                    compressedImg = Image.FromStream(ms);
                    Bitmap bm = new Bitmap(compressedImg);

                ms.Dispose();

                    return bm;
                }
            
        }
0
Iro8 napisał(a):
        public static Image Compress(this Image img, string format, long compression)
...
                MemoryStream ms = new MemoryStream();
...
                        bmp.Save(ms, ImgFormat, encoderParameters);
...
                    compressedImg = Image.FromStream(ms);
...
                    return compressedImg;

Jaki jest ogólnie sens tego co robisz - czemu to ma służyć?

0

Zapisuje do strumienia obraz obrobiony (przy użyciu parametrów) a następnie taki obraz "obrobiony" chce pobrać z strumienia i zwrócić. Wiem łatwiej byłoby zrobić aby zapisywać od razu do miejsca docelowego zdjęcie zamiast do MS ale, to jest kolejny punkt, aby obraz był zwracany i dopiero poza metodą zdecydować się na jego zapis.

0

ale czy Image.FromStream nie powoduje zdekodowania obrazu, skutkiem czego cała ta kompresja była na nic?

0

Nie kompresja się nie traci, poza metodą jak chce zapisać zdjęcie to piszę coś takiego

Image img2 = compress(parametry wejściowe);
Img2.Save("path." + img.RawFormat, img.RawFormat)

Więc jako tako potem przy zapisie obrazu podaje znowu format zdjęcia w jakim ma być zapisane(bo jakbym nie podał to jak dobrze pamiętam automatycznie jest zapisywane z formatem png) ale zdjęcie jest skompresowane. Nie wiem czy dobrze to wytłumaczyłem ale po prostu przy takim sposobie to działa.

2

dopóki zdjęcie masz otwarte to nie możesz zamknąć strumienia - jest o tym info w helpie do klasy Image. Po prostu klasa Image korzysta z danych ze strumienia. Nie da się tego obejść (chyba, że użyjesz czegoś innego niż klasa Image). Wg mnie klasa Image i sama obsługa obrazów w c# jest mocno niedorobiona i nie umywa się do delpiowego TImage. Ostatnio siedzieliśmy 2 dni nad problemem ze znikającym RAMem w aplikacji - okazało się, że to co w delphi zajmowało niecałe 100MB w c# zajmuje ponad 1GB - mowa o obrazkach właśnie - otwarcie 200 obrazków (PNG, na dysku zajmują niecałe 100kB każdy, w sumie 88MB) zjada ponad 1GB RAMu i co byś nie robił to nie będzie inaczej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1