我有一些代码需要 3 个不同的 PDF 字节数组并将它们合并。这段代码效果很好。问题(有些人)是每个 PDF 都被认为是整页(如果打印),即使上面只有 4 英寸的内容,因此垂直留下 7 英寸的空白。然后放入中间文档,其末尾可能有也可能没有垂直空白。然后页脚也会放在自己的页面上。
这是代码:
byte[] Bytes = rv.LocalReport.Render("PDF", null, out MimeType, out Encoding, out Extension, out StreamIDs, out Warnings);
List<byte[]> MergeSets = // This is filled prior to this code
// Append any other pages to this primary letter
if (MergeSets.Count > 0) {
MemoryStream ms = new MemoryStream();
Document document = new Document();
PdfCopy copy = new PdfCopy(document, ms);
document.Open();
PdfImportedPage page;
PdfReader reader = new PdfReader(Bytes); // read the generated primary Letter
int pages = reader.NumberOfPages;
for (int i = 0; i < pages; ) {
page = copy.GetImportedPage(reader, ++i);
copy.AddPage(page);
} // foreach of the pages in the Cover Letter
// Now append the merge sets
foreach (byte[] ba in MergeSets) {
reader = new PdfReader(ba);
pages = reader.NumberOfPages;
for (int i = 0; i < pages; ) {
page = copy.GetImportedPage(reader, ++i);
copy.AddPage(page);
} // foreach of the pages in the current merge set
} // foreach of the sets of data
document.Close();
ServerSaved = SaveGeneratedLetter(ms.GetBuffer(), DateTime.Now.Year, hl.LetterName, SaveName);
} // if there is anything to merge
当我合并每个页面时,有没有办法剪辑/删除/擦除每个pdf末尾的垂直空白,使其显示为一个无缝文档?header , body , footer
public class PdfVeryDenseMergeTool {
private Rectangle PageSize;
private float TopMargin;
private float BottomMargin;
private float Gap;
private Document Document = null;
private PdfWriter Writer = null;
private float YPosition = 0;
public PdfVeryDenseMergeTool(Rectangle size, float top, float bottom, float gap) {
this.PageSize = size;
this.TopMargin = top;
this.BottomMargin = bottom;
this.Gap = gap;
} // PdfVeryDenseMergeTool
public void Merge(MemoryStream outputStream, List<PdfReader> inputs) {
try {
this.OpenDocument(outputStream);
foreach (PdfReader reader in inputs) {
this.Merge(reader);
} // foreach of the PDF files to merge
} finally {
this.CloseDocument();
} // try-catch-finally
} // Merge
public void OpenDocument(MemoryStream outputStream) {
this.Document = new Document(PageSize, 36, 36, this.TopMargin, this.BottomMargin);
this.Writer = PdfWriter.GetInstance(Document, outputStream);
this.Document.Open();
this.NewPage();
} // OpenDocument
public void CloseDocument() {
try {
this.Document.Close();
} finally {
this.Document = null;
this.Writer = null;
this.YPosition = 0;
} // try-finally
} // CloseDocument
public void NewPage() {
this.Document.NewPage();
this.YPosition = PageSize.GetTop(this.TopMargin);
} // Merge
public void Merge(PdfReader reader) {
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
for (int pageIndex = 1; pageIndex <= reader.NumberOfPages; pageIndex++) {
this.Merge(reader, parser, pageIndex);
} // foreach of the pages of the current PDF
} // Merge
public void Merge(PdfReader reader, PdfReaderContentParser parser, int pageIndex) {
PdfImportedPage importedPage = Writer.GetImportedPage(reader, pageIndex);
PdfContentByte directContent = Writer.DirectContent;
PageVerticalAnalyzer finder = parser.ProcessContent(pageIndex, new PageVerticalAnalyzer());
if (finder.VerticalFlips.Count < 2)
return;
Rectangle pageSizeToImport = reader.GetPageSize(pageIndex);
int startFlip = finder.VerticalFlips.Count - 1;
bool first = true;
while (startFlip > 0) {
if (!first)
this.NewPage();
float freeSpace = this.YPosition - PageSize.GetBottom(BottomMargin);
int endFlip = startFlip + 1;
while ((endFlip > 1) && (finder.VerticalFlips[startFlip] - finder.VerticalFlips[endFlip - 2] < freeSpace))
endFlip -= 2;
if (endFlip < startFlip) {
float height = finder.VerticalFlips[startFlip] - finder.VerticalFlips[endFlip];
directContent.SaveState();
directContent.Rectangle(0, this.YPosition - height, pageSizeToImport.Width, height);
directContent.Clip();
directContent.NewPath();
this.Writer.DirectContent.AddTemplate(importedPage, 0, this.YPosition - (finder.VerticalFlips[startFlip] - pageSizeToImport.Bottom));
directContent.RestoreState();
this.YPosition -= height + this.Gap;
startFlip = endFlip - 1;
} else if (!first) {
throw new ArgumentException(string.Format("Page {0} content too large", pageIndex));
} // if
first = false;
} // while
} // Merge
} // PdfVeryDenseMergeTool
public class PageVerticalAnalyzer : IRenderListener {
public PageVerticalAnalyzer() { }
public List<float> VerticalFlips = new List<float>();
public void AddVerticalUseSection(float from, float to) {
if (to < from) {
float temp = to;
to = from;
from = temp;
}
int i = 0;
int j = 0;
for (i = 0; i < VerticalFlips.Count; i++) {
float flip = VerticalFlips[i];
if (flip < from)
continue;
for (j = i; j < VerticalFlips.Count; j++) {
flip = VerticalFlips[j];
if (flip < to)
continue;
break;
}
break;
} // foreach of the vertical flips
bool fromOutsideInterval = i % 2 == 0;
bool toOutsideInterval = j % 2 == 0;
while (j-- > i)
VerticalFlips.RemoveAt(j); // This was the problem line with just .Remove(j)
if (toOutsideInterval)
VerticalFlips.Insert(i, to);
if (fromOutsideInterval)
VerticalFlips.Insert(i, from);
} // AddVerticalUseSection
public void BeginTextBlock() { /* Do nothing */ }
public void EndTextBlock() { /* Do nothing */ }
public void RenderImage(ImageRenderInfo renderInfo) {
Matrix ctm = renderInfo.GetImageCTM();
List<float> YCoords = new List<float>(4) { 0, 0, 0, 0 };
for (int x = 0; x < 2; x++) {
for (int y = 0; y < 2; y++) {
Vector corner = new Vector(x, y, 1).Cross(ctm);
YCoords[2 * x + y] = corner[Vector.I2];
}
}
YCoords.Sort();
AddVerticalUseSection(YCoords[0], YCoords[3]);
} // RenderImage
public void RenderText(TextRenderInfo renderInfo) {
LineSegment ascentLine = renderInfo.GetAscentLine();
LineSegment descentLine = renderInfo.GetDescentLine();
List<float> YCoords = new List<float>(4) {
ascentLine.GetStartPoint()[Vector.I2],
ascentLine.GetEndPoint()[Vector.I2],
descentLine.GetStartPoint()[Vector.I2],
descentLine.GetEndPoint()[Vector.I2],
};
YCoords.Sort();
AddVerticalUseSection(YCoords[0], YCoords[3]);
} // RenderText
} // PageVericalAnalyzer
public void TestMergeDocuments() {
PdfVeryDenseMergeTool tool = new PdfVeryDenseMergeTool(iTextSharp.text.PageSize.A4, 18, 18, 10);
List<byte[]> Files = new List<byte[]>();
// Code to load each of the 3 files I need into this byte array list
using (MemoryStream ms = new MemoryStream()) {
List<PdfReader> files = new List<PdfReader>();
foreach (byte[] ba in Files) {
files.Add(new PdfReader(ba));
} // foreach of the sets of data
tool.Merge(ms, files);
// Save the file using: ms.GetBuffer()
} // using the memory stream
} // TestMergeDocuments
最佳答案
下面的示例工具是根据 this answer 的工具 PdfDenseMergeTool
的想法实现的,OP 评论说它非常接近 [他] 需要的东西。就像 PdfDenseMergeTool
一样,这里的这个工具是在 Java/iText 中实现的,我比 C#/iTextSharp 更熟悉它。作为OP has already translated PdfDenseMergeTool
to C#/iTextSharp,在这里翻译这个工具也应该不是太大的问题。
PdfVeryDenseMergeTool
该工具与 PdfDenseMergeTool
类似,从多个 PdfReader
实例中获取页面的页面内容,并尝试将它们密集合并,即将多个源页面的内容放在一个目标页面上,如果有足够的可用空间来这样做。与早期的工具相比,该工具甚至可以拆分源页面内容以实现更密集的合并。
就像其他工具一样,PdfVeryDenseMergeTool
不考虑矢量图形,因为 iText(Sharp) 解析 API 只转发文本和位图图像PdfVeryDenseMergeTool
在水平线上拆分不完全适合目标页面的源页面,该水平线不与文本字形或位图图形的边界框相交。
工具类:
此工具使用自定义 RenderListener
与 iText 解析器 API 一起使用:
它是这样使用的:
应用于 OP 的示例文档
标题.pdf
正文.pdf
页脚.pdf
它产生
如果将目标文档页面大小定义为 A5 横向:
它产生这个:
当心! 这只是概念证明,并未考虑所有可能性。例如。具有非平凡 旋转 值的源页面或目标页面的情况未得到正确处理。因此,它还没有准备好用于生产。
当前 (5.5.6 SNAPSHOT) iText 版本的改进
当前面向 5.5.6 的 iText 开发版本增强了解析器功能,以同时表示矢量图形。因此,我扩展了 PageVerticalAnalyzer
以利用它:
一个简单的测试( VeryDenseMerging.java 方法 testMergeOnlyGraphics
)合并这些文件
进入这个:
但 再次提防:这仅仅是概念的证明。尤其是modifyPath()
需要改进,实现不正确,因为它包括曲线的控制点,可能远在实际曲线之外。
关于c# - 如何在合并时删除空格,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28991291/