Canvas print - wpf - wpf

I used these code in order to print out the UI. Printing out is working, but if the size of paper is over, the UI cuts off in the middle of a canvas.
Is there any possible way not to be cut off in the middle?
<--cs code-->
PrintDialog dialog = new PrintDialog();
dialog.PrintVisual(lst , "print");
<--Xaml -->
<ListView Name="lst">
<Grid Name="grdPrint">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Canvas Grid.Row="0" >
.......
</Canvas>
<HListBox x:Name="lstImage" ItemsSource="{Binding IMG, Mode=TwoWay}" Grid.Row="1" IsHitTestVisible="True">
<HListBox.ItemTemplate>
<DataTemplate>
<HImage Margin="0" Width="590" Height="590" Stretch="Fill" Source="{Binding IMG_PATH_NM, Converter={StaticResource StrUriConverter}}" Tag="{Binding IMG_PATH_NM}">
</HImage>
</DataTemplate>
</HListBox.ItemTemplate>
<HListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" IsHitTestVisible="True"/>
</ItemsPanelTemplate>
</HListBox.ItemsPanel>
</HListBox>
</Grid>
</ListView>

This method will print the canvas to PNG file.
public void ExportToPNG(string imgpath, Canvas surface)
{
Uri path = new Uri(imgpath);
if (path == null)
return;
Transform transform = surface.LayoutTransform;
surface.LayoutTransform = null;
Size size = new Size(surface.Width, surface.Height);
surface.Measure(size);
surface.Arrange(new Rect(size));
RenderTargetBitmap renderBitmap =
new RenderTargetBitmap(
(int)size.Width,
(int)size.Height,
96d,
96d,
PixelFormats.Pbgra32);
renderBitmap.Render(surface);
using (FileStream outStream = new FileStream(path.LocalPath, FileMode.Create))
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
encoder.Save(outStream);
}
surface.LayoutTransform = transform;
}

You could create an BitmapImage (see RenderTargetBitmap to create a bitmap from an element). This bitmap can then be saved as a JPEG file and manipulated using GDI+ (System.Image).

Related

Label control - Border lines issue on PDF export

I attempted to export a Label control with a white background and noticed some border lines in the output file. Is there a workaround for this problem?
UI As seen below:
Exported output
Xaml Code
<Canvas x:Name="sampleCanvas" Grid.Row="1" Grid.Column="0">
<Canvas>
<Grid x:Name="SimpleNode" Height="50" Width="50" Margin="200,200" Background="CornflowerBlue">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<Canvas>
<Border x:Name="Bd" BorderThickness="1"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Border BorderThickness="1" Margin="2">
<Grid Name="parent">
</Grid>
</Border>
</Border>
<Label x:Name="lbl" BorderBrush="Transparent" Background="#FFFF" BorderThickness="0"
Content="Node Text" FontSize="12" FontFamily="Calibri"
Canvas.Top="40"
Panel.ZIndex="2" HorizontalAlignment="Center">
</Label>
</Canvas>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
</Grid>
</Canvas>
</Canvas>
Code Used for Printing
private void Button_Click(object sender, RoutedEventArgs e)
{
var filename = SaveCurrentDocument();
PrintDialog printDialog = new PrintDialog();
if ((bool)printDialog.ShowDialog())
{
PrintXPSDocument(printDialog, filename);
}
}
public string SaveCurrentDocument()
{
var filename = #"D:\exportWPF.xps";
File.Delete(filename);
using (Stream stream = File.Create(filename))
{
this.InvokeXps(stream);
}
return filename;
}
private void InvokeXps(Stream stream)
{
FixedDocument fixedDoc = new FixedDocument();
PageContent pageContent = new PageContent();
FixedPage fixedPage = CreateFixedPage(new Rect(0, 0, 500, 500));
((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);
fixedDoc.Pages.Add(pageContent);
Package package = Package.Open(stream, FileMode.Create, FileAccess.ReadWrite);
XpsDocument doc = new XpsDocument(package);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
writer.Write(fixedDoc);
doc.Close();
package.Close();
}
internal FixedPage CreateFixedPage(Rect area)
{
VisualBrush visualBrush = new VisualBrush(sampleCanvas);
System.Windows.Shapes.Rectangle rect = new System.Windows.Shapes.Rectangle();
RenderOptions.SetBitmapScalingMode(visualBrush, BitmapScalingMode.HighQuality);
visualBrush.Stretch = Stretch.None;
visualBrush.ViewboxUnits = BrushMappingMode.Absolute;
visualBrush.Viewbox = area;
rect.Fill = visualBrush;
rect.Stretch = Stretch.Fill;
rect.Width = area.Width;
rect.Height = area.Height;
rect.Arrange(new Rect(area.Size));
FixedPage fp = new FixedPage();
fp.Width = area.Width;
fp.Height = area.Height;
fp.Children.Add(rect);
fp.Arrange(new Rect(area.Size));
return fp;
}
internal void PrintXPSDocument(PrintDialog printDialog, string filePath)
{
var document = new XpsDocument(filePath, FileAccess.Read);
var sequence = document.GetFixedDocumentSequence();
FixedDocument fixedDocument = sequence.References[0].GetDocument(false);
fixedDocument.DocumentPaginator.PageSize = new System.Windows.Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);
printDialog.PrintDocument(fixedDocument.DocumentPaginator, "Printing");
document.Close();
}
I attempted to export my canvas control to.xps format and then print it using the Print Dialog via the shared code.
If you just want text then you should use a textblock rather than label.
Instead of
<Label x:Name="lbl" BorderBrush="Transparent" Background="#FFFF" BorderThickness="0"
Content="Node Text" FontSize="12" FontFamily="Calibri"
Canvas.Top="40"
Panel.ZIndex="2"
HorizontalAlignment="Center">
</Label>
You can use a textblock
<TextBlock x:Name="justText"
Background="#FFFF"
Text="Node Text"
FontSize="12"
FontFamily="Calibri"
Canvas.Top="40"
Panel.ZIndex="2"
TextAlignment="Center">
</TextBlock>
The functionality is very similar.
When you set content of a label to a string, a label creates a textblock as it's content and sets text to the string.
If you need the white background then you could try setting the height and width of the textblock but it seems you already have a white background anyhow.

