使用 iTextSharp 删除 PDF 不可见对象
Posted
技术标签:
【中文标题】使用 iTextSharp 删除 PDF 不可见对象【英文标题】:Removing PDF invisible objects with iTextSharp 【发布时间】:2013-02-20 07:32:43 【问题描述】:是否可以使用 iTextSharp 从 PDF 文档中删除不可见(或至少不显示)的对象?
更多细节:
1) 我的来源是一个 PDF 页面,其中包含图像和文本(可能是一些矢量图)和嵌入的字体。
2) 有一个界面可以设计多个“裁剪框”。
3) 我必须生成一个仅包含裁剪框内内容的新 PDF。必须从生成的文档中删除任何其他内容(实际上我可以接受一半在里面一半在外面的内容,但这不是理想的,无论如何也不应该出现)。
到目前为止我的解决方案:
我已经成功开发了一种解决方案,可以创建新的临时文档,每个文档都包含每个裁剪框的内容(使用 writer.GetImportedPage 和 contentByte.AddTemplate 到与裁剪框大小完全相同的页面)。然后我创建最终文档并重复该过程,使用 AddTemplate 方法将每个“裁剪页面”定位在最终页面中。
这个解决方案有两个很大的缺点:
文档的大小是[原始大小] * [裁剪框的数量],因为整页都在那里,盖了很多次! (看不见,但它就在那里) 仍然可以通过在阅读器中选择全部 (CTRL+A) 并粘贴来访问不可见文本。所以,我认为我需要遍历 PDF 对象,检测它是否可见,然后将其删除。在撰写本文时,我正在尝试使用 pdfReader.GetPdfObject。
感谢您的帮助。
【问题讨论】:
由于 iText 提供了一个低级 API,允许您操作文档中的几乎所有内容,这是可能的。不过,这不是说它是简单,因为您必须自己编写代码来识别页面内容中的每个元素是否可见,您也必须自己将内容的其余部分粘合在一起。但是,如果要使导入的页面模板的多个部分可见,则可以在当前解决方案中减小生成的文档大小。有趣的工作数周...... 尝试使用PdfStamper
类进行裁剪:itextpdf.com/examples/iia.php?id=231
就 iTextSharp 而言,我不是 100% 的,但 iPdfSharp 能够从表单呈现。这个想法是您在表单中打开您正在裁剪的页面,然后仅将您需要的部分呈现到新文档中。您不会制作多个副本,渲染(裁剪)的部分将是图像。试试看这是否是 IText api 下的一个选项。
由于时间限制,我决定使用另一个PDF框架来完成我所需要的。为此,我使用了 AmyUni PDF Creator .NET,一个简单而漂亮的库。虽然它有自己的错误,但我正在与他们互动以解决。
你看过ABCPdf吗?如果我是正确的,它可以做你想做的事,而且价格和 AmyUni lics 差不多。
【参考方案1】:
这是我找到的三个解决方案,如果它可以帮助某人(使用iTextSharp、Amyuni 或Tracker-Software,正如@Hetote 在他正在寻找另一个库的 cmets 中所说):
使用 iTextSharp
作为answered by @martinbuberl in another question:
public static void CropDocument(string file, string oldchar, string repChar)
int pageNumber = 1;
PdfReader reader = new PdfReader(file);
iTextSharp.text.Rectangle size = new iTextSharp.text.Rectangle(
Globals.fX,
Globals.fY,
Globals.fWidth,
Globals.fHeight);
Document document = new Document(size);
PdfWriter writer = PdfWriter.GetInstance(document,
new FileStream(file.Replace(oldchar, repChar),
FileMode.Create, FileAccess.Write));
document.Open();
PdfContentByte cb = writer.DirectContent;
document.NewPage();
PdfImportedPage page = writer.GetImportedPage(reader,
pageNumber);
cb.AddTemplate(page, 0, 0);
document.Close();
@rafixwpt 在his question 中的另一个答案,但它不会删除不可见的元素,它会清理页面的一个区域,这可能会影响页面的其他部分:
static void textsharpie()
string file = "C:\\testpdf.pdf";
string oldchar = "testpdf.pdf";
string repChar = "test.pdf";
PdfReader reader = new PdfReader(file);
PdfStamper stamper = new PdfStamper(reader, new FileStream(file.Replace(oldchar, repChar), FileMode.Create, FileAccess.Write));
List<PdfCleanUpLocation> cleanUpLocations = new List<PdfCleanUpLocation>();
cleanUpLocations.Add(new PdfCleanUpLocation(1, new iTextSharp.text.Rectangle(0f, 0f, 600f, 115f), iTextSharp.text.BaseColor.WHITE));
PdfCleanUpProcessor cleaner = new PdfCleanUpProcessor(cleanUpLocations, stamper);
cleaner.CleanUp();
stamper.Close();
reader.Close();
使用 Amyuni
作为answered by @yms in another question:
IacDocument.GetObjectsInRectangle 方法
GetObjectsInRectangle 方法获取位于 指定的矩形。
然后你可以迭代页面中的所有对象,删除你不感兴趣的:
//open a pdf document
document.Open(testfile, "");
IacPage page1 = document.GetPage(1);
Amyuni.PDFCreator.IacAttribute attribute = page1.AttributeByName("Objects");
// listObj is an array list of graphic objects
System.Collections.ArrayList listobj = (System.Collections.ArrayList) attribute.Value.Cast<IacObject>();;
// listObjToKeep is an array list of graphic objects inside a rectangle
var listObjToKeep = document.GetObjectsInRectangle(0f, 0f, 600f, 115f, IacGetRectObjectsConstants.acGetRectObjectsIntersecting).Cast<IacObject>();
foreach (IacObject pdfObj in listObj.Except(listObjToKeep))
// if pdfObj is not in visible inside the rectangle then call pdfObj.Delete();
pdfObj.Delete(false);
如cmets中@yms所说,另一种使用5.0版本新方法IacDocument.Redact的解决方案也可以用于删除指定矩形中的所有对象,并在其位置绘制一个纯色矩形。
使用 Tracker-Software Editor SDK
我没有尝试过,但似乎可行,请参阅post。
【讨论】:
在 Amyuni PDF Creator 的情况下,5.0 版本中添加了一个新方法IacDocument.Redact,这可能对这种情况有所帮助。【参考方案2】:是的,这是可能的。您需要将 pdf 页面内容字节解析为 PdfObject,将它们存储到内存中,删除不需要的 PdfObject,将 Pdf 内容从 PdfObject 构建回 pdf 内容字节,在通过 PdfWriter 导入页面之前替换 PdfReader 中的页面内容。
我建议你看看这个:http://habjan.blogspot.com/2013/09/proof-of-concept-converting-pdf-files.html
链接中的示例实现 Pdf 内容字节解析,从 PdfObjec 重建,替换 PdfReader 页面内容字节...
【讨论】:
【参考方案3】:PdfReader pdfReader = new PdfReader(../Template_Path.pdf"));
PdfStamper pdfStamperToPopulate = new PdfStamper(pdfReader, new FileStream(outputPath, FileMode.Create));
AcroFields pdfFormFields = pdfStamperToPopulate.AcroFields;
pdfFormFields.RemoveField("fieldNameToBeRemoved");
【讨论】:
【参考方案4】:如果您尝试的 PDF 是模板/预定义/固定,那么您可以通过调用 RemoveField 删除该对象。
PdfReader pdfReader = new PdfReader(../Template_Path.pdf"));
PdfStamper pdfStamperToPopulate = new PdfStamper(pdfReader, new FileStream(outputPath, FileMode.Create));
AcroFields pdfFormFields = pdfStamperToPopulate.AcroFields;
pdfFormFields.RemoveField("fieldNameToBeRemoved");
【讨论】:
OP 不是在谈论表单字段。他扔掉了writer.GetImportedPage
和contentByte.AddTemplate
期间的所有表单字段,如果有的话。【参考方案5】:
您是否尝试过使用 IRenderListener?您可以通过检查 TextRenderInfo 或 ImageRenderInfo 对象的 StartPoint 和 EndPoint 或 Area 有选择地仅将那些位于裁剪区域内的元素添加到新的 pdf 中。
【讨论】:
以上是关于使用 iTextSharp 删除 PDF 不可见对象的主要内容,如果未能解决你的问题,请参考以下文章
使用 iTextSharp 突出显示文本减少对 PDF 文件大小的影响
IE 浏览器不显示使用 iTextSharp 设置的 PDF 的标题和文件名
ASP.NET 转自定内容到 PDF - 使用 iTextSharp