2010-10-02 18 views
12

Czy możliwe jest użycie metody FromStream z System.Drawing.Image bez konieczności utrzymywania strumienia otwartego przez cały okres istnienia obrazu?Ładowanie obrazu ze strumienia bez utrzymywania strumienia otwartego

Mam aplikację, która ładuje kilka grafik paska narzędzi z plików zasobów, używając kombinacji Image.FromStream i Assembly.GetManifestResourceStream.

Problem, który mam, podczas gdy to działa poprawnie w systemie Windows 7, w systemie Windows XP aplikacja ulega awarii, jeśli element interfejsu użytkownika połączony z jednym z tych obrazów jest wyłączony. W systemie Windows 7 obraz jest renderowany w skali szarości. W przypadku XP zawiesza się z wyjątkiem braku pamięci.

Po obciążeniu włosów w końcu wyśledziłem je do początkowego załadowania obrazu. W gruncie oczywiście, jeśli utworzyć dowolny obiekt wykonawczych IDisposable który jest również zniszczone w taki sam sposób, ja owinąć go w użyciu instrukcji, na przykład

using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName)) 
{ 
    image = Image.FromStream(resourceStream); 
} 

Jeśli usunąć za pomocą komunikatu tak, że ISN strumień zlikwidowane, aplikacja nie zawiesza się już na XP. Ale teraz mam w zanadrzu masę "osieroconych" strumieni - obrazy są przechowywane w klasach poleceń, a te poprawnie usuwają obrazy, gdy same się pozbywają, ale oryginalny strumień nie jest.

Sprawdziłem dokumentację pod kątem FromStream i potwierdziłem, że strumień musi pozostać otwarty. Dlaczego to nie rozbił się i spalił na systemie Windows 7 rozwoju jest tajemnicą jednak!

Naprawdę nie chcę, żeby ten strumień kręcił się w pobliżu, a ja na pewno nie chcę przechowywać odniesienia do tego strumienia, jak również obrazu, aby móc go później usunąć. Potrzebuję tego strumienia tylko raz, więc chcę się go pozbyć :)

Czy jest możliwe utworzenie obrazu, a następnie zabicie tam i potem strumienia?

+3

Przez sposób, 'OutOfMemoryException' w' System.Drawing' zwykle oznacza * ogólny błąd * w GDI +. Powodem tego jest [historyczny] (http://stackoverflow.com/questions/2610416/is-there-a-reason-image-fromfile-throws-an-outofmemoryexception- for-an-invalid-im) i jest należny do mapowania niezarządzanych kodów błędów. –

+0

Jeśli strumień przesyłany do Image.FromStream nie jest dostępny, można bezpiecznie zamknąć strumień. Jest to jednak nieudokumentowane zachowanie, więc korzystaj z niego na własne ryzyko. – user2452157

Odpowiedz

19

Powodem strumień musi być otwarta jest following:

GDI +, a zatem System.Drawing nazw może odraczać dekodowanie bitów obrazu surowców aż wymagane bity są obrazem . Ponadto, nawet po zdekodowaniu obrazu, GDI + może określić, że bardziej wydajne jest odrzucanie pamięci dla dużej bitmapy i późniejsze jej dekodowanie. Dlatego GDI + musi mieć dostęp do bitów źródłowych obrazu przez cały okres jego istnienia.

Udokumentowane rozwiązaniem jest utworzenie albo nieindeksowane obrazu za pomocą Graphics.DrawImage lub utworzenia indeksowanego Bitmap oryginalnego obrazu, jak tutaj opisano:

Bitmap and Image constructor dependencies

+0

Dzięki za niezwykle przydatną odpowiedź! Wiedziałem o plikach blokujących FromFile, ale do tej pory nie znałem przyczyny. Przetestowałem za pomocą metody Create an Non-Indexed Image, która działa bez zarzutu, a aplikacja przestała działać na mojej maszynie wirtualnej XP. Będę testować ponownie za pomocą podejścia Indexed i zobacz, co się stanie - nie jestem pewien co do różnicy między tymi dwoma typami. –

+2

Fwiw: naprawili kilka problemów z indeksowanymi formatami pikseli w wersji Vista gdiplus.dll. Miło z tego powodu, ale ból głowy, gdy twój kod musi działać na XP. Zasadniczo trzymaj się od nich z daleka, aby uniknąć takich problemów. –

0

Możesz zapisać strumień do pliku tymczasowego i użyć metody Image.FromFile. Lub po prostu nie osadzaj obrazu, zachowaj go jako plik i wczytaj go z tego pliku w czasie wykonywania.

+0

Dzięki za odpowiedź, chociaż jest to coś, co już odrzuciłem, ponieważ wiem z doświadczenia, że ​​blokuje to plik, dlatego nie będzie w stanie go usunąć, dopóki aplikacja się nie zakończy. –

2

Zgodnie z dokumentacją strumień musi pozostać otwarty, gdy obraz jest w użyciu. Dlatego nawet jeśli zamykanie działało (i nie ma nic do powiedzenia, nie można zamknąć strumienia przed jego usunięciem, o ile sam obiekt strumienia idzie), może nie być to bardzo niezawodne podejście.

Można skopiować obraz do innego obiektu obrazu i użyć go. Jednak prawdopodobnie będzie to wymagać więcej pamięci niż tylko utrzymywanie otwartego strumienia.

+0

Dzięki za odpowiedź. To jest to, z czym się zetknąłem, używając powyższego artykułu z bazy wiedzy, który podał powody. –

+0

Wyszczególnia także szczegóły, chociaż w niektórych przypadkach skuteczniejsze może być przytrzymanie strumienia, co warto wziąć pod uwagę. –

Powiązane problemy