How to set borderbrush color to each border direction on different Thickness?

i used visualbrush on borderbrush for setting different color to each border direction.
<Border Grid.Row="0" Grid.Column="4" BorderThickness="10,10,5,5" CornerRadius="0" HorizontalAlignment="Right" Height="50" Width="50" VerticalAlignment="Bottom" >
<Border.BorderBrush>
<VisualBrush>
<VisualBrush.Visual>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10"/>
<RowDefinition Height="30"/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="10"/>
</Grid.ColumnDefinitions>
<Border Background="Blue" Grid.Row="1" Grid.Column="0"/>
<Border Background="Red" Grid.Row="1" Grid.Column="2"/>
<Border Background="Green" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"/>
<Border Background="Yellow" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3"/>
</Grid>
</VisualBrush.Visual>
</VisualBrush>
</Border.BorderBrush>
</Border>
on xaml, this code did work well. each border direction color is different.
but on behind code,
Grid grid = new Grid();
grid.Height = this.rowHeight[r] + topHeight + bottomHeight;
grid.Width = this.columnWidth[c] + leftWidth + rightWidth;
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(topHeight) });
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(rowHeight[r])});
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(bottomHeight) });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(leftWidth) });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(columnWidth[c])});
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(rightWidth) });
Border bdTop = new Border() { Background = new SolidColorBrush(cellInfo["BorderBrush"]["Top"]) };
Border bdBottom = new Border() { Background = new SolidColorBrush(cellInfo["BorderBrush"]["Bottom"]) };
Border bdLeft = new Border() { Background = new SolidColorBrush(cellInfo["BorderBrush"]["Left"]) };
Border bdRight = new Border() { Background = new SolidColorBrush(cellInfo["BorderBrush"]["Right"]) };
bdTop.Height = topHeight;
bdBottom.Height = bottomHeight;
bdLeft.Height = this.rowHeight[r];
bdRight.Height = this.rowHeight[r];
grid.Children.Add(bdTop);
grid.Children.Add(bdBottom);
grid.Children.Add(bdLeft);
grid.Children.Add(bdRight);
Grid.SetRow(bdTop, 0);
Grid.SetColumn(bdTop, 0);
Grid.SetColumnSpan(bdTop, 3);
Grid.SetRow(bdBottom, 2);
Grid.SetColumn(bdBottom, 0);
Grid.SetColumnSpan(bdBottom, 3);
Grid.SetRow(bdLeft, 1);
Grid.SetColumn(bdLeft, 0);
Grid.SetRow(bdRight, 1);
Grid.SetColumn(bdRight, 2);
VisualBrush vb = new VisualBrush();
vb.Visual = grid;
if all thickness not same, on behind code, each border direction use each visualbrush. border top showed whole visualbrush. border bottom showed whole visualbrush.
i don't know what's problem....
xaml code used in border UI. behind code used in tablecell border.
if you want want to make a border have 4 different colors you can layer them on top of each other which is a lot more simple to implement:
<Grid Height="50" Width="50">
<Border BorderBrush="Blue" BorderThickness="5,0,0,0"></Border>
<Border BorderBrush="Red" BorderThickness="0,0,5,0"></Border>
<Border BorderBrush="Yellow" BorderThickness="0,0,0,5"></Border>
<Border BorderBrush="Green" BorderThickness="0,5,0,0"></Border>
<Grid Margin="5">
<!-- Content here -->
</Grid>
</Grid>

