I am having two control image view and canvas.
Over image i am drawing rectangle.While taking screenshot i am only getting image not the rectangle.
Using below code i am getting black image
int Width = (int)canvas1.RenderSize.Width;
int Height = (int)canvas1.RenderSize.Height;
RenderTargetBitmap renderTargetBitmap =
new RenderTargetBitmap(Width, Height, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(canvas1);
PngBitmapEncoder pngImage = new PngBitmapEncoder();
pngImage.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (Stream fileStream = File.Create(filePath))
{
pngImage.Save(fileStream);
}
if i am replacing canvas with image only image is coming.
How to take screenshot containing both the controls ?
have a no-op after the render call for the render to be completed before taking the screenshot.
Also am assuming you are able to view the drawn rectangle in the viewport
and it is only not appearing in the screenshot. If not make sure the color of the rectangle is distinct against the image background.
renderTargetBitmap.Render(canvas1);
//no-op for rendering to complete before taking screenshot.
_dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => { }));
//screenshot code here.
Related
I am trying to draw some string to bitmap at certain position and copy a barcode bitmap to the new bitmap.I have not done with graphics before so i don't know where to start.
Can anyone guide me on this?my output of the bitmap is a receipt like.
Here is a solution. Please make a grid or canvas and put the barcode image and use a label with desired text and put the label on desired location relative to barcode grid. So, trick is you can immediately take screenshot of this grid using following code.Then, you are done.
public void ConvertToBitmapSource(UIElement element)
{
var target = new RenderTargetBitmap(
(int)element.RenderSize.Width, (int)element.RenderSize.Height,
96, 96, PixelFormats.Pbgra32);
target.Render(element);
var encoder = new PngBitmapEncoder();
var outputFrame = BitmapFrame.Create(target);
encoder.Frames.Add(outputFrame);
using (var file = File.OpenWrite("TestImage.png"))
{
encoder.Save(file);
}
}
I have a Path. It displays correctly in a ContentControl:
<ContentControl
Name="PathContainer"
Content="{Binding Path}"
RenderTransform="{StaticResource ScaleTransform}"
Width="Auto"
Height="Auto"
Background="Transparent"
/>
But I'd like to copy it to the clipboard. The following creates what appears to be a solid black bitmap of the correct size. If I change the brush to White, it creates a solid white bitmap of the correct size. If, instead of creating this Canvas, I render from the actual ContentControl which hosts the Path in the UI, I get a bitmap of the correct size, with the Path drawn on it, but with what appears to be an opaque black background (unless I change the background to PapayaWhip or something, which does what you'd expect).
When I say "appears to be an opaque black background", I mean that when I copy it to the clipboard with System.Windows.Clipboard.CopyImage() and paste it into the VS icon or bitmap editors, the background of the pasted image is black rather than transparent, and the anti-aliased pixels that ought to be semi-transparent are the color they'd appear to be on a black background.
So, two questions:
First: Is the following code broken, or am I just trying to do something you can't do? It doesn't throw any exceptions, FWIW in WPF.
Second: How do you make a bitmap with an alpha channel in WPF? Should I quit wasting my time on all these labor-saving abstractions, whack up a BITMAPINFOHEADER, and create the ARGB quads in a loop by hand?
public BitmapSource CreateImage(Transform tfm)
{
var path = CreatePath();
var rcBounds = path.Data.GetRenderBounds(GetPen());
if (null != tfm)
{
rcBounds = tfm.TransformBounds(rcBounds);
}
int pxWidth = (int)Math.Round(rcBounds.Width);
int pxHeight = (int)Math.Round(rcBounds.Height);
var canvas = new System.Windows.Controls.Canvas();
canvas.Width = pxWidth;
canvas.Height = pxHeight;
canvas.Margin = new System.Windows.Thickness(0);
canvas.Background = Brushes.Transparent;
canvas.Measure(new Size(canvas.Width, canvas.Height));
canvas.Arrange(new Rect(new Size(canvas.Width, canvas.Height)));
canvas.UpdateLayout();
canvas.Children.Add(path);
canvas.RenderTransform = tfm;
RenderTargetBitmap rtb = new RenderTargetBitmap(pxWidth, pxHeight,
96, 96, PixelFormats.Pbgra32);
rtb.Render(canvas);
return BitmapFrame.Create(rtb);
}
There seems to be no need for the Canvas. You could directly render the Path into the RenderTargetBitmap, like e.g. the following blue circle with transparent background:
var path = new Path
{
Data = new EllipseGeometry(new Point(100, 100), 100, 100),
Fill = Brushes.Blue
};
var bounds = path.Data.GetRenderBounds(null);
path.Measure(bounds.Size);
path.Arrange(bounds);
var bitmap = new RenderTargetBitmap(
(int)bounds.Width, (int)bounds.Height, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(path);
I have two images,now i want to overlay the images,such that the other image appears on center or left corner of the other image,and then when finally both the images are overlayed i can store it in another new image object,and i want to all this in code behind only not xaml,how to do this?
if (((Grid)sender).Children.Count > 0)
{
gridBackground = (ImageBrush)(((Grid)sender).Background);
gridBackImage = new System.Windows.Controls.Image();
gridBackImage.Source = gridBackground.ImageSource;
}
System.Windows.Controls.Image imgRejectIcon;
if (((Grid)sender).Children.Count > 0)
{
imgRejectIcon = (System.Windows.Controls.Image)(((Grid)sender).Children[0]);
}
Now i want to merge gridBackImage and imgRejection and store it in new image object
You can arrange your two Images in any way that you want and I'll leave that code for you to do (it'd much simpler to do in XAML). In WPF, all UI controls extend the Visual class. This is very useful for making BitmapImages from UI controls, when used with the RenderTargetBitmap.Render method.
First, arrange your two Image controls into a Grid, or other container control, and then you can pass the container control to the RenderTargetBitmap.Render method and create an Image something like this:
RenderTargetBitmap renderTargetBitmap =
new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(yourContainerControl);
PngBitmapEncoder pngImage = new PngBitmapEncoder();
pngImage.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (Stream fileStream = File.Create(filePath))
{
pngImage.Save(fileStream);
}
I want to develope a .NET application with WPF.
In the end there should be a Viewbox or something similar, this Viewbox should contain a canvas and in this canvas there could be various things like filled rectangles, ellipses etc. ( like a drawing application eg. paint).
Now I want to implement the functionallity to save the content of the Canvas to a PNG. I tried rendering the Canvas to a RenderTargetBitmap and then saving it.
The problem here is that I am not able to set specific coordinates, the only thing I can set is the Size (Canvas width & height) of the RenderTargetBitmap, but it will start rendering the Size starting from (0|0) where my Canvas element starts somewhere else. Is there some work arround for that??
The next Problem is, there should be the posibilty to add pictures as sub-element of the root-Canvas, but how could I care about quality and that everything in the Viewbox is printed?
Thank you very much!
------ EDIT ------
I think I've got a Solution:
void SaveUsingEncoder(Canvas myCanvas, string fileName)
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
RenderTargetBitmap bitmap = new RenderTargetBitmap(
(int)myCanvas.ActualWidth,
(int)myCanvas.ActualHeight,
96,
96,
PixelFormats.Pbgra32);
Rect bounds = VisualTreeHelper.GetDescendantBounds(myCanvas);
Console.WriteLine(bounds.X + "|" + bounds.Y + " " + bounds.Width + "|" + bounds.Height);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext ctx = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(myCanvas);
ctx.DrawRectangle(vb, null, new Rect(bounds.Location, bounds.Size));
}
bitmap.Render(dv);
BitmapFrame frame = BitmapFrame.Create(bitmap);
encoder.Frames.Add(frame);
using (var stream = File.Create(fileName))
{
encoder.Save(stream);
}
}
This saves the complete canvas for me
at specific position -
I think in your case use Margins.
I have two layers. The first layer is Image control. The source of it is Bitmap Image. And this is the background layer. The second one, which is the front layer is a canvas on which I can draw geometry objects (such as line, polyline, rectangle etc.) and the background of canvas is transparent.
How can I merge these two layers and save it as an image using WPF.
What do you mean by "Layers"? Just two controls sat in the same cell of a grid? If you have both "layers" sat in another container (such as a grid, or even the window) then you can use RenderTargetBitmap with that container to get your image. I have some details, an extension method for taking WPF "Screenshots" on my blog.
You can get bitmap of your parent panel on which you have placed your image control and canvas.
How is the code to get the bitmap of UIElement in WPF.
RenderTargetBitmap bmp = new RenderTargetBitmap(Width, Height, 96, 96, PixelFormats.Pbgra32);
bmp.Render(parentPanel);
Use something like, call this method from your canvas (this is canvas) -
private Bitmap ImageGenerator()
{
var transform = this.LayoutTransform;
// Call UpdateLayout to make sure changes all changes
// while drawing objects on canvas are reflected
var layer = AdornerLayer.GetAdornerLayer(this);
layer?.UpdateLayout();
// Get the size of canvas
var size = new System.Windows.Size(this.ActualWidth, this.ActualHeight);
// Measure and arrange the surface
// VERY IMPORTANT
this.Measure(size);
this.Arrange(new Rect(RenderSize));
RenderTargetBitmap renderBitmap =
new RenderTargetBitmap(
(int)this.ActualWidth,
(int)this.ActualHeight,
96d,
96d,
PixelFormats.Pbgra32);
renderBitmap.Render(this);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
// push the rendered bitmap to it
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
var stream = new MemoryStream();
encoder.Save(stream);
this.LayoutTransform = transform;
return new Bitmap(stream);
}