Reputation: 3358
Take a screenshot of a control (or a set of controls) using RenderTargetBitmap
.
Source:
<Grid Height="200" Width="500">
<!-- Here goes any content, in my case, a Label or a Shape-->
<Label VerticalAligment="Top" HorizontalAligment="Left" Content="Text">
</Grid>
Expected result:
This one basically uses the UIElement
as the source of the RenderTargetBitmap
.
public static ImageSource GetRender(this UIElement source)
{
double actualHeight = source.RenderSize.Height;
double actualWidth = source.RenderSize.Width;
var renderTarget = new RenderTargetBitmap((int)Math.Round(actualWidth),
(int)Math.Round(actualHeight), 96, 96, PixelFormats.Pbgra32);
renderTarget.Render(source);
return renderTarget;
}
Result:
Instead of directly setting the UIElement
as the source of the RenderTargetBitmap
, I'll use a VisualBrush
.
//Same RenderTargetBitmap...
DrawingVisual dv = new DrawingVisual();
using (DrawingContext ctx = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(target);
ctx.DrawRectangle(vb, null, new Rect(new Point(), bounds.Size));
}
rtb.Render(dv);
Result:
This one ignores the position and size of the Grid
and the Label
inside:
What's happening here?
Upvotes: 3
Views: 2586
Reputation: 430
This is because that RenderTargetBitmap render the visual object based on cordinate of its parent object. Margin of itself, Padding or BorderThickness of its parent will all affect the rendered image. To solve this issue, you can simply add a fake parent container: If the original visual logical tree is like
<Grid>
<Canvas Margin="20" />
</Grid>
changed to
<Grid>
<Border Margin="20">
<Canvas />
</Border>
</Grid>
Settings for Alignment\Margin should also be moved into parent. Now you will get what you want.
Upvotes: -1
Reputation: 3358
I just needed to get the bounds of the descendant of the Grid
and render only the needed part.
public static ImageSource GetRender(this UIElement source, double dpi)
{
Rect bounds = VisualTreeHelper.GetDescendantBounds(source);
var scale = dpi / 96.0;
var width = (bounds.Width + bounds.X)*scale;
var height = (bounds.Height + bounds.Y)*scale;
RenderTargetBitmap rtb =
new RenderTargetBitmap((int)Math.Round(width, MidpointRounding.AwayFromZero),
(int)Math.Round(height, MidpointRounding.AwayFromZero),
dpi, dpi, PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext ctx = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(source);
ctx.DrawRectangle(vb, null,
new Rect(new Point(bounds.X, bounds.Y), new Point(width, height)));
}
rtb.Render(dv);
return (ImageSource)rtb.GetAsFrozen();
}
Result:
The rendered Label
/Shape
:
Merged with another Picture:
Upvotes: 3