wpf oxyplot PlotAreaBackground image

I want a colorful background. My code not work. Version OxyPlotWpf: 1.0.0-unstable2100. Date published: Tuesday, April 12, 2016 (4/12/2016)
Can not imagine what else you can write in detail, my questions not passed since the system thinks there is not enough detail, so I added the text (sorry)
What i have
What i want
My GrpahPhone.png
<Window x:Class="OxiPlotTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:OxiPlotTest"
xmlns:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf"
xmlns:oxy2="http://oxyplot.codeplex.com"
mc:Ignorable="d"
Title="MainWindow" Height="250" Width="750"
Background="#333333">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="200"/>
</Grid.RowDefinitions>
<oxy:Plot Grid.Row="0" x:Name="oxyPlot2" Title="" Margin="10" Background="Transparent" PlotAreaBorderThickness="0,0,0,1" PlotAreaBorderColor="#CCCCCC">
<oxy:Plot.Axes>
<oxy:LinearAxis Position="Left" Minimum="0" Maximum="100" MajorGridlineColor="#333333" MajorGridlineStyle="Solid" MajorGridlineThickness="1" MajorStep="25" MinorStep="25"
TickStyle="None" TextColor="#CCCCCC" FontSize="16" FontWeight="Bold" AxisDistance="5"/>
<oxy:LinearAxis Position="Bottom" Minimum="0" Maximum="5" MajorGridlineStyle="None" MajorStep="1" MinorStep="1"
TextColor="#CCCCCC" FontSize="16" FontWeight="Bold" TicklineColor="#CCCCCC"/>
</oxy:Plot.Axes>
<oxy:Plot.Series>
<oxy:LineSeries ItemsSource="{Binding Points}" Color="AliceBlue" StrokeThickness="4"/>
</oxy:Plot.Series>
</oxy:Plot>
</Grid>
public partial class MainWindow : Window
{
public IList<DataPoint> Points { get; private set; }
public MainWindow()
{
InitializeComponent();
Points = new List<DataPoint>
{
new DataPoint(0, 5),
new DataPoint(1, 40),
new DataPoint(2, 55),
new DataPoint(3, 80),
new DataPoint(4, 90),
new DataPoint(5, 50),
};
DataContext = this;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = new Uri("pack://application:,,,/OxiPlotTest;component/Resources/GraphFon.png", UriKind.Absolute);
bitmapImage.EndInit();
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create((BitmapImage)bitmapImage));
var stream = new System.IO.MemoryStream();
encoder.Save(stream);
stream.Flush();
var image = new System.Drawing.Bitmap(stream);
var bitmap = new System.Drawing.Bitmap(image);
var bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
bitmap.Dispose();
var brush = new ImageBrush(bitmapSource);
oxyPlot2.PlotAreaBackground = brush;
}
}
I made 5 different List Points by color and added LineSeries

DrawingContext.PushOpacityMask() with BitmapImage does not work

