Ostatnio poświecam troszkę czasu na zabawę z obrazkami z mojego cyfraka. Napisałem prosty programik, który tworzy miniaturki z moich zbiorów zdjęć. Niestety ośmio megapikselowa matryca daje mi pliki JPG o rozmiarach przekraczających grubo 3MB, więc tworzenie tych miniatur trwało i trwało.
Ponizsza linijka wykonuje się na moim laptopie średnio ~850ms.
Image img = Image.FromFile(fileName);
Niestety to trochę dla mnie za długo, bo tych plików mam bardzo duzą ilość. Dlatego szukałem sposobu, aby przyśpieszyć odczyt takiego pliku i utworzyć z niego obiekt Image. Szukałem, szukałem, ale nie za bardzo mogłem znaleźć. Zacząłem sam kombinować i zrobiłem dokładnie to co napisałem wcześniej: "odczytać plik, a dopiero z tego utworzyć obiekt Image". Ponizszy kod tworzy obiekt Image prawie o dwa rzędy wielkości szybciej niz metoda pokazana wyzej.
using (MemoryStream mem = new MemoryStream(File.ReadAllBytes(fileName)))
{
using (Image img = Image.FromStream(mem, true, false))
{
...
}
}
Na tym samym laptopie jeden plik średniej wielkości około 3,5MB wczytuje się ~15ms. Istotny jest trzeci parametr metody FromStream, który powoduje, ze dane nie są walidowane pod kątem poprawności pliku, ale zakładam, ze będę czytał poprawne pliki. Ponadto jeśli plik jest faktycznie wadliwy, to mogę uzyć try{}catch{} na tą okoliczność. :)
Próbowałem do tego uzyć takze obiektu StreamReader, ale nie jest tak szybkie jak File.ReadAllBytes() :)
Jednakze powyzszy kod jeszcze nie gwarantuje sukcesu. Dlaczego? Otóz w dokumentacji Microsoft pisze, aby nie zamykać obiektu typu Stream (w tym przypadku MemoryStream), który jest skojarzony z obiektem Image przez cały czas jego zycia. Teraz, jeśli chcielibyśmy posługiwać się obiektem typu Image stworzonym na przykład taką metodą:
public Image GetImage(string fileName){
Image img = null;
using (MemoryStream mem = new MemoryStream(File.ReadAllBytes(fileName))){
img = Image.FromStream(mem, true, false);
}
return img;
}
to odwołanie do takiego obiektu Image zakończy się wyjątkiem: System.Runtime.InteropServices.ExternalException.
Mała zmiana poprawia działanie:
public Image GetImage(string fileName){
MemoryStream mem = new MemoryStream(File.ReadAllBytes(fileName));
return Image.FromStream(mem, true, false);
}
Kiedy juz zakończymy działanie na obrazku to wykonujemy na nim metodę Dispose() co spowoduje zwolnienie zasobów z nim związanych, m. in. takze Stream.