我正在编写一个桌面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);
然后它神奇地得到了错误的值。如果我在该行之前的任何时间中断程序执行,实际文件没有得到一个框,但是当它通过该行时它就会混乱。
我不知道这里发生了什么,或者如何解决它。它以前工作,我不记得我做了什么来改变它,所以它停止工作。到目前为止,我一整天都在寻找解决方案而没有运气。任何帮助将不胜感激。
答案 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的方法。