旋转页面后如何让PDFSharp在正确的位置绘制东西?

时间:2016-01-14 20:56:35

标签: c# wpf rotation position pdfsharp

我正在编写一个桌面WPF应用程序,允许用户打开扫描的PDF文件,必要时旋转它们,然后根据需要进行编辑。使用PDFium将页面呈现到屏幕,以便用户可以看到需要执行的操作。如果需要旋转,则单击旋转按钮将其旋转。如果需要编辑,则单击相应的按钮,然后使用鼠标在Canvas上绘制System.Windows.Shapes.Rectangle。然后,他们单击保存按钮将编辑(或编辑)保存到pdf文件。 PDF的实际更改是使用在Visual Studio 2013中通过NuGet下载的PDFSharp v1.50.4000-beta3b进行的。

如果页面正面朝上,IE旋转值为0,那么一切正常。我可以毫无问题地在整个地方画箱子。当旋转值不是0时,会出现问题。如果我将页面向任一方向旋转90度(旋转= 90或-90),那么当我尝试在页面上绘制框时,它会使事情变得混乱。它似乎是在不改变页面内容的情况下交换页面的高度和宽度(从横向转为纵向,反之亦然)。然后,如果页面再旋转90度,它将绘制矩形。

为了更好地展示我的意思,以下是一个例子: 我有一个标准尺寸的PDF页面(A4,Letter,不重要)。它在文件的前三分之一处有一个大笑脸,在余数上有文字,旋转设置为0,方向为纵向。我在我的程序中将其打开并将其旋转90度。现在它是风景,笑脸在页面的右三分之一侧面。我尝试在页面的右上角画一个方框。当我单击保存按钮时,它会更改文件,现在它以纵向显示,但内容没有改变,所以现在笑脸在页面的右边缘不可见。我试图放在右上角的盒子就好像它已经旋转一样,现在它位于右下角。如果我把它变成一个漂亮的椭圆形矩形,我可以看到它确实看起来好像它已经整个页面旋转但没有内容。如果我再次执行此操作,右上角的另一个框然后单击保存,它将再次交换高度和宽度,并将我的框旋转到与放置它的位置相差90度的位置。现在我可以再次看到笑脸,但盒子仍然不在我想要的地方。

此外,如果页面旋转为180,那么当它保存框时,它会如何旋转它应该在180度的位置。因此,如果我的笑脸在页面底部颠倒,我在他的眼睛上方(在页面底部)画了一个方框,它会将框保存在页面顶部。

最奇怪的是,它在几个星期前完美运作,现在还没有。从我的测试来看,似乎在某种程度上在PdfDocument.Save()方法中进行了更改,因为在该点之前,矩形的坐标是它们对于页面的当前方向/位置应该是什么。

无论如何,现在我已经解释了问题,这是我的代码。

首先,我们有处理旋转的代码。它位于辅助类中,它存储文件的路径和总页数。它包含要旋转的页码列表。此外,我必须将方向设置为纵向(无论是否应该),因为PDFSharp会在其他地方自动设置,但如果我在此处手动设置,它会正确旋转页面,如果我不在此处设置,页面内容将旋转而不会更改页面本身的大小/方向。

public bool RotatePages(List<int> pageNums)
    {
        if (pageNums.Count > 0)
        {
            PdfDocument currDoc = PdfReader.Open(fullPath, PdfDocumentOpenMode.Modify);

            for (int i = 0; i < totalPageCount; i++)
            {
                PdfPage newPage = currDoc.Pages[i]; //newDoc.AddPage();

                if (pageNums.Contains(i))
                {
                    newPage.Orientation = PdfSharp.PageOrientation.Portrait;

                    newPage.Rotate = (newPage.Rotate + 90) % 360;
                }
            }

            currDoc.Save(fullPath);

            return true;
        }
        else
            return false;
    }

接下来是绘制编校框的代码。它包含System.Windows.Rect对象列表,颜色列表,要标记的页码和矩阵。矩阵是因为pdf被渲染为图像,但是用户将矩形绘制到Canvas。图像可以放大或平移,矩阵存储这些变换,以便我可以将Canvas上矩形的位置与image / pdf上的适当点匹配。如果页面旋转为0,它将完美地工作。

