Printing viewport - c#

C# wpf 3D visual studio 2010 net 4.5
Hi
I am trying to print out the 3D image I have created but can not get it right.
The image that is printed is changing in size depending on how large the window is etc.
or it is clipped etc.
What I would like is to print the view port on the printer,
stretching it so wide as the paper is and keeping aspect ration.
PrintDialog dialog = new PrintDialog();
if (dialog.ShowDialog() != true)
{ return; }
StackPanel myPanel = new StackPanel();
myPanel.Margin = new Thickness(40);
Image myImage = new Image();
myImage.Width = dialog.PrintableAreaWidth - (2 * MYDPI);
myImage.Stretch = Stretch.Uniform;
RenderTargetBitmap bmp = new RenderTargetBitmap((int)dialog.PrintableAreaWidth, (int)dialog.PrintableAreaWidth, 96, 96, PixelFormats.Pbgra32);
bmp.Render(myViewPort);
myImage.Source = bmp;
myPanel.Children.Add(myImage);
myPanel.Measure(new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight));
myPanel.Arrange(new Rect(new Point(0, 0), myPanel.DesiredSize));
dialog.PrintVisual(myPanel, myName);

The following worked, now the picture get scaled to the size of the paper regardless of
the size of the viewport
...
PrintDialog dialog = new PrintDialog();
if (dialog.ShowDialog() != true)
{
return;
}
Grid grid = new Grid();
grid.Margin = new Thickness(40);
//do this for each column
ColumnDefinition coldef;
coldef = new ColumnDefinition();
coldef.Width = new GridLength(dialog.PrintableAreaWidth, GridUnitType.Pixel);
grid.ColumnDefinitions.Add(coldef);
//do this for each row
RowDefinition rowdef;
rowdef = new RowDefinition();
rowdef.Height = new GridLength(1, GridUnitType.Auto);
grid.RowDefinitions.Add(rowdef);
//
rowdef = new RowDefinition();
rowdef.Height = new GridLength(1, GridUnitType.Auto);
grid.RowDefinitions.Add(rowdef);
TextBlock myTitle = new TextBlock();
myTitle.FontSize = 24;
myTitle.FontFamily = new FontFamily("Arial");
myTitle.TextAlignment = TextAlignment.Center;
myTitle.Text = myName;
grid.Children.Add(myTitle);
//put it in column 0, row 0
Grid.SetColumn(myTitle, 0);
Grid.SetRow(myTitle, 0);
Image myImage = new Image();
RenderTargetBitmap bmp = new RenderTargetBitmap((int)this.Width, (int)this.Height, 96, 96, PixelFormats.Pbgra32);
bmp.Render(myViewPort);
myImage.Source = bmp;
myImage.Stretch = Stretch.Uniform;
grid.Children.Add(myImage);
//put it in column 0, row 1
Grid.SetColumn(myImage, 0);
Grid.SetRow(myImage, 1);
grid.Measure(new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight));
grid.Arrange(new Rect(new Point(0, 0), grid.DesiredSize));
dialog.PrintVisual(grid, myName);

Related

Export chart to PNG without rendering it in the UI - WPF LiveCharts2

