Poznámka: články jsou již mnoho let staré, doba se posunula, mnoho věcí v nich doporučovaných je již dnes překonané - berte s rezervou!


Export z WPF okna do obrázku.

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




3
 
20
 
16
 
12
 
0
 
 
Vložit komentář:
 

 



 

 

Nepoužívejte žádné html ani texy značky, odřádkování se zachová. Pokud uvádíte zdrojový kód, můžete ho vložit mezi značky
<syntax jazyk="PHP">...</syntax>,
bude potom zformátován. Jako atribut můžete uvést PHP, C#, HTML, CSS a mnoho dalších.


opiste cislo Opište číslo:

 

25. 11. 2012 2:56:44
[1] (Katlyn Brooks (katlynbrooks(at)yahoo.com)) www
longchamp handbag odpovědět
Great post!! Keep up the good work - I´m sure someday soon, someone will be doing an Ada Lovelace post about you!