public bool Redact(List<Rect> redactions, List<System.Windows.Media.Color> redactionColors, System.Windows.Media.Matrix matrix, int pageNum)
    {
        if (pageNum >= 0 && pageNum < totalPageCount && redactions.Count > 0 && redactions.Count == redactionColors.Count)
        {
            PdfDocument currDoc = PdfReader.Open(fullPath, PdfDocumentOpenMode.Modify);
            PdfPage newPage = currDoc.Pages[pageNum];
            XGraphics gfx = XGraphics.FromPdfPage(newPage);
            XBrush brush = null;

            for (int i = 0; i < redactions.Count; i++)
            {
                Rect redaction = redactions[i];
                System.Windows.Media.Color redactionColor = redactionColors[i];

                redaction.X = redaction.X / (matrix.OffsetX / newPage.Width);
                redaction.Y = redaction.Y / (matrix.OffsetY / newPage.Height);
                redaction.Width = redaction.Width / (matrix.OffsetX / newPage.Width);
                redaction.Height = redaction.Height / (matrix.OffsetY / newPage.Height);

                redaction.Width = redaction.Width / matrix.M11;
                redaction.Height = redaction.Height / matrix.M12;

                brush = new XSolidBrush(XColor.FromArgb(redactionColor.A, redactionColor));

                gfx.DrawRectangle(brush, redaction);
            }

            gfx.Save();
            currDoc.Save(fullPath);

            return true;
        }
        else
            return false;
    }

在矩阵中(并且我没有使用它进行矩阵数学运算,只是使用它来传递数据而不是使用6个整数/双精度数,是的,我知道它是糟糕的编码练习但是修复它是一个相当低的优先级):

M11 = the x scale transform
M12 = the y scale transform
M21 = the x translate transform
M22 = the y translate transform
OffsetX = the actual width of the image control
OffsetY = the actual height of the image control

尽可能靠近我一步一步地说,我的数学和一切看起来和它的工作方式完全一致,直到currDoc.Save(fullPath);然后它神奇地得到了错误的值。如果我在该行之前的任何时间中断程序执行,实际文件没有得到一个框,但是当它通过该行时它就会混乱。

我不知道这里发生了什么,或者如何解决它。它以前工作,我不记得我做了什么来改变它,所以它停止工作。到目前为止,我一整天都在寻找解决方案而没有运气。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

所以我终于明白了。显然,PDFSharp在处理页面旋转方面存在一些问题。为了解决这个问题,我首先要调整PDFSharp的源代码。

当页面设置为横向时,我必须注释掉交换高度/宽度值的代码。显然,PDFSharp使用&#34;方向&#34;尽管PDF没有这样的设置,但存储方向的变量。通过评论这些线条,我终于开始为旋转页面获得正确的高度和宽度。这是对PdfPage.cs的更改。

public XUnit Height
    {
        get
        {
            PdfRectangle rect = MediaBox;
            //return _orientation == PageOrientation.Portrait ? rect.Height : rect.Width;
            return rect.Height;
        }
        set
        {
            PdfRectangle rect = MediaBox;
            //if (_orientation == PageOrientation.Portrait)
                MediaBox = new PdfRectangle(rect.X1, 0, rect.X2, value);
            //else
            //    MediaBox = new PdfRectangle(0, rect.Y1, value, rect.Y2);
            _pageSize = PageSize.Undefined;
        }
    }


public XUnit Width
    {
        get
        {
            PdfRectangle rect = MediaBox;
            //return _orientation == PageOrientation.Portrait ? rect.Width : rect.Height;
            return rect.Width;
        }
        set
        {
            PdfRectangle rect = MediaBox;
            //if (_orientation == PageOrientation.Portrait)
                MediaBox = new PdfRectangle(0, rect.Y1, value, rect.Y2);
            //else
            //    MediaBox = new PdfRectangle(rect.X1, 0, rect.X2, value);
            _pageSize = PageSize.Undefined;
        }
    }