I want to take a given BitmapImage and use its grayscale/black-and-white representation as an opacity mask on a DrawingContext.
I got far enough to do the color conversion, so I ended up with the follwing state of a demo application:
Method on ViewModel:
public void Demo()
{
var width = 400;
var height = 400;
var target = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
var target2 = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
var drawingVisual = new DrawingVisual();
var drawingVisual2 = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
{
var bitmapImage = new BitmapImage(new Uri(#"pack://application:,,,/WarningFilled.png"));
using (var drawingContext2 = drawingVisual2.RenderOpen())
{
drawingContext2.DrawImage(bitmapImage, new Rect(0, 0, width, height));
}
target2.Render(drawingVisual2);
var mask = target2.ToGrayscale();
this.Mask = mask;
drawingContext.PushOpacityMask(new ImageBrush(mask));
drawingContext.DrawRectangle(Brushes.Red, null, new Rect(0, 0, width, height));
// drawingContext.Pop();
}
target.Render(drawingVisual);
this.Rendered = target;
}
View:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication1="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<wpfApplication1:MainViewModel></wpfApplication1:MainViewModel>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" BorderThickness="2" BorderBrush="Blue" HorizontalAlignment="Center">
<Image Source="{Binding Rendered}" Width="400" Height="400"></Image>
</Border>
<Border Grid.Column="1" BorderThickness="2" BorderBrush="Green" HorizontalAlignment="Center">
<Image Source="{Binding Mask}" Width="400" Height="400"></Image>
</Border>
</Grid>
Running the demo application produces this:
I expected the red rectangle on the left to reflect the opacity mask pushed onto the DrawingContext before drawing the actual rectangle.
The image you see on the right is the BitmapImage after the color conversion, right before it is pushed as an opacity mask. As I mentioned before I also tried it with the black/white conversion, but even with only two colors there's no effect.
I've tried many similar setups and scenarios, but I don't get the opacity mask to work.
From the Opacity Masks Overview article on MSDN (emphasis mine):
To create an opacity mask, you apply a Brush to the OpacityMask
property of an element or Visual. The brush is mapped to the element
or visual, and the opacity value of each brush pixel is used to
determine the resulting opacity of each corresponding pixel of the
element or visual.
The color values of the pixel are ignored.

Connecting ScatterViewItems with a line

I want to draw lines between ScatterViewItems but it doesn't work with what I already found here. There is a Line, but not connected to the center of the ellipses. Does anybody see my mistake? Here is what I have:
<Grid>
<s:ScatterView>
<s:ScatterViewItem Height="250" Width="500" Background="Transparent" Orientation="0" HorizontalAlignment="Right" Margin="0,70,-764,-70" d:LayoutOverrides="HorizontalAlignment, Width">
<s:ScatterView Height="250" Width="500" Background="BlueViolet">
<s:ScatterViewItem Background="Transparent" Center="100,145" Orientation="0">
<Label Content="Knoten A" Background="WhiteSmoke" Foreground="Black"/>
</s:ScatterViewItem>
<s:ScatterViewItem x:Name="StartItem" CanMove="False" CanRotate="False" Margin="0" Center="10,125" Background="Transparent">
<Ellipse Width="10" Height="10" Fill="Transparent" Stroke="Black" Margin="0,0,0,0"/>
</s:ScatterViewItem>
<s:ScatterViewItem x:Name="EndItem" CanMove="False" CanRotate="False" Margin="0" Center="490,125" Background="Transparent">
<Ellipse Width="10" Height="10" Fill="Transparent" Stroke="Black" Margin="0,0,0,0"/>
</s:ScatterViewItem>
<s:ScatterViewItem Background="Transparent">
<Canvas Name="LineHost"/>
</s:ScatterViewItem>
</s:ScatterView>
</s:ScatterViewItem>
</s:ScatterView>
</Grid>
And the c#
Line line = new Line { Stroke = Brushes.Black, StrokeThickness = 2.0 };
BindLineToScatterViewItems(line, StartItem, EndItem);
LineHost.Children.Add(line);
private void BindLineToScatterViewItems(Line line, ScatterViewItem StartItem, ScatterViewItem EndItem)
{
BindingOperations.SetBinding(line, Line.X1Property,
new Binding {Source = StartItem, Path = new PropertyPath("ActualCenter.X")});
BindingOperations.SetBinding(line, Line.Y1Property,
new Binding { Source = StartItem, Path = new PropertyPath("ActualCenter.Y") });
BindingOperations.SetBinding(line, Line.X2Property,
new Binding { Source = EndItem, Path = new PropertyPath("ActualCenter.X") });
BindingOperations.SetBinding(line, Line.Y2Property,
new Binding { Source = EndItem, Path = new PropertyPath("ActualCenter.Y") });
}
The startpoint AND endpoint from your lines is ActualCenter.X/ActualCenter.Y of your Startitem. If the ActualCenter of your Startitem is 10/100, you would draw a line from 10/100 to 10/100, which is a reason why youre not seeing any line.
Instead of setting Source = Startitem in the last two lines of your BindLineToScatterViewItems method, try setting Source = EndItem.
Hope this helps.
If I use Canvas instead of ScatterView and ScatterViewItem and the order ist like this
<s:ScatterView>
<Canvas Name="LineCanvas2" Width="500" Height="250" Background="Aquamarine">
<Canvas Background="Transparent" Name="LineCanvas"/>
<s:ScatterView Width="500" Height="250" Background="Transparent">
<s:ScatterViewItem ...
there is no problem with the positioning of the connection lines.

Resources