I'm trying to export a chart as a PNG file (without having to render it in the UI) and have implemented the following code for LiveCharts v0 which works fine...
LiveCharts.Wpf.CartesianChart control = new LiveCharts.Wpf.CartesianChart()
{
// Series = ...
Width = 700,
Height = 700,
DisableAnimations = true
};
var viewbox = new Viewbox();
viewbox.Child = control;
viewbox.Measure(control.RenderSize);
viewbox.Arrange(new Rect(new System.Windows.Point(0, 0), control.RenderSize));
control.Update(true, true); //force chart redraw
viewbox.UpdateLayout();
var encoder = new PngBitmapEncoder();
var bitmap = new RenderTargetBitmap((int)control.ActualWidth, (int)control.ActualHeight, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(control);
var frame = BitmapFrame.Create(bitmap);
encoder.Frames.Add(frame);
using (Stream stm = File.Create("filename.png"))
encoder.Save(stm);
However, when I try to implement this for LiveCharts2 with the following code, I'm not seeing any chart output as a PNG...
CartesianChart visual = new CartesianChart() {
// Series = series,
Height = 700,
Width = 700,
EasingFunction = null
};
var viewbox2 = new Viewbox();
viewbox2.Child = visual;
viewbox2.Measure(visual.RenderSize);
viewbox2.Arrange(new Rect(new System.Windows.Point(0, 0), visual.RenderSize));
visual.CoreChart.Update(new LiveChartsCore.Kernel.ChartUpdateParams() { IsAutomaticUpdate = false, Throttling = false });
viewbox2.UpdateLayout();
var encoder2 = new PngBitmapEncoder();
RenderTargetBitmap bmp = new(700, 700, 96, 96, PixelFormats.Pbgra32);
bmp.Render(visual);
encoder2.Frames.Add(BitmapFrame.Create(bmp));
using (Stream stm = File.Create("filename.png"))
encoder2.Save(stm);
Can anyone help fix this issue? Thanks in advance.
Found the answer here:
https://github.com/beto-rodriguez/LiveCharts2/discussions/725#discussioncomment-4030202
var skChart = new SKCartesianChart(chartControl) { Width = 900, Height = 600, };
skChart.SaveImage("CartesianImageFromControl.png");

Export WPF ScrollViewer content as separate PNGs

In my WPF application I have a ScrollViewer which is dynamically populated by DataBinding and the use of a UserControl. Imagine that my UserControl is something simple that only contains a label, and the value displayed in the label comes from a list. So when I run the application it looks like below:
As you can see there are multiple instances of the UserControl each with a different value that is dynamically populated. My goal is to export each of the UserControls as a separate PNG. My EXPORT PNG button click should do this.
So I looked around and found this example which works fine for exporting the entire content of the ScorllViewer.
So I tried modifying it to achieve my goal, and I do get it to work to a certain extent, but not quite what I want.
Here's my code:
private void ExportPNG()
{
var dir = Directory.GetCurrentDirectory();
var file = "ITEM_{0}.PNG";
var height = 100.0; // Height of the UserControl
var width = mainSV.ActualWidth;
for (int i = 1; i <= ItemList.Count; i++)
{
var path = System.IO.Path.Combine(dir, string.Format(file, i));
Size size = new Size(width, height);
UIElement element = mainSV.Content as UIElement;
element.Measure(size);
element.Arrange(new Rect(new Point(0, 0), size));
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
VisualBrush sourceBrush = new VisualBrush(element);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
using (drawingContext)
{
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(width, height)));
}
renderTarget.Render(drawingVisual);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write))
{
encoder.Save(stream);
}
}
}
Now this exports 5 PNGs (when my list has 5 items), bu they all contain the image of the first element:
And I figure the problem is likely where I do the drawingContext.DrawRectangle() because my rectanble coordinates are always the same. So I tried changing it to the following, which I thought should work, but for some reason it just generates one PNG with the first UserControl and 4 empty PNGs.
using (drawingContext)
{
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, (i-1) * height), new Point(width, height + ((i-1) * height))));
}
And the result:
What am I doing wrong here?
If you would like to run the code please find it here.
Please check below two methods. I tested it and it is working very well.
1. First, find children from you Items controls
2. Convert them to PNGs.
private void ExportPNG()
{
var dir = Directory.GetCurrentDirectory();
var file = "ITEM_{0}.PNG";
var height = 100.0;
var width = 100.0;
var children = GetChildrenOfType<UCDisplayItem>(itC);
foreach (var item in children)
{
var path = System.IO.Path.Combine(dir, string.Format(file, DateTime.Now.Ticks));
Size size = new Size(width, height);
UIElement element = item as UIElement;
element.Measure(size);
element.Arrange(new Rect(new Point(0, 0), size));
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
VisualBrush sourceBrush = new VisualBrush(element);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
using (drawingContext)
{
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(width, height)));
//drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, (i - 1) * height), new Point(width, height + ((i - 1) * height))));
}
renderTarget.Render(drawingVisual);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write))
{
encoder.Save(stream);
}
}
}
public List<T> GetChildrenOfType<T>( DependencyObject depObj)
where T : DependencyObject
{
var result = new List<T>();
if (depObj == null) return null;
var queue = new Queue<DependencyObject>();
queue.Enqueue(depObj);
while (queue.Count > 0)
{
var currentElement = queue.Dequeue();
var childrenCount = VisualTreeHelper.GetChildrenCount(currentElement);
for (var i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(currentElement, i);
if (child is T)
result.Add(child as T);
queue.Enqueue(child);
}
}
return result;
}
RESULT

C# WPF - Print ScreenCapture of WPF Window

