The program below creates a snapshot with the content of the main window of the application itself. However the quality of the produced picture is not equivalent to the print screen program of windows 10, which produces the desired result.
Here is a snapshot of the program running, taken with the print screen program of windows 10, zoomed in:
https://ibb.co/wz4pb4d
And here is the snapshot that the program below is producing, zoomed in:
https://ibb.co/DLsNb8X
Is there something we can try to improve the quality of the snapshot that this program produse?
I tried Bitmap Encoder but is the same result , just without transparency, (Don't need to have transparency) also tried some other Pixel Formats but I get errors, only Pbgra32 seems to work as the program is.
if (e.Key == Key.P)
{
//Set scrollviewer's Content property as UI element to capture full content
UIElement element = mainwindow.Content as UIElement;
Uri path = new Uri(#"C:\Users\4gry\Desktop\screenshot.png");
CaptureScreen(element, path);
}
}
public void CaptureScreen(UIElement source, Uri destination)
{
try
{
Double Height, renderHeight, Width, renderWidth;
Height = renderHeight = source.RenderSize.Height;
Width = renderWidth = source.RenderSize.Width;
//Specification for target bitmap like width/height pixel etc.
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32);
//creates Visual Brush of UIElement
VisualBrush visualBrush = new VisualBrush(source);
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
//draws image of element
drawingContext.DrawRectangle(visualBrush, null, new Rect(new Point(0, 0), new Point(Width, Height)));
}
//renders image
renderTarget.Render(drawingVisual);
//PNG encoder for creating PNG file
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.ToString());
}
}
}
}
Not sure if this is exactly what you are trying to achieve, but you can avoid anti-aliasing effects by setting the RenderOptions.EdgeMode property of the source element to EdgeMode.Aliased.
Note also that you can also write your CaptureScreen method somewhat simpler:
public void CaptureScreen(UIElement source, string destination)
{
RenderOptions.SetEdgeMode(source, EdgeMode.Aliased); // here
var drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawRectangle(
new VisualBrush(source),
null,
new Rect(source.RenderSize));
}
var bitmap = new RenderTargetBitmap(
(int)Math.Round(source.RenderSize.Width),
(int)Math.Round(source.RenderSize.Height),
96, 96, PixelFormats.Default);
bitmap.Render(drawingVisual);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using (var stream = new FileStream(destination, FileMode.Create))
{
encoder.Save(stream);
}
}
In order to create an image with a higher resolution, use a DPI parameter instead of the default 96 like this:
public void CaptureScreen(UIElement source, double dpi, string destination)
{
RenderOptions.SetEdgeMode(source, EdgeMode.Aliased);
var drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawRectangle(
new VisualBrush(source),
null,
new Rect(source.RenderSize));
}
var bitmap = new RenderTargetBitmap(
(int)Math.Round(source.RenderSize.Width * dpi / 96),
(int)Math.Round(source.RenderSize.Height * dpi / 96),
dpi, dpi, PixelFormats.Default);
bitmap.Render(drawingVisual);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using (var stream = new FileStream(destination, FileMode.Create))
{
encoder.Save(stream);
}
}
Related
I need to capture UI element in this case LiveCharts chart and save it to a PNG/JPEG
I got this code
private void Button_Click(object sender, RoutedEventArgs e) {
var filePath = "qwerty.png";
var res = CaptureScreen(charts, charts.ActualWidth, charts.ActualHeight);
using (var fileStream = new FileStream(filePath, FileMode.Create)) {
BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(res));
encoder.Save(fileStream);
}
}
private BitmapSource CaptureScreen(Visual target, double dpiX, double dpiY) {
if (target == null) {
return null;
}
Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
RenderTargetBitmap rtb = new RenderTargetBitmap((int)(bounds.Width * dpiX / 96.0),
(int)(bounds.Height * dpiY / 96.0),
dpiX,
dpiY,
PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext ctx = dv.RenderOpen()) {
VisualBrush vb = new VisualBrush(target);
ctx.DrawRectangle(vb, null, new Rect(new System.Windows.Point(), bounds.Size));
}
rtb.Render(dv);
return rtb;
}
I can get a png no problem. Though it is the picture created is 30k x 9k pixels. The picture has a transparent background. what would be the best practice to capture a UI element and export as a picture with a white backgroun?
I want to draw large number of shapes (lines, ellipses and ...) and then save them as bitmap or png. I made the drawings and the question is: how can I convert a DrawingImage to BitmapImage in C#? the code is something like this:
DrawingGroup drawingGroup = new DrawingGroup();
using(DrawingContext context = drawingGroup.Open())
{
//make some drawing
}
DrawingImage drawingImage = new DrawingImage(drawingGroup)
// your suggestion? DrawingImage - > BitmapImage
You may put the ImageDrawing into an Image control and render that into a RenderTargetBitmap, which is a BitmapSource and can therefore be serialized by a BitmapEncoder (PngBitmapEncoder in this example).
public void SaveDrawingToFile(Drawing drawing, string fileName, double scale)
{
var drawingImage = new Image { Source = new DrawingImage(drawing) };
var width = drawing.Bounds.Width * scale;
var height = drawing.Bounds.Height * scale;
drawingImage.Arrange(new Rect(0, 0, width, height));
var bitmap = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(drawingImage);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using (var stream = new FileStream(fileName, FileMode.Create))
{
encoder.Save(stream);
}
}
Note that you don't actually need a BitmapImage for encoding, because BitmapSource (or any derived class like RenderTargetBitmap) will be accepted as argument to BitmapFrame.Create.
A slightly different solution would involve a DrawingVisual instead of a DrawingImage:
public void SaveDrawingToFile(Drawing drawing, string fileName, double scale)
{
var drawingVisual = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
{
drawingContext.PushTransform(new ScaleTransform(scale, scale));
drawingContext.PushTransform(new TranslateTransform(-drawing.Bounds.X, -drawing.Bounds.Y));
drawingContext.DrawDrawing(drawing);
}
var width = drawing.Bounds.Width * scale;
var height = drawing.Bounds.Height * scale;
var bitmap = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(drawingVisual);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using (var stream = new FileStream(fileName, FileMode.Create))
{
encoder.Save(stream);
}
}
I found it pretty easy this way:
public static BitmapSource ToBitmapSource(DrawingImage source)
{
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawImage(source, new Rect(new Point(0, 0), new Size(source.Width, source.Height)));
drawingContext.Close();
RenderTargetBitmap bmp = new RenderTargetBitmap((int)source.Width, (int)source.Height, 96, 96, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
return bmp;
}
You may use it to get System.Drawing.Bitmap
using (MemoryStream ms = new MemoryStream())
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(ToBitmapSource(drawingImage)));
encoder.Save(ms);
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(ms))
{
bmpOut = new System.Drawing.Bitmap(bmp);
}
}
Here is my wpf code
<InkCanvas x:Name="inkCanvas" Margin="9,325,210,193" Background="Azure"></InkCanvas>
And also there is a button
When pressing the button, i want to save image drawn to a file. here is my code
private void button1_Click(object sender, RoutedEventArgs e)
{
int margin = (int)inkCanvas.Margin.Left;
int width = (int)inkCanvas.ActualWidth - margin;
int height = (int)inkCanvas.ActualHeight - margin;
RenderTargetBitmap rtb = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default);
rtb.Render(inkCanvas);
using (FileStream fs = new FileStream("path", FileMode.Create))
{
BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(fs);
}
}
But image dusplayed is all black (whatching from an explorer) or complitely white, if opened in paint.
What do i do to get an image exactely as drawn? ty.
The problem is that you are trying to save Vector Graphics as a Bitmap and thats not possible, so first what you need to do is draw the Vectors and then you can save the Drawing
this class will draw Ink on to a existing bitmap
public class InkImage
{
public static BitmapFrame MergeInk(StrokeCollection ink, BitmapSource background)
{
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawImage(background, new Rect(0, 0, background.Width, background.Height));
foreach (var item in ink)
{
item.Draw(drawingContext);
}
drawingContext.Close();
var bitmap = new RenderTargetBitmap((int)background.Width, (int)background.Height, background.DpiX, background.DpiY, PixelFormats.Pbgra32);
bitmap.Render(drawingVisual);
return BitmapFrame.Create(bitmap);
}
}
}
you can then save the bitmap using the JPEG or PNG encoder
When I take a screenshot of a current WPF window, the image resolution is that of my monitor (if the app is maximized), which is ok. However, if I was to print that image to a much bigger format, the image would look blurry. I found the way to capture the current window, and save it as a png file, but it's not doing the trick. The image is saved with the resolution I set, but the actual wpf window takes only a small portion of the saved image. Example is taken from:
http://blogs.msdn.com/b/saveenr/archive/2008/09/18/wpf-xaml-saving-a-window-or-canvas-as-a-png-bitmap.aspx
var screen = System.Windows.Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
var rtb = new RenderTargetBitmap(4000, 4000, 96, 96, PixelFormats.Pbgra32);
rtb.Render(screen);
var enc = new System.Windows.Media.Imaging.PngBitmapEncoder();
enc.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(rtb));
using (var stm = System.IO.File.Create("ScreenShot.png"))
{
enc.Save(stm);
using (Image img = Image.FromStream(stm))
{
Rectangle dest = new Rectangle(0, 0, 6000, 4000);
using (Graphics imgG = Graphics.FromImage(img))
{
imgG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
imgG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
imgG.DrawImage(img, dest);
}
img.Save("NewScreenShot.png");
}
}
So basically, I'd like to capture the screenshot with the resolution of 4000 x 4000, if that's possible, without losing quality.
The above code produces an image of 4000 x 4000, however the screenshot only takes a small portion of it, its original resolution.
To scale your image, you can use a DrawingVisual and a ScaleTransform :
var w = 4000;
var h = 4000;
var screen = System.Windows.Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
var visual = new DrawingVisual();
using (var context = visual.RenderOpen())
{
context.DrawRectangle(new VisualBrush(screen),
null,
new Rect(new Point(), new Size(screen.Width, screen.Height)));
}
visual.Transform = new ScaleTransform(w / screen.ActualWidth, h / screen.ActualHeight);
var rtb = new RenderTargetBitmap(w, h, 96, 96, PixelFormats.Pbgra32);
rtb.Render(visual);
var enc = new PngBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(rtb));
using (var stm = File.Create("ScreenShot.png"))
{
enc.Save(stm);
}
I am trying to resize image to width=100 height=100
public ActionResult RegisterUser(userAuthModel user, HttpPostedFileBase userimage)
{
if (userimage.ContentLength > 0 && userimage != null)
{
string fname = userimage.FileName;
var path = Server.MapPath("~/Images/User_DP/" + userimage.FileName);
var image_100 = new System.Drawing.Bitmap(userimage, new Size(100, 100));
userimage.SaveAs(path);
}
.
.
.
.
.
}
Here I am using bitmap approach to resize imgae to some specific width and height.
But this shows me error in line-
var image_100 = new System.Drawing.Bitmap(userimage, new Size(100, 100));
of invalid arguments. How Do Ii resize image with using bitmap?
The System.Drawing.Bitmap class asks for two parameters in the constructor your are using:
System.Drawing.Image
System.Drawing.Size
In your code, you are passing the size correctly, but not the image. HttpPostedFileBase does not extend the Image class.
You will need to change that part of your code. If you are using the HttpPostedFileBase as a stream, then keep in mind that System.Drawing.Bitmap has no constructor asking for a Stream and a Size.
References:
System.Drawing.Image
System.Web.HttpPostedFileBase
you have to use mentioned method it may help you
private static BitmapFrame CreateResizedImage(ImageSource source, int width, int height, int margin)
{
var rect = new Rect(margin, margin, width - margin * 2, height - margin * 2);
var group = new DrawingGroup();
RenderOptions.SetBitmapScalingMode(group, BitmapScalingMode.HighQuality);
group.Children.Add(new ImageDrawing(source, rect));
var drawingVisual = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
drawingContext.DrawDrawing(group);
var resizedImage = new RenderTargetBitmap(
width, height, // Resized dimensions
96, 96, // Default DPI values
PixelFormats.Default); // Default pixel format
resizedImage.Render(drawingVisual);
return BitmapFrame.Create(resizedImage);
}