首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何让PDFSharp在旋转页面后在正确的位置绘制东西?

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

Stack Overflow用户
提问于 2016-01-14 20:56:34
回答 2查看 3.1K关注 0票数 2

我正在编写一个桌面WPF应用程序,允许人们打开扫描的PDF文件,在需要时旋转它们,然后在需要时编辑它们。使用PDFium将页面呈现到屏幕上,这样用户就可以看到需要做什么。如果需要旋转,他们点击旋转按钮来旋转它。如果需要编辑,则单击相应的按钮,然后使用鼠标在画布上绘制System.Windows.Shapes.Rectangle。然后单击“保存”按钮将编辑(或编辑)保存到pdf文件中。对PDF的实际更改是使用PDFSharp v1.50.400-beta3b在Visual 2013中通过NuGet下载的。

如果页面右侧向上,则旋转值为0,则一切都正常。我可以把盒子画得到处都是,没有问题。当旋转值不是0时,就会出现这个问题。如果我将页面朝任意一个方向旋转90度(旋转= 90或-90),那么当我试图在页面上绘制框时,它会把事情搞砸。它似乎是在不改变页面内容的情况下交换页面的高度和宽度(将其从景观转换到纵向,反之亦然)。然后,如果页面再旋转90度,它就会在这个点绘制矩形。

为了更好地展示我的意思,这里有一个例子:我有一个pdf页面,它是标准的大小(A4,字母,不重要)。它在文件的前三分之一上有一个大的笑脸,在剩余的部分上有一个文本,旋转设置是0,方向是肖像。我打开它在我的程序和旋转它90度。现在,它是风景和笑脸是横向的,在右边的三分之一页。我试着在页面右上角画一个框。当我点击保存按钮,它改变了文件,现在它显示在纵向方向,但是内容没有改变,所以现在Smiley脸在页面的右边是看不见的。我试图放置在右上角的盒子就像它被旋转了一样,现在它在右下角。如果我把它做成一个很好的长方形,我可以看到它看起来确实是和整个页面一起旋转的,但是没有内容。如果我再次这样做,另一个框在右上角,然后单击保存,它将再次交换高度和宽度,并将我的框旋转到一个与我放置的位置90度的位置。现在我又能看到笑脸了,但是盒子仍然不在我想要的地方。

另外,如果页面旋转为180,那么当它保存方框时,它是如何旋转它应该在180度内的位置。所以,如果我的笑脸倒在页面底部,而我在他的眼睛上画了一个盒子(在页面的底部),它会把盒子保存在页面的顶部。

最奇怪的是,几周前它运行得很完美,现在却没有了。从我的测试来看,似乎是在PdfDocument.Save()方法中做出了某种改变,因为在此之前,矩形的坐标是页面当前方向/位置的坐标。

不管怎样,现在我已经解释了问题,这是我的代码。

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

代码语言:javascript
复制
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被呈现到图像,但是矩形是由用户绘制到画布上的。图像可以放大,可以缩放,矩阵可以存储这些转换,这样我就可以将画布上矩形的位置与图像/pdf上的适当点相匹配。如果页面旋转为0,它将完美地工作。

代码语言:javascript
复制
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个整数/双),是的,我知道这是糟糕的编码实践,但修复它是一个相当低的优先级):

代码语言:javascript
复制
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);,然后它神奇地得到了错误的值。如果我在该行之前的任何时间中断程序执行,那么实际的文件不会得到一个框,但当它经过这一行时,它就会搞砸。

我不知道这是怎么回事,也不知道怎么解决。它以前是工作的,我不记得我做了什么来改变它,所以它停止工作。到目前为止,我一直在寻找一个解决方案,却没有运气。任何帮助都将不胜感激。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-01-19 21:58:25

所以我终于想明白了。显然,PDFSharp在如何处理页面旋转方面存在一些问题。为了修复它,我首先必须修改PDFSharp的源代码。

当页面设置为景观时,我不得不注释掉正在交换高度/宽度值的代码。显然,PDFSharp使用一个“方向”变量来存储方向,尽管PDF没有这样的设置。通过注释掉这些行,我终于开始为旋转的页面获得合适的高度和宽度。这是对PdfPage.cs的更改。

代码语言:javascript
复制
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方法中一些正在翻转mediabox的高度和宽度值的行。这些是我评论掉的台词。这阻止了PDFSharp每次保存它时都会翻转我旋转的页面大小。

代码语言:javascript
复制
        //// 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

最后,在我自己的代码中,我必须更改大部分的编辑代码,以便将方框放在合适的位置。计算正确需要花费很长时间,而且代码很混乱,但它很有效。任何关于如何清理它的建议将不胜感激。

代码语言:javascript
复制
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;
    }

所以这就是我找到的对我有用的解决方案。

票数 3
EN

Stack Overflow用户

发布于 2019-07-10 23:05:43

当使用Adobe旋转页面时,当您旋转一个页面并添加注释时,这个问题仍然存在。我找到的最简单的解决方案是旋转页面,提取页面,将单个页面重新保存为PDF/A,然后重新插入到pdf中。通过重新保存为pdf/A,它将页面上的所有底层文本坐标修正为新的旋转,这样当您添加注释时,它们都位于应该的位置。不幸的是,我还没有找到一种方法来保存一个现有的pdf到pdf/A使用pdfshap。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34799564

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档