public RenderTargetBitmap GetSketchContentForExport()
{
Rect rectBounds = VisualTreeHelper.GetDescendantBounds(drawingCanvas);
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)rectBounds.Width, (int)rectBounds.Height, 96, 96, PixelFormats.Pbgra32);
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
VisualBrush visualBrush = new VisualBrush(drawingCanvas);
drawingContext.DrawRectangle(visualBrush, null, new Rect(new Point(), rectBounds.Size));
}
renderTarget.Render(drawingVisual);
return renderTarget;
}
When rendering the canvas content into a bitmap, all the content is displayed but has also grey borders (exactly the parts that are not in the current view).
Editing the resulting image in an external tool (XnView) and using the option "True Colour" fixes that problem. Does anyone see how I can fix this problem in my code? I appreciate any help!
Related
I have a MVVM WPF application.
I am trying to capture current content of the window without the Window Form Header and Window Form borders.
I know this is easy to do in a Windows Forms application, here is an example.
I would like to do the same in my WPF application but I am lost. I have found an example here but it captures all the screen.
How can I do this? Also, once captured I need to send it directly to print to the default printer.
So I am trying to do the following without success:
Capture WPF window content without the Window Form Header and Window Form borders.
Print this screen capture to default printer without showing any print dialog.
ATTEMPT #1 - ISSUE 1 - Capture screen:
Regarding point 1 (capturing content of window) I have done below. SnapShotPNG solution is working perfectly.
TopGrid UI Element in GetSnapshotButton_Click is the grid from which I want to do snapshot its content.
GetJpgImage solution is not working at all. In the snapshot appears black zones. Why?
Solutions extracted from here and here.
private void GetSnapshotButton_Click(object sender, RoutedEventArgs e)
{
var uri = new System.Uri("c:\\Temp\\capture1.png");
SnapShotPNG(TopGrid, uri, 1);
uri = new System.Uri("c:\\Temp\\capture2.jpg");
GetJpgImage(TopGrid, uri, 1, 100);
}
public void SnapShotPNG(UIElement source, Uri destination, int scale)
{
try
{
double actualHeight = source.RenderSize.Height;
double actualWidth = source.RenderSize.Width;
double renderHeight = actualHeight * scale;
double renderWidth = actualWidth * scale;
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32);
VisualBrush sourceBrush = new VisualBrush(source);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
using (drawingContext)
{
drawingContext.PushTransform(new ScaleTransform(scale, scale));
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(actualWidth, actualHeight)));
}
renderTarget.Render(drawingVisual);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
using (FileStream stream = new FileStream(destination.LocalPath, FileMode.Create, FileAccess.Write))
{
encoder.Save(stream);
}
}
catch (Exception e)
{
//MessageBox.Show(e);
}
}
///
/// Gets a JPG "screenshot" of the current UIElement
///
/// UIElement to screenshot
/// Scale to render the screenshot
/// JPG Quality
/// Byte array of JPG data
public void GetJpgImage(UIElement source, Uri destination, double scale, int quality)
{
double actualHeight = source.RenderSize.Height;
double actualWidth = source.RenderSize.Width;
double renderHeight = actualHeight * scale;
double renderWidth = actualWidth * scale;
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32);
VisualBrush sourceBrush = new VisualBrush(source);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
using (drawingContext)
{
drawingContext.PushTransform(new ScaleTransform(scale, scale));
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(actualWidth, actualHeight)));
}
renderTarget.Render(drawingVisual);
JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();
jpgEncoder.QualityLevel = quality;
jpgEncoder.Frames.Add(BitmapFrame.Create(renderTarget));
using (FileStream stream = new FileStream(destination.LocalPath, FileMode.Create, FileAccess.Write))
{
jpgEncoder.Save(stream);
}
}
ATTEMPT #2 - ISSUE 1 - Capture screen:
Using Dymanoid solution works but with one problem: Content does not fit in one page. I am trying now to fit into one page. To fit content into one page I am trying to do what is explained here.
for printing grid cotent (see here):
PrintDialog printDlg = new PrintDialog();
printDlg.PrintVisual(TopGrid, "Grid Printing.");
for printing entire wpf window (see here):
PrintDialog printDlg = new PrintDialog();
printDlg.PrintVisual(this, "Window Printing.");
I write this code to draw a text in a RenderTargetBitmap:
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawText(new FormattedText("yes", CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight, new Typeface("Times New Roman"),
30, Brushes.Red), new Point(10, 10));
}
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(drawingVisual);
image1.Source = renderTargetBitmap;//image1 is an Image control
the result is:
How can I remove this blurry effect? this effect comes from RenderTargetBitmap not from Image control.
You could use DrawingImage instead of RenderTargetBitmap
var drawingGroup = new DrawingGroup();
using (var drawingContext = drawingGroup.Open())
{
drawingContext.DrawText(
new FormattedText("yes",
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Times New Roman"),
30,
Brushes.Red),
new Point(10, 10));
}
image1.Source = new DrawingImage(drawingGroup);
You'll need to create DrawingGroup and open DrawingContext from there
I have a texture image as .jpg and I want to use this image as Windows.Media.pen
I use Windows.Media.pen for drawing skeleton data in DrawingContext which I got it from microsoft kinect.
How can I use texture image .jpg as Windows.Media.pen?
solved the problem.
ImageSource image = new BitmapImage(new Uri(#"...\texture.jpg", UriKind.Relative));
var brush = new ImageBrush(image);
var pen = new Pen(brush, 10);
drawingContext.DrawLine(pen, XPos, YPos);
Welcome to StackOverflow :D
Not sure if you'd get what you've been expecting as you can see below but here's how to do it :
You need to use ImageBrush to be able to assign an image to a Pen.
Original image :
Result :
Code :
ImageSource image = new BitmapImage(new Uri(#"..\..\5c5f910416e2b92bb73fa59c56fe695d.png", UriKind.Relative));
var brush = new ImageBrush(image);
var pen = new Pen(brush, 50);
var drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawRectangle(null, pen, new Rect(new Size(200, 200)));
}
var renderTargetBitmap = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(drawingVisual);
Content = new Image {Source = renderTargetBitmap, Stretch = Stretch.None};
I have a video feed from a Kinect sensor hosted by an image stored as a bitmap. My question is how do I overlay an image, for example a .png on to the video feed.
The video feed is shown like show below as bitmap source, I know how to draw a line to the bitmap but how do I draw an image from resources to the it?
KinectVideo.Source = BitmapSource.Create(colorFrame.Width, colorFrame.Height, 96, 96,
PixelFormats.Bgr32, null, colorData, colorFrame.Width * colorFrame.BytesPerPixel);
Below is a mock up of what I'm trying to achieve by placing the image over the video feed:
Updated implementation of drawing method,I don't think this is the correct implementation also I'm getting invalid argument error when adding image path to .DrawImage:
void myKinect_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
{
using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
{
if (colorFrame == null) return;
byte[] colorData = new byte[colorFrame.PixelDataLength];
colorFrame.CopyPixelDataTo(colorData);
KinectVideo.Source = BitmapSource.Create(colorFrame.Width, colorFrame.Height, 96, 96,
PixelFormats.Bgr32, null, colorData, colorFrame.Width * colorFrame.BytesPerPixel);
Rect destRect2;
//drawing image overlay to video feed
var drawingVisual = new DrawingVisual();
var drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawImage(BitmapSource.Create(colorFrame.Width, colorFrame.Height, 96, 96, PixelFormats.Bgr32, null, colorData, colorFrame.Width * colorFrame.BytesPerPixel),
new Rect(new Size(colorFrame.Width, colorFrame.Height)));
drawingContext.DrawImage("Images/boxbag.jpg", destRect2);
drawingContext.Close();
var mergedImage = new RenderTargetBitmap(colorFrame.Width, colorFrame.Height, 96, 96, PixelFormats.Pbgra32);
mergedImage.Render(drawingVisual);
KinectVideo.Source = mergedImage;
}
}
To create merged image you can use DrawingContext that gives you methods like DrawText or DrawImage and then render it using RenderTargetBitmap.Render:
var drawingVisual = new DrawingVisual();
var drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawImage(BitmapSource.Create(colorFrame.Width, colorFrame.Height, 96, 96, PixelFormats.Bgr32, null, colorData, colorFrame.Width * colorFrame.BytesPerPixel),
new Rect(new Size(colorFrame.Width, colorFrame.Height)));
var overlayImage = new BitmapImage(new Uri("Images/boxbag.jpg"));
drawingContext.DrawImage(overlayImage,
new Rect(x, y, overlayImage.Width, overlayImage.Height));
drawingContext.Close();
var mergedImage = new RenderTargetBitmap(colorFrame.Width, colorFrame.Height, 96, 96, PixelFormats.Pbgra32);
mergedImage.Render(drawingVisual);
KinectVideo.Source = mergedImage;
If you just want display an Image on top of another UI control, then you can either just declare one after the other UI elements, or set the Panel.ZIndex property:
<Grid>
<Border Background="Black" />
<Image Source="/AppName;component/Images/ImageName.jpg" Width="50" Height="50" />
</Grid>
Or:
<Grid>
<Image Source="/AppName;component/Images/ImageName.jpg"
Width="50" Height="50" Panel.ZIndex="1" />
<Border Background="Black" />
</Grid>
To find out how to data bind a BitmapImage to an Image.ItemsSource property, please see the Bind Xaml bitmap image question here on StackOverflow. To position the Image in a specific place, you can either use the Image.Margin property or put it in a Canvas and use the Canvas.Left and Canvas.Top properties.
Hopefully this'll be a fairly simple answer, but it's not the easiest thing to google for.
I'm planning to do a lot of painting using simple shapes, but the actual result doesn't need to be displayed to the user until the final stage, so for the sake of speed, I was wondering if there were existing methods in c#/WPF to draw simple shapes to a buffer without the overhead of a BitmapSource, so at the end I can just copy it into a WritableBitmap.
Something like
PixelFormat pixelFormat = PixelFormats.Default;
int stride = bitmapWidth * pixelFormat.BitsPerPixel / 8;
byte[] pixels new byte[bitmapHeight * stride];
*some static library*.DrawOval(xpos=10,ypos=10,radius=5, pixels, stride, pixelFormat);
Thanks
"Drawing shapes to a buffer" in WPF could be done by drawing shapes into a DrawingVisual using a DrawingContext. When drawing is finished, the DrawingVisual can be rendered into a RenderTargetBitmap.
Example:
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawEllipse(null, new Pen(Brushes.Black, 1), new Point(100, 100), 50, 50);
}
Drawing drawing = drawingVisual.Drawing;
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawDrawing(drawing);
drawingContext.DrawEllipse(null, new Pen(Brushes.Black, 1), new Point(100, 100), 60, 60);
}
RenderTargetBitmap bitmap = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Default);
bitmap.Render(drawingVisual);