Export z WPF okna do obrázku.
- Vložil Trupík 3/10/2009 9:18:33 PM
-
Může se vám někdy hodit uložit obsah vašeho okna do obrázku na disku. Poněkud přímočará aplikace jsou
screenshoty. Pokud programujete
editor UML diagramů, je možnost vyexportovat diagram jako obrázek
(PNG export) uživatelem očekávaná funkce.
Díky architektuře WPF to není obtížné, jen je třeba vědět, kam sáhnout (jak je to s většinou problémů v .NET Frameworku).
Principem je vytvořit štětěc z exportovaného objektu typu Visual (VisualBrush) a tímto štětcem "nakreslit" obdélník s rozměry tohoto objektu.
Přejdu rovnou k věci, tedy ke kódu. První metoda je co možná nejpřímočařejší - na vstupu očekává objekt typu Visual (třída poměrně vysoko v hierarchii grafických objektů WPF) - můžete jí předat třeba libovolný formulář nebo okno apod. Aktuální obsah předaného objektu Visual je uložen jako PNG obrázek.
1 /// <summary>
2 /// Saves contents of a visual into a PNG file.
3 /// </summary>
4 /// <param name="visual">visual to save</param>
5 /// <param name="filename">path to the exported file</param>
6 private void ExportToPNG1(Visual visual, string filename)
7 {
8 double canvasWidth;
9 double canvasHeight;
10 /* this method returns width and height of the export
11 * from somewhere */
12 GetCanvasWidthAndHeight(out canvasWidth, out canvasHeight);
13
14 RenderTargetBitmap rtb = new RenderTargetBitmap(
15 (int) canvasWidth,
16 (int) canvasHeight, 96, 96, PixelFormats.Pbgra32);
17 DrawingVisual drawingVisual = new DrawingVisual();
18 DrawingContext drawingContext = drawingVisual.RenderOpen();
19 /* create a visual brush - brush, that paints content of a visual. */
20 VisualBrush canvasBrush = new VisualBrush(visual) { Stretch = Stretch.None, AlignmentX = 0, AlignmentY = 0 };
21 /* define a rectangle which fills whole picture */
22 Rect rect = new Rect(0, 0, canvasWidth, canvasHeight);
23 /* draw the rectangle with canvasBrush - paint contents of the visual */
24 drawingContext.DrawRectangle(canvasBrush, null, rect);
25 drawingContext.Close();
26 rtb.Render(drawingVisual);
27
28 /* Create a PngBitmapEncoder and save it to file */
29 PngBitmapEncoder png = new PngBitmapEncoder();
30 png.Frames.Add(BitmapFrame.Create(rtb));
31
32 using (Stream stm = File.Create(filename))
33 {
34 png.Save(stm);
35 }
36 }
37
Druhá metoda ještě ukazuje, jak se dá export trochu upravovat a zkrášlit - kromě samotného exportovaného objektu se v ní nakreslí také rámeček a vycentrovaný titulek. Vše pomocí DrawingContextu, který je při vytváření exportu k dispozici.
1 /// <summary>
2 /// Saves contents of a visual into a PNG file. Adds borders
3 /// and title to the image.
4 /// </summary>
5 /// <param name="visual">visual to save</param>
6 /// <param name="filename">path to the exported file</param>
7 private void ExportToPNG2(Visual visual, string filename, string title)
8 {
9 const int bounds = 10; // borders of the exported image
10 const int textoffset = 20; // offset of the title from top
11 double canvasWidth;
12 double canvasHeight;
13 /* this method returns width and height of the export
14 * from somewhere */
15 GetCanvasWidthAndHeight(out canvasWidth, out canvasHeight);
16
17 /* create a title text */
18 FormattedText titleText = new FormattedText(
19 title, new CultureInfo("en-us"), FlowDirection.LeftToRight,
20 new Typeface("Verdana"), 20, Brushes.Gray);
21
22 /* create a target bitmap for the image */
23 RenderTargetBitmap rtb = new RenderTargetBitmap(
24 (int) (Math.Max(bounds + canvasWidth + bounds, textoffset + titleText.Width + textoffset)),
25 (int) (textoffset + titleText.Height + textoffset + canvasHeight + bounds), 96, 96, PixelFormats.Pbgra32);
26
27 DrawingVisual drawingVisual = new DrawingVisual();
28 DrawingContext drawingContext = drawingVisual.RenderOpen();
29 /* paint a background rectangle */
30 drawingContext.DrawRectangle(Brushes.Wheat, null, new Rect(0, 0, rtb.Width, rtb.Height));
31 /* create a visual brush - brush, that paints content of a visual. */
32 VisualBrush canvasBrush = new VisualBrush(visual) {Stretch = Stretch.None, AlignmentX = 0, AlignmentY = 0};
33 /* create a rectangle to which the visual will be painted - with offsets */
34 Rect rect = new Rect(bounds, textoffset + titleText.Height + textoffset, rtb.Width - 2*bounds,
35 rtb.Height - bounds - textoffset - titleText.Height - textoffset);
36 /* draw the rectangle with canvasBrush and with borders */
37 drawingContext.DrawRectangle(canvasBrush, new Pen(Brushes.LightGray, 1), rect);
38 /* draw the title text */
39 drawingContext.DrawText(titleText, new Point(rtb.Width/2 - titleText.Width/2, textoffset));
40 drawingContext.Close();
41 rtb.Render(drawingVisual);
42
43 /* Create a PngBitmapEncoder and save it to file */
44 PngBitmapEncoder png = new PngBitmapEncoder();
45 png.Frames.Add(BitmapFrame.Create(rtb));
46
47 using (Stream stm = File.Create(filename))
48 {
49 png.Save(stm);
50 }
51 }
52
Takhle vypadají výstupy obou funkcí u diagramu z XCase:
Výstup z první funkce:

Výstup z druhé funkce:
Ohodnoťte prosím užitečnost článku