Re positioning canvas control - c#

I have Grid with three columns and layout is like
radio button | Canvas Control | radio button
For some feature of my application I need to take a screenshot of current view of canvas feature and save into a file.
I am using following method to save canvas to bmp,where I measure and arrange canvas.My problem is after image is saved ,canvas position in original grid is shifted to left,how can I re position my canvas back in grid as it was earlier.
private void SaveCanvasContentToImage(string path, Canvas canvasControl)
{
if (path == null && canvasControl != null) return;
// Save current canvas transform
Transform transform = canvasControl.LayoutTransform;
// reset current transform (in case it is scaled or rotated)
canvasControl.LayoutTransform = null;
// Get the size of canvas
Size size = new Size(canvasControl.Width, canvasControl.Height);
// Measure and arrange the canvas
canvasControl.Measure(size);
canvasControl.Arrange(new Rect(size));
// Create a render bitmap and push the canvas to it
RenderTargetBitmap renderBitmap =
new RenderTargetBitmap(
(int)size.Width,
(int)size.Height,
96d,
96d,
PixelFormats.Pbgra32);
renderBitmap.Render(canvasControl);
// Create a file stream for saving image
using (FileStream outStream = new FileStream(path, FileMode.CreateNew,FileAccess.ReadWrite))
{
// Use bitmap encoder for our data
BitmapEncoder encoder = new BmpBitmapEncoder();
// push the rendered bitmap to it
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
// save the data to the stream
encoder.Save(outStream);
outStream.Close();
outStream.Dispose();
}
// Restore previously saved layout
canvasControl.LayoutTransform = transform;
}

You may avoid the layout problem by using an intermediate DrawingVisual:
var renderTargetBitmap = new RenderTargetBitmap(
(int)canvasControl.ActualWidth, (int)canvasControl.ActualHeight,
96, 96, PixelFormats.Default);
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
dc.DrawRectangle(
new VisualBrush(canvasControl),
null,
new Rect(0, 0, canvasControl.ActualWidth, canvasControl.ActualHeight));
}
renderTargetBitmap.Render(visual);

Related

Why is a PNG file from a Grid completely black?

I'm trying to save a PNG image of a WPF Grid to file. The Grid is shown fine on the MainWindow, but the created file is completely black (though its dimensions are fine.)
Here is the code:
public MainWindow()
{
InitializeComponent();
int length = 30;
//Create Grid:
Grid myGrid = new Grid
{
Width = length,
Height = length,
Background = Brushes.Aqua,
};
//Save to file:
RenderTargetBitmap bmp = new RenderTargetBitmap(length, length, 96, 96, PixelFormats.Pbgra32);
bmp.Render(myGrid);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmp));
FileStream fileStream = new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\test.png", FileMode.Create);
encoder.Save(fileStream);
//Show on Window: (shows fine.)
gridOnMainWindow.Children.Add(myGrid);
}
When using a tool like RenderTargetBitmap, you must involve yourself in the Measure/Arrange cycle of the WPF layout process. See MSDN > WPF > Advanced > Layout > Measuring and Arranging Children.
Changing your example to:
int length = 30;
//Create Grid:
Grid myGrid = new Grid
{
Width = length,
Height = length,
Background = Brushes.Aqua,
};
myGrid.Measure(new Size(length, length));
myGrid.Arrange(new Rect(0, 0, length, length));
//Save to file:
RenderTargetBitmap bmp = new RenderTargetBitmap(length, length, 96, 96, PixelFormats.Pbgra32);
bmp.Render(myGrid);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmp));
using (var fileStream = File.OpenWrite("test.png"))
{
encoder.Save(fileStream);
}
Results in the expected image:

Saving image from inkCanvas as png or jpeg file

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

Take a screenshot of a WPF window with the predefined image size without losing quality

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);
}

How to export part of a huge Canvas to PNG

I need to export a Canvas to multiple PNG files. Trying to export the whole canvas to an image and then crop the image failed due to the size of the resulting image (something like 20.000px x 5.000px).
Now the strategy is to split the main canvas into smaller parts and then export each individual part to an image. The resulting image though, doesn't show the image from the main canvas below it.
Any ideas? Here is the code used to test the splitting of the Canvas (the real one is much larger than 1024x1024):
public void TestPrintPartOfCanvas()
{
//the main canvas
var main = new Canvas();
main.Width = 1024;
main.Height = 1024;
main.Background = Brushes.Blue;
//place something inside the canvas
var redRect = new System.Windows.Shapes.Rectangle();
redRect.Fill = Brushes.OrangeRed;
redRect.Width = 128;
redRect.Height = 128;
main.Children.Add(redRect);
// reset current transform (in case it is scaled or rotated)
var transform = main.LayoutTransform;
main.LayoutTransform = null;
// Get the size of canvas
var size = new Size(main.Width, main.Height);
//representing the first part of the main canvas
var part = new Canvas();
part.Width = 256;
part.Height = 256;
part.Background = Brushes.Transparent;
main.Children.Add(part);
// Measure and arrange the surface
main.Measure(size);
main.Arrange(new Rect(size));
// Create a render bitmap and push the part to it
var renderBitmap = new RenderTargetBitmap((int)part.Width, (int)part.Height, 96d, 96d, PixelFormats.Pbgra32);
renderBitmap.Render(part);
// Create a file stream for saving image
using (var outStream = new FileStream("p:/part.png", FileMode.Create))
{
// Use png encoder for our data
var encoder = new PngBitmapEncoder();
// push the rendered bitmap to it
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
// save the data to the stream
encoder.Save(outStream);
}
// Restore previously saved layout
main.LayoutTransform = transform;
}
You may easily crop a part of the Canvas by adjusting the Arrange rectangle:
var size = new Size(main.Width, main.Height);
main.Measure(size);
var cropOffset = new Point(-256, -256);
main.Arrange(new Rect(cropOffset, size));
var renderBitmap = new RenderTargetBitmap(256, 256, 96d, 96d, PixelFormats.Pbgra32);
renderBitmap.Render(main);
The above crops a 256x256 rectangle at position 256,256.

Saving canvas as image saves black area at top of image WPF c#

My problem is that I am creating images with increasing size black area's at the top of my images after saving them from a canvas.
Each time I save the image the black area at the top increases in size and a portion at the bottom of the image disappears.
When the image is created, it is loaded as the background of the canvas:
public void LoadImage(string fileName)
{
BitmapImage bitmap;
using (FileStream stream = new FileStream(fileName, FileMode.Open))
{
bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = stream;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
}
ImageBrush ib = new ImageBrush(bitmap);
this.Background = ib;
}
It is then amended by the user, and when they save, this is how the image is saved:
public void SaveAsImage(string filename, Window parent)
{
Size size = new Size(this.ActualWidth, this.ActualHeight);
Point point = this.TransformToAncestor(parent).Transform(new Point(0, 0));
RenderTargetBitmap renderBitmap = new RenderTargetBitmap(
(int)size.Width, (int)size.Height,
96d, 96d, PixelFormats.Pbgra32);
// needed otherwise the image output is black
this.Measure(size);
this.Arrange(new Rect(point, size));
renderBitmap.Render(this);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
using (FileStream file = File.Create(filename))
{
encoder.Save(file);
}
}
What I am wondering is why the canvas or image seems to move each time I save it and the background turn black.
As you can see in the comments (the save routine was taken from another post on here) it uses the measure and arrange functions to stop the whole of the background turning black, however it's not stopping my image from moving / disappearing.
Any help / advice appreciated.
Thanks.

Categories

Resources