然后我必须在WriteObject方法中注释掉几行,这些行正在翻转媒体框的高度和宽度值。这些是我评论出来的。每次保存时,这都会阻止PDFSharp翻转我的旋转页面大小。

        //// HACK: temporarily flip media box if Landscape
        //PdfRectangle mediaBox = MediaBox;
        //// TODO: Take /Rotate into account
        //if (_orientation == PageOrientation.Landscape)
        //    MediaBox = new PdfRectangle(mediaBox.X1, mediaBox.Y1, mediaBox.Y2, mediaBox.X2);

...

//if (_orientation == PageOrientation.Landscape)
        //    MediaBox

最后,在我自己的代码中,我不得不更改大部分编校代码,将框放在合适大小的正确位置。正确的数学运算是永远的,代码是混乱但它的工作原理。任何有关如何清理它的建议都将不胜感激。

public bool Redact(List<Rect> redactions, List<System.Windows.Media.Color> redactionColors, System.Windows.Media.Matrix matrix, int pageNum)
    {
        if (pageNum >= 0 && pageNum < totalPageCount && redactions.Count > 0 && redactions.Count == redactionColors.Count)
        {
            PdfDocument currDoc = PdfReader.Open(fullPath, PdfDocumentOpenMode.Modify);
            int angle = currDoc.Pages[pageNum].Rotate;
            PdfPage oldPage = currDoc.Pages[pageNum];
            XBrush brush = null;
            XGraphics gfx = XGraphics.FromPdfPage(oldPage);
            XPoint pagePoint = new XPoint(0, 0);

            if (angle == 180)
            {
                pagePoint.X = oldPage.Width / 2;
                pagePoint.Y = oldPage.Height / 2;
                gfx.RotateAtTransform(180, pagePoint);
            }

            for (int i = 0; i < redactions.Count; i++)
            {
                Rect redaction = redactions[i];
                System.Windows.Media.Color redactionColor = redactionColors[i];
                double scaleValue = oldPage.Height / matrix.OffsetX;

                if (angle == 180 || angle == 0)
                {
                    redaction.X = redaction.X / (matrix.OffsetX / oldPage.Width);
                    redaction.Y = redaction.Y / (matrix.OffsetY / oldPage.Height);
                    redaction.Width = redaction.Width / (matrix.OffsetX / oldPage.Width);
                    redaction.Height = redaction.Height / (matrix.OffsetY / oldPage.Height);

                    redaction.Width = redaction.Width / matrix.M11;
                    redaction.Height = redaction.Height / matrix.M12;
                }
                else if (angle == 90 || angle == 270)
                {
                    Rect tempRect = redaction;

                    tempRect.X = redaction.X * scaleValue;
                    tempRect.Y = redaction.Y * scaleValue;

                    tempRect.Height = redaction.Height * scaleValue;
                    tempRect.Width = redaction.Width * scaleValue;

                    redaction.Width = tempRect.Height;
                    redaction.Height = tempRect.Width;

                    tempRect.Width = tempRect.Width / matrix.M11;
                    tempRect.Height = tempRect.Height / matrix.M12;

                    redaction.X = oldPage.Width - tempRect.Y - tempRect.Height;
                    redaction.Y = tempRect.X;

                    if (angle == 90)
                        gfx.RotateAtTransform(180, new XPoint(oldPage.Width / 2, oldPage.Height / 2));

                    redaction.Width = tempRect.Height;
                    redaction.Height = tempRect.Width;
                }

                brush = new XSolidBrush(XColor.FromArgb(redactionColor.A, redactionColor));
                gfx.DrawRectangle(brush, redaction);
            }

            gfx.Save();
            currDoc.Save(fullPath);

            return true;
        }
        else
            return false;
    }

这样我找到的解决方案对我有用。

答案 1 :(得分:-1)

当使用Adobe Libraries旋转页面时,当旋转页面并添加注释时,该注释全部关闭,该问题也仍然存在。我发现最简单的解决方案是旋转页面,提取页面,将单个页面重新保存为PDF / A,然后重新插入pdf。通过重新另存为pdf / A,它会将页面上的所有基础文本坐标固定为新的旋转,以便在添加注释时它们都应位于原位置。不幸的是,我还没有找到使用pdfshap将现有pdf保存为pdf / A的方法。