打印 Canvas 到 XPS 不需要的缩放和切断
Printing Canvas to XPS unwanted scaling and cut off
更新
在写回复之前,可以查看 SamTheDev 的回答及其评论。 SamTheDev 的回答解决了这两个问题,但我不明白,为什么它解决了第一个问题。
我遇到了以下 XPS 问题,需要您的帮助来解决这些问题。赏金现在是 运行.
问题 1:WPF 中 10 厘米长的行在 XPS 中不是 10 厘米长
我正在画这条 10 厘米长的黑线:
截屏,粘贴到 Word 并打印出来,我发现它真的有 10 厘米长:
然而打印生成的XPS文件时,线只有9.7厘米长:
画黑线的代码如下。我假定分辨率为每英寸 96 点,我想我需要在创建 XPS 文件之前进行一些缩放,但我不知道该怎么做。
XAML:
<Window x:Class="MWEXps.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:MWEXps"
mc:Ignorable="d"
Title="Sample 1 - 10 cm long black line" Height="300" Width="700">
<Canvas x:Name="canvas">
<!-- will be filled by code behind -->
</Canvas>
</Window>
背后的代码:
(基本上只有constructor和printCanvas方法相关)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// a 10 cm long line
PathFigure lineFigure1 = new PathFigure();
lineFigure1.StartPoint = cmPoint(3, 1);
LineSegment lineSegment1 = new LineSegment();
lineSegment1.Point = cmPoint(13, 1);
lineFigure1.Segments.Add(lineSegment1);
drawPathFigure(lineFigure1, canvas, Colors.Black);
// save as XPS
printCanvas();
}
public void printCanvas()
{
XpsDocument doc = new XpsDocument(@".\canvas-10cm.xps", System.IO.FileAccess.Write);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
writer.Write(canvas);
doc.Close();
}
// helper creating a point in centimeters
public Point cmPoint(double x, double y)
{
return new Point(cmToWpf(x), cmToWpf(y));
}
// helper converting a length in device independent pixels to centimeters
public double wpfToCm(double wpfValue)
{
double factor = (96 / 2.54);
return wpfValue / factor;
}
// helper converting a length in centimeters to device independent pixels
public double cmToWpf(double cmValue)
{
double factor = (96 / 2.54);
return cmValue * factor;
}
// helper for drawing a figure
public void drawPathFigure(PathFigure figure, Canvas canvas, Color color)
{
PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures.Add(figure);
Path path = new Path();
path.Stretch = Stretch.None;
path.StrokeLineJoin = PenLineJoin.Miter;
path.Stroke = new SolidColorBrush(color);
path.StrokeThickness = 1;
path.Data = pathGeometry;
canvas.Children.Add(path);
}
}
问题 2:100 厘米长的线在创建的 XPS 上被切断
在第二个示例中,我绘制了一条 100 厘米长的红线。显然它比 window 尺寸长。这不是问题,问题是它在生成的 XPS 文件上也被截断了。
生成的 XPS 文件如下所示:
画红线的代码如下。可以看到,红线被简单地切断了。我需要 XPS 中完整的 100 厘米红线 - 我该怎么做?
XAML:
<Window x:Class="MWEXps.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:MWEXps"
mc:Ignorable="d"
Title="Sample 2 - 100 cm long red line" Height="300" Width="700">
<Canvas x:Name="canvas">
<!-- will be filled by code behind -->
</Canvas>
</Window>
背后的代码:
(基本上只有constructor和printCanvas方法相关)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// a 100 cm long line
PathFigure lineFigure1 = new PathFigure();
lineFigure1.StartPoint = cmPoint(3, 1);
LineSegment lineSegment1 = new LineSegment();
lineSegment1.Point = cmPoint(103, 1);
lineFigure1.Segments.Add(lineSegment1);
drawPathFigure(lineFigure1, canvas, Colors.Red);
// save as XPS
printCanvas();
}
public void printCanvas()
{
XpsDocument doc = new XpsDocument(@".\canvas-100cm.xps", System.IO.FileAccess.Write);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
writer.Write(canvas);
doc.Close();
}
// helper creating a point in centimeters
public Point cmPoint(double x, double y)
{
return new Point(cmToWpf(x), cmToWpf(y));
}
// helper converting a length in device independent pixels to centimeters
public double wpfToCm(double wpfValue)
{
double factor = (96 / 2.54);
return wpfValue / factor;
}
// helper converting a length in centimeters to device independent pixels
public double cmToWpf(double cmValue)
{
double factor = (96 / 2.54);
return cmValue * factor;
}
// helper for drawing a figure
public void drawPathFigure(PathFigure figure, Canvas canvas, Color color)
{
PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures.Add(figure);
Path path = new Path();
path.Stretch = Stretch.None;
path.StrokeLineJoin = PenLineJoin.Miter;
path.Stroke = new SolidColorBrush(color);
path.StrokeThickness = 1;
path.Data = pathGeometry;
canvas.Children.Add(path);
}
}
感谢您对此的支持!
问题 1:
你如何测量黑线的长度?如果您在屏幕上放了一把尺子,您应该知道,大多数屏幕的 DPI 不完全是 96,而是接近它的值。打印文档测量尺寸。
问题 2:
你可以把你的Canvas放到一个固定页中,然后把固定页的大小调整到你的canvas。
var doc = new XpsDocument( "out.xps", FileAccess.Write );
var xpsdw = XpsDocument.CreateXpsDocumentWriter( doc );
FixedDocument document = new FixedDocument();
FixedPage page = new FixedPage();
FixedPage.SetLeft( yourCanvas, 0 );
FixedPage.SetTop( yourCanvas, 0 );
page.Width = pageWidth;
page.Height = pageHeight;
page.Children.Add( yourCanvas );
page.Measure( new Size( pageWidth, pageHeight ) );
page.Arrange( new Rect( 0, 0, pageWidth, pageHeight ) );
page.UpdateLayout();
PageContent page_content = new PageContent();
( (IAddChild)page_content ).AddChild( page );
document.Pages.Add( page_content );
xpsdw.Write( document );
doc.Close();
只需根据您的需要调整变量 "pageWidth" 和 "pageHeight",例如yourCanvas.ActualWidth 和 yourCanvas.ActualHeight.
请注意,XPSViewer 不会呈现过大的页面。每个维度的最大值在我的机器上大约是 70000 DiP。
快速提醒一下,像素大小取决于两个因素:显示分辨率和物理大小 的显示器,所以物理英寸和像素之间没有固定的关系,因此 WPF 使用逻辑英寸并通过转换:一个逻辑英寸是 96 像素 但这可以根据用户偏好进行更改。
所以 "ruler" 英寸或厘米在 wpf 上并不真正存在,只有从一个屏幕到另一个屏幕的逻辑值。
例如,我的两个屏幕上黑线的大小:
关于红线,您可以使用 Arrange
方法根据其子项修复 canvas 大小,将您的 PrintCanvas
方法更新为:
public void printCanvas()
{
XpsDocument doc = new XpsDocument(@".\canvas.xps", System.IO.FileAccess.Write);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
// The size of the canvas
System.Windows.Size size = new System.Windows.Size(cmToWpf(102), cmToWpf(6));
// Arrange canvas
canvas.Arrange(new Rect(size));
writer.Write(canvas);
doc.Close();
}
参考资料
DPI and Device-Independent Pixels
What measurement units does Silverlight and WPF use?
更新
在写回复之前,可以查看 SamTheDev 的回答及其评论。 SamTheDev 的回答解决了这两个问题,但我不明白,为什么它解决了第一个问题。
我遇到了以下 XPS 问题,需要您的帮助来解决这些问题。赏金现在是 运行.
问题 1:WPF 中 10 厘米长的行在 XPS 中不是 10 厘米长
我正在画这条 10 厘米长的黑线:
截屏,粘贴到 Word 并打印出来,我发现它真的有 10 厘米长:
然而打印生成的XPS文件时,线只有9.7厘米长:
画黑线的代码如下。我假定分辨率为每英寸 96 点,我想我需要在创建 XPS 文件之前进行一些缩放,但我不知道该怎么做。
XAML:
<Window x:Class="MWEXps.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:MWEXps"
mc:Ignorable="d"
Title="Sample 1 - 10 cm long black line" Height="300" Width="700">
<Canvas x:Name="canvas">
<!-- will be filled by code behind -->
</Canvas>
</Window>
背后的代码: (基本上只有constructor和printCanvas方法相关)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// a 10 cm long line
PathFigure lineFigure1 = new PathFigure();
lineFigure1.StartPoint = cmPoint(3, 1);
LineSegment lineSegment1 = new LineSegment();
lineSegment1.Point = cmPoint(13, 1);
lineFigure1.Segments.Add(lineSegment1);
drawPathFigure(lineFigure1, canvas, Colors.Black);
// save as XPS
printCanvas();
}
public void printCanvas()
{
XpsDocument doc = new XpsDocument(@".\canvas-10cm.xps", System.IO.FileAccess.Write);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
writer.Write(canvas);
doc.Close();
}
// helper creating a point in centimeters
public Point cmPoint(double x, double y)
{
return new Point(cmToWpf(x), cmToWpf(y));
}
// helper converting a length in device independent pixels to centimeters
public double wpfToCm(double wpfValue)
{
double factor = (96 / 2.54);
return wpfValue / factor;
}
// helper converting a length in centimeters to device independent pixels
public double cmToWpf(double cmValue)
{
double factor = (96 / 2.54);
return cmValue * factor;
}
// helper for drawing a figure
public void drawPathFigure(PathFigure figure, Canvas canvas, Color color)
{
PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures.Add(figure);
Path path = new Path();
path.Stretch = Stretch.None;
path.StrokeLineJoin = PenLineJoin.Miter;
path.Stroke = new SolidColorBrush(color);
path.StrokeThickness = 1;
path.Data = pathGeometry;
canvas.Children.Add(path);
}
}
问题 2:100 厘米长的线在创建的 XPS 上被切断
在第二个示例中,我绘制了一条 100 厘米长的红线。显然它比 window 尺寸长。这不是问题,问题是它在生成的 XPS 文件上也被截断了。
生成的 XPS 文件如下所示:
画红线的代码如下。可以看到,红线被简单地切断了。我需要 XPS 中完整的 100 厘米红线 - 我该怎么做?
XAML:
<Window x:Class="MWEXps.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:MWEXps"
mc:Ignorable="d"
Title="Sample 2 - 100 cm long red line" Height="300" Width="700">
<Canvas x:Name="canvas">
<!-- will be filled by code behind -->
</Canvas>
</Window>
背后的代码: (基本上只有constructor和printCanvas方法相关)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// a 100 cm long line
PathFigure lineFigure1 = new PathFigure();
lineFigure1.StartPoint = cmPoint(3, 1);
LineSegment lineSegment1 = new LineSegment();
lineSegment1.Point = cmPoint(103, 1);
lineFigure1.Segments.Add(lineSegment1);
drawPathFigure(lineFigure1, canvas, Colors.Red);
// save as XPS
printCanvas();
}
public void printCanvas()
{
XpsDocument doc = new XpsDocument(@".\canvas-100cm.xps", System.IO.FileAccess.Write);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
writer.Write(canvas);
doc.Close();
}
// helper creating a point in centimeters
public Point cmPoint(double x, double y)
{
return new Point(cmToWpf(x), cmToWpf(y));
}
// helper converting a length in device independent pixels to centimeters
public double wpfToCm(double wpfValue)
{
double factor = (96 / 2.54);
return wpfValue / factor;
}
// helper converting a length in centimeters to device independent pixels
public double cmToWpf(double cmValue)
{
double factor = (96 / 2.54);
return cmValue * factor;
}
// helper for drawing a figure
public void drawPathFigure(PathFigure figure, Canvas canvas, Color color)
{
PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures.Add(figure);
Path path = new Path();
path.Stretch = Stretch.None;
path.StrokeLineJoin = PenLineJoin.Miter;
path.Stroke = new SolidColorBrush(color);
path.StrokeThickness = 1;
path.Data = pathGeometry;
canvas.Children.Add(path);
}
}
感谢您对此的支持!
问题 1:
你如何测量黑线的长度?如果您在屏幕上放了一把尺子,您应该知道,大多数屏幕的 DPI 不完全是 96,而是接近它的值。打印文档测量尺寸。
问题 2:
你可以把你的Canvas放到一个固定页中,然后把固定页的大小调整到你的canvas。
var doc = new XpsDocument( "out.xps", FileAccess.Write );
var xpsdw = XpsDocument.CreateXpsDocumentWriter( doc );
FixedDocument document = new FixedDocument();
FixedPage page = new FixedPage();
FixedPage.SetLeft( yourCanvas, 0 );
FixedPage.SetTop( yourCanvas, 0 );
page.Width = pageWidth;
page.Height = pageHeight;
page.Children.Add( yourCanvas );
page.Measure( new Size( pageWidth, pageHeight ) );
page.Arrange( new Rect( 0, 0, pageWidth, pageHeight ) );
page.UpdateLayout();
PageContent page_content = new PageContent();
( (IAddChild)page_content ).AddChild( page );
document.Pages.Add( page_content );
xpsdw.Write( document );
doc.Close();
只需根据您的需要调整变量 "pageWidth" 和 "pageHeight",例如yourCanvas.ActualWidth 和 yourCanvas.ActualHeight.
请注意,XPSViewer 不会呈现过大的页面。每个维度的最大值在我的机器上大约是 70000 DiP。
快速提醒一下,像素大小取决于两个因素:显示分辨率和物理大小 的显示器,所以物理英寸和像素之间没有固定的关系,因此 WPF 使用逻辑英寸并通过转换:一个逻辑英寸是 96 像素 但这可以根据用户偏好进行更改。
所以 "ruler" 英寸或厘米在 wpf 上并不真正存在,只有从一个屏幕到另一个屏幕的逻辑值。
例如,我的两个屏幕上黑线的大小:
关于红线,您可以使用
Arrange
方法根据其子项修复 canvas 大小,将您的PrintCanvas
方法更新为:public void printCanvas() { XpsDocument doc = new XpsDocument(@".\canvas.xps", System.IO.FileAccess.Write); XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc); // The size of the canvas System.Windows.Size size = new System.Windows.Size(cmToWpf(102), cmToWpf(6)); // Arrange canvas canvas.Arrange(new Rect(size)); writer.Write(canvas); doc.Close(); }
参考资料
DPI and Device-Independent Pixels
What measurement units does Silverlight and WPF use?