Is there any way to print a screen capture of a wpf window?
I tried a lot of stuff, but either it's too big for A4 size or it's cropped of because there are no margins set.
Here the code i tried:
Sample1:
private void btnPrintStanzbild_Click(object sender, RoutedEventArgs e)
{
Visual target = gRight;
Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
RenderTargetBitmap renderTarget = new RenderTargetBitmap((Int32)bounds.Width, (Int32)bounds.Height, 96, 96, PixelFormats.Pbgra32);
DrawingVisual visual = new DrawingVisual();
using (DrawingContext context = visual.RenderOpen())
{
VisualBrush visualBrush = new VisualBrush(target);
context.DrawRectangle(visualBrush, null, new Rect(new Point(), bounds.Size));
}
renderTarget.Render(visual);
PngBitmapEncoder bitmapEncoder = new PngBitmapEncoder();
BitmapImage bi = new BitmapImage();
bitmapEncoder.Frames.Add(BitmapFrame.Create(renderTarget));
using (MemoryStream stm = new MemoryStream())
{
bitmapEncoder.Save(stm);
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.StreamSource = stm;
bi.EndInit();
}
var vis = new DrawingVisual();
var dc = vis.RenderOpen();
dc.DrawImage(bi, new Rect { Width = bi.Width, Height = bi.Height });
dc.Close();
var pdialog = new PrintDialog();
if (pdialog.ShowDialog() == true)
{
var queue = pdialog.PrintQueue;
var area = queue.GetPrintCapabilities(pdialog.PrintTicket)
.PageImageableArea;
pdialog.PrintVisual(vis, "My Image");
}
}
Sample2:
PrintDialog pdialog = new PrintDialog();
if (pdialog.ShowDialog() == true)
{
var queue = pdialog.PrintQueue;
var area = queue.GetPrintCapabilities(pdialog.PrintTicket)
.PageImageableArea;
pdialog.PrintVisual(this, "My Image");
}
Sample 3:
Link to sample 3
private void Print()
{
PrintDialog pdialog = new PrintDialog();
if (pdialog.ShowDialog() == true)
{
// Save current layout
Transform origTransform = LayoutTransform;
Size oldWindowSize = new Size(ActualWidth, ActualHeight);
// Get printer caps
PrintCapabilities capabilities = pdialog.PrintQueue.GetPrintCapabilities(pdialog.PrintTicket);
// Get size of the printer page
var sz = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
// Calculate zoom level of window
double ratio = Math.Min(sz.Width / ActualWidth, sz.Height / ActualHeight);
//if (ratio < 1) // Uncomment this line if you dont want zoom out small window
{
LayoutTransform = new ScaleTransform(ratio, ratio);
}
Measure(sz);
Arrange(new Rect(new Point(0,0), sz));
pdialog.PrintVisual(this, "My Image");
// Store old layout
LayoutTransform = origTransform;
Measure(oldWindowSize);
Arrange(new Rect(new Point(0, 0), oldWindowSize));
}
}

How to use texture image .jpg as Windows.Media.pen C#

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

Showing a part of a brush on a Stackpanel

I want to show a brush on my stackpanel in the following behavior:
Brush is an image 240x120
panel is 240x60
I want to show a part of the brush like rect(0, 30, 240, 60) (so that the image on the panel is moved down a bit)
tried it with viewport and Viewbox with no result (empty Panel)
This is my code:
for (int i = 0; i < listExplorationData.Count; i++)
{
StackPanel panelLoop = new StackPanel();
panelLoop.Name = "panel_" + i.ToString();
panelLoop.Width = 240;
panelLoop.Height = 60;
panelLoop.Margin = new Thickness(0, 60 * i, 0, 0);
BitmapImage image = new BitmapImage(
new Uri("pack://application:,,,/GW2-MyWorldExploration;component/Images/" +
listExplorationData[i].mapname_en.Replace(" ", "_") +
"_loading_screen.jpg"));
ImageBrush brush = new ImageBrush();
brush.ImageSource = image;
brush.Stretch = Stretch.None;
brush.Viewport = new Rect(0, 30, 240, 60);
panelLoop.Background = brush;
mainStackPanel.Children.Add(panelLoop);
}
In order to show part of the ImageBrush you would have to set the Viewbox. If you want to specify the viewbox in absolute units, you would also have to set the ViewboxUnits property:
brush.ViewboxUnits = BrushMappingMode.Absolute;
brush.Viewbox = new Rect(0, 30, 240, 60);

Categories