打印画布到XPS不需要的缩放和切断

时间:2016-02-06 18:48:14

标签: c# wpf canvas printing xps

更新

在写回复之前,可以查看SamTheDev的回答及其评论。 SamTheDev的答案解决了这两个问题,但我不明白,为什么它解决了第一个问题。

我遇到了以下XPS问题,需要您帮助解决问题。赏金现在正在运行。

问题1:在XPS中,10厘米长的XCP行不长10厘米

我画了这条10厘米长的黑线: 10 cm long black line WPF

制作它的截图,将其粘贴到Word并打印显示,它实际上是10厘米长:

10 cm long line after printing with word

然而,当打印生成的XPS文件时,该行只有大约9.7厘米长:

Screenshot if generated XPS file

Print of generated XPS file

用于绘制黑线的代码如下。我假设每英寸有96个dotchs的分辨率,我想我需要在创建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>

代码背后: (基本上只有构造函数和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:在创建的XPS上切断100厘米长的线

在第二个例子中,我绘制了一条长100厘米的红线。显然它比窗口大小长。这不是问题,问题是,它也会在生成的XPS文件中被切断。

100 cm long red line

生成的XPS文件如下所示: 100 cm long red line on 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>

代码背后: (基本上只有构造函数和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);
    }
}

感谢您的支持!

2 个答案:

答案 0 :(得分:4)

作为快速提醒,像素大小取决于两个因素:显示器分辨率显示器的物理尺寸,因此物理英寸和像素之间没有固定的关系, WPF 使用逻辑英寸和转换:一个逻辑英寸 96像素但这可以根据用户更改偏好。

因此,wpf上并不存在“标尺”英寸或厘米,只是从一个屏幕到另一个屏幕的逻辑单位。

例如,这里是我的两个屏幕上黑线的大小:

enter image description here

enter image description here

  1. 关于红线,您可以使用Arrange方法根据其子项修复画布大小,将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();
    }
    
  2. 参考

    DPI and Device-Independent Pixels

    What measurement units does Silverlight and WPF use?

答案 1 :(得分:0)

问题1:

你如何衡量黑线的长度?如果你在屏幕上放置一把尺子,你应该知道,大多数屏幕都没有96 DPI,但接近它。打印文档以测量尺寸。

问题2:

您可以将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();

只需调整变量&#34; pageWidth&#34;和&#34; pageHeight&#34;根据您的需要,例如yourCanvas.ActualWidth和yourCanvas.ActualHeight。

请注意,XPSViewer不会渲染太大的页面。每个维度的最大值大约是我机器上的70000 DiP。