Lubie WPF’a.
Można o nim powiedzieć, że jest niedorobiony, wolny a technologia ta już nie będzie dalej rozwijana przez MS. Można też zachwycać się nad tym jak bardzo wiele jest klas w WPF i jak wiele jest ich jeszcze nieodkrytych kąsków.
Ostatnio natrafiłem na jeden z nich o którym chciałbym dziś napisać: *Bitmap(De/En)coder. Są to klasy, które umożliwiają pracę z różnymi formatami graficznymi np. PngBitmap(De/En)coder, BmpBitmap(De/En)coder, JpegBitnap(De/En)coder, TiffBitmap(De/En)coder.
Kiedyś, we wpisie 70-502 (WPF) – Image Metadata pisałem już o decoderach. Dziś trochę o encoderach.
Generalnie, jak można się domyśleć to co można odczytać za pomocą klas De-, przy pomocy klas En- można zapisać, tak więc w skrócie opisują za pomocą tych klas, można w WPFie stworzyć odpowiednie obrazki. Tyle? Gdyby to było wszystko pewnie bym o tym nie pisał posta (chociaż, kto wie – dawno już nic nie napisałem ;)) – posiadają one jednak ciekawą opcję. Potrafią, w bardzo prosty sposób zapisać w sobie stan kontrolki czyli zrobić zrzut ekranu naszej aplikacji. Sweet :]. Jak możemy ich użyć? Zobaczmy poniżej. Aby móc zapisać cokolwiek w tym obiekcie musimy dodać to do kolekcji Frames. Niestety przyjmuje ona obiekty typu BitmapFrame. Ona natomiast w statycznym konstruktorze bierze BitmapSource. Jak więc za tem możemy za ich pomocą zapisać do pliku nasze okno? Z pomocą przychodzi jeszcze jedna sweet-klasa a mianowicie RenderTargetBitmap.
A poskładane całe do kupy?
- private void SaveScreenshot(System.Windows.Media.Imaging.BitmapEncoder encoder, string name)
- {
- RenderTargetBitmap targetBitmap = new RenderTargetBitmap((int) Width, (int) Height, 96, 96,
- PixelFormats.Default);
- targetBitmap.Render(this);
- BitmapFrame frame = BitmapFrame.Create(targetBitmap);
- encoder.Frames.Add(frame);
- using (FileStream stream = File.Open(name, FileMode.Create))
- {
- encoder.Save(stream);
- }
- }
Tworzymy sobie odpowiednich rozmiarów RenderTargetBitmap a następnie renderujemy do niego zawartość naszej formy. Następnie wrzucamy to do frame’a i zapisujemy do pliku. Proste. Tak skonstruowaną metodę możemy sobie użyć z dowolnym decoderam i zapisywać do jakiego formatu nam się podoba.
- private void SavePng(object sender, RoutedEventArgs e)
- {
- PngBitmapEncoder encoder = new PngBitmapEncoder();
- SaveScreenshot(encoder, “main.png”);
- }
- private void SaveBmp(object sender, RoutedEventArgs e)
- {
- BmpBitmapEncoder encoder = new BmpBitmapEncoder();
- SaveScreenshot(encoder, “main.bmp”);
- }
- private void SaveTiff(object sender, RoutedEventArgs e)
- {
- TiffBitmapEncoder encoder = new TiffBitmapEncoder();
- SaveScreenshot(encoder, “main.tiff”);
- }
- private void SaveJpg(object sender, RoutedEventArgs e)
- {
- JpegBitmapEncoder encoder = new JpegBitmapEncoder();
- SaveScreenshot(encoder, “main.jpg”);
- }
Gotowe. PS. Jak wykonacie poniższy kod to zobaczycie dziwną ramkę po prawej i u dołu. Powodem tego jest fakt, że podstawiamy wielkość całego okna wraz z obramowaniem a renderowana jest tylko zawartość konta. Przez to wymiary faktycznego obrazka są większe niż to co na nim rysujemy.
Miłego renderowania.
Founder of Octal Solutions a .NET software house.
Passionate dev, blogger, occasionally speaker, one of the leaders of Wroc.NET user group. Microsoft MVP. Podcaster – Ostrapila.pl