如何在合并时删除空格

我有一些代码需要3个不同的PDF字节数组并将其合并。这段代码很棒。(某些人)遇到的问题是,即使PDF仅包含4英寸的内容,每个PDF仍被视为整页(如果打印的话),因此垂直留有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末尾的垂直空白时,有没有一种方法可以使它显示为一个无缝文档?


四季花海
浏览 523回答 3
3回答

茅侃侃

我已经将@mkl的代码转换为C#,就在这里。工具类:public class PdfVeryDenseMergeTool {&nbsp; private Rectangle PageSize;&nbsp; private float TopMargin;&nbsp; private float BottomMargin;&nbsp; private float Gap;&nbsp; private Document Document = null;&nbsp; private PdfWriter Writer = null;&nbsp; private float YPosition = 0;&nbsp; public PdfVeryDenseMergeTool(Rectangle size, float top, float bottom, float gap) {&nbsp; &nbsp; this.PageSize = size;&nbsp; &nbsp; this.TopMargin = top;&nbsp; &nbsp; this.BottomMargin = bottom;&nbsp; &nbsp; this.Gap = gap;&nbsp; } // PdfVeryDenseMergeTool&nbsp; public void Merge(MemoryStream outputStream, List<PdfReader> inputs) {&nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; this.OpenDocument(outputStream);&nbsp; &nbsp; &nbsp; foreach (PdfReader reader in inputs) {&nbsp; &nbsp; &nbsp; &nbsp; this.Merge(reader);&nbsp; &nbsp; &nbsp; } // foreach of the PDF files to merge&nbsp; &nbsp; } finally {&nbsp; &nbsp; &nbsp; this.CloseDocument();&nbsp; &nbsp; } // try-catch-finally&nbsp; } // Merge&nbsp; public void OpenDocument(MemoryStream outputStream) {&nbsp; &nbsp; this.Document = new Document(PageSize, 36, 36, this.TopMargin, this.BottomMargin);&nbsp; &nbsp; this.Writer = PdfWriter.GetInstance(Document, outputStream);&nbsp; &nbsp; this.Document.Open();&nbsp; &nbsp; this.NewPage();&nbsp; } // OpenDocument&nbsp; public void CloseDocument() {&nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; this.Document.Close();&nbsp; &nbsp; } finally {&nbsp; &nbsp; &nbsp; this.Document = null;&nbsp; &nbsp; &nbsp; this.Writer = null;&nbsp; &nbsp; &nbsp; this.YPosition = 0;&nbsp; &nbsp; } // try-finally&nbsp; } // CloseDocument&nbsp; public void NewPage() {&nbsp; &nbsp; this.Document.NewPage();&nbsp; &nbsp; this.YPosition = PageSize.GetTop(this.TopMargin);&nbsp; } // Merge&nbsp; public void Merge(PdfReader reader) {&nbsp; &nbsp; PdfReaderContentParser parser = new PdfReaderContentParser(reader);&nbsp; &nbsp; for (int pageIndex = 1; pageIndex <= reader.NumberOfPages; pageIndex++) {&nbsp; &nbsp; &nbsp; this.Merge(reader, parser, pageIndex);&nbsp; &nbsp; } // foreach of the pages of the current PDF&nbsp; } // Merge&nbsp; public void Merge(PdfReader reader, PdfReaderContentParser parser, int pageIndex) {&nbsp; &nbsp; PdfImportedPage importedPage = Writer.GetImportedPage(reader, pageIndex);&nbsp; &nbsp; PdfContentByte directContent = Writer.DirectContent;&nbsp; &nbsp; PageVerticalAnalyzer finder = parser.ProcessContent(pageIndex, new PageVerticalAnalyzer());&nbsp; &nbsp; if (finder.VerticalFlips.Count < 2)&nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; Rectangle pageSizeToImport = reader.GetPageSize(pageIndex);&nbsp; &nbsp; int startFlip = finder.VerticalFlips.Count - 1;&nbsp; &nbsp; bool first = true;&nbsp; &nbsp; while (startFlip > 0) {&nbsp; &nbsp; &nbsp; if (!first)&nbsp; &nbsp; &nbsp; &nbsp; this.NewPage();&nbsp; &nbsp; &nbsp; float freeSpace = this.YPosition - PageSize.GetBottom(BottomMargin);&nbsp; &nbsp; &nbsp; int endFlip = startFlip + 1;&nbsp; &nbsp; &nbsp; while ((endFlip > 1) && (finder.VerticalFlips[startFlip] - finder.VerticalFlips[endFlip - 2] < freeSpace))&nbsp; &nbsp; &nbsp; &nbsp; endFlip -= 2;&nbsp; &nbsp; &nbsp; if (endFlip < startFlip) {&nbsp; &nbsp; &nbsp; &nbsp; float height = finder.VerticalFlips[startFlip] - finder.VerticalFlips[endFlip];&nbsp; &nbsp; &nbsp; &nbsp; directContent.SaveState();&nbsp; &nbsp; &nbsp; &nbsp; directContent.Rectangle(0, this.YPosition - height, pageSizeToImport.Width, height);&nbsp; &nbsp; &nbsp; &nbsp; directContent.Clip();&nbsp; &nbsp; &nbsp; &nbsp; directContent.NewPath();&nbsp; &nbsp; &nbsp; &nbsp; this.Writer.DirectContent.AddTemplate(importedPage, 0, this.YPosition - (finder.VerticalFlips[startFlip] - pageSizeToImport.Bottom));&nbsp; &nbsp; &nbsp; &nbsp; directContent.RestoreState();&nbsp; &nbsp; &nbsp; &nbsp; this.YPosition -= height + this.Gap;&nbsp; &nbsp; &nbsp; &nbsp; startFlip = endFlip - 1;&nbsp; &nbsp; &nbsp; } else if (!first) {&nbsp; &nbsp; &nbsp; &nbsp; throw new ArgumentException(string.Format("Page {0} content too large", pageIndex));&nbsp; &nbsp; &nbsp; } // if&nbsp; &nbsp; &nbsp; first = false;&nbsp; &nbsp; } // while&nbsp; } // Merge} // PdfVeryDenseMergeToolRenderListener类:修复了1行代码及其工作:请参见代码中的注释public class PageVerticalAnalyzer : IRenderListener {&nbsp; public PageVerticalAnalyzer() { }&nbsp; public List<float> VerticalFlips = new List<float>();&nbsp; public void AddVerticalUseSection(float from, float to) {&nbsp; &nbsp; if (to < from) {&nbsp; &nbsp; &nbsp; float temp = to;&nbsp; &nbsp; &nbsp; to = from;&nbsp; &nbsp; &nbsp; from = temp;&nbsp; &nbsp; }&nbsp; &nbsp; int i = 0;&nbsp; &nbsp; int j = 0;&nbsp; &nbsp; for (i = 0; i < VerticalFlips.Count; i++) {&nbsp; &nbsp; &nbsp; float flip = VerticalFlips[i];&nbsp; &nbsp; &nbsp; if (flip < from)&nbsp; &nbsp; &nbsp; &nbsp; continue;&nbsp; &nbsp; &nbsp; for (j = i; j < VerticalFlips.Count; j++) {&nbsp; &nbsp; &nbsp; &nbsp; flip = VerticalFlips[j];&nbsp; &nbsp; &nbsp; &nbsp; if (flip < to)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;&nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; } // foreach of the vertical flips&nbsp; &nbsp; bool fromOutsideInterval = i % 2 == 0;&nbsp; &nbsp; bool toOutsideInterval = j % 2 == 0;&nbsp; &nbsp; while (j-- > i)&nbsp; &nbsp; &nbsp; VerticalFlips.RemoveAt(j); // This was the problem line with just .Remove(j)&nbsp; &nbsp; if (toOutsideInterval)&nbsp; &nbsp; &nbsp; VerticalFlips.Insert(i, to);&nbsp; &nbsp; if (fromOutsideInterval)&nbsp; &nbsp; &nbsp; VerticalFlips.Insert(i, from);&nbsp; } // AddVerticalUseSection&nbsp; public void BeginTextBlock() { /* Do nothing */&nbsp; }&nbsp; public void EndTextBlock() { /* Do nothing */ }&nbsp; public void RenderImage(ImageRenderInfo renderInfo) {&nbsp; &nbsp; Matrix ctm = renderInfo.GetImageCTM();&nbsp; &nbsp; List<float> YCoords = new List<float>(4) { 0, 0, 0, 0 };&nbsp; &nbsp; for (int x = 0; x < 2; x++) {&nbsp; &nbsp; &nbsp; for (int y = 0; y < 2; y++) {&nbsp; &nbsp; &nbsp; &nbsp; Vector corner = new Vector(x, y, 1).Cross(ctm);&nbsp; &nbsp; &nbsp; &nbsp; YCoords[2 * x + y] = corner[Vector.I2];&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; YCoords.Sort();&nbsp; &nbsp; AddVerticalUseSection(YCoords[0], YCoords[3]);&nbsp; } // RenderImage&nbsp; public void RenderText(TextRenderInfo renderInfo) {&nbsp; &nbsp; LineSegment ascentLine = renderInfo.GetAscentLine();&nbsp; &nbsp; LineSegment descentLine = renderInfo.GetDescentLine();&nbsp; &nbsp; List<float> YCoords = new List<float>(4) {&nbsp; &nbsp; &nbsp; ascentLine.GetStartPoint()[Vector.I2],&nbsp; &nbsp; &nbsp; ascentLine.GetEndPoint()[Vector.I2],&nbsp; &nbsp; &nbsp; descentLine.GetStartPoint()[Vector.I2],&nbsp; &nbsp; &nbsp; descentLine.GetEndPoint()[Vector.I2],&nbsp; &nbsp; };&nbsp; &nbsp; YCoords.Sort();&nbsp; &nbsp; AddVerticalUseSection(YCoords[0], YCoords[3]);&nbsp; } // RenderText} // PageVericalAnalyzer收集文件并运行该工具的代码:public void TestMergeDocuments() {&nbsp; PdfVeryDenseMergeTool tool = new PdfVeryDenseMergeTool(iTextSharp.text.PageSize.A4, 18, 18, 10);&nbsp; List<byte[]> Files = new List<byte[]>();&nbsp; // Code to load each of the 3 files I need into this byte array list&nbsp; using (MemoryStream ms = new MemoryStream()) {&nbsp; &nbsp; List<PdfReader> files = new List<PdfReader>();&nbsp; &nbsp; foreach (byte[] ba in Files) {&nbsp; &nbsp; &nbsp; files.Add(new PdfReader(ba));&nbsp; &nbsp; } // foreach of the sets of data&nbsp; &nbsp; tool.Merge(ms, files);&nbsp; &nbsp; // Save the file using: ms.GetBuffer()&nbsp; } // using the memory stream} // TestMergeDocuments

跃然一笑

下面的示例工具一直沿着工具的想法实现PdfDenseMergeTool,从这个答案,其中OP曾评论是如此接近到什么[他] NEED 秒。就像PdfDenseMergeTool此工具在Java / iText中实现一样,我比C#/ iTextSharp更能在家中使用。由于OP 已转换 PdfDenseMergeTool为C#/ iTextSharp,因此在此处翻译此工具也不会有太大问题。PdfVeryDenseMergeTool该工具类似于PdfDenseMergeTool从多个PdfReader实例中获取页面的页面内容,并尝试密集地合并它们,即,如果有足够的可用空间,则将多个源页面的内容放到单个目标页面上。与以前的工具相比,该工具甚至可以拆分源页面内容,以实现更密集的合并。就像其他工具一样,PdfVeryDenseMergeTool它不考虑矢量图形,因为iText(Sharp)解析API仅转发文本和位图图像该PdfVeryDenseMergeTool拆分源的网页,无法完全贴合到目标页面,在未通过文字的字形或位图图形的边框相交的水平线。工具类:public class PdfVeryDenseMergeTool{&nbsp; &nbsp; public PdfVeryDenseMergeTool(Rectangle size, float top, float bottom, float gap)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; this.pageSize = size;&nbsp; &nbsp; &nbsp; &nbsp; this.topMargin = top;&nbsp; &nbsp; &nbsp; &nbsp; this.bottomMargin = bottom;&nbsp; &nbsp; &nbsp; &nbsp; this.gap = gap;&nbsp; &nbsp; }&nbsp; &nbsp; public void merge(OutputStream outputStream, Iterable<PdfReader> inputs) throws DocumentException, IOException&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; try&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; openDocument(outputStream);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (PdfReader reader: inputs)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; merge(reader);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; finally&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; closeDocument();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; void openDocument(OutputStream outputStream) throws DocumentException&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; final Document document = new Document(pageSize, 36, 36, topMargin, bottomMargin);&nbsp; &nbsp; &nbsp; &nbsp; final PdfWriter writer = PdfWriter.getInstance(document, outputStream);&nbsp; &nbsp; &nbsp; &nbsp; document.open();&nbsp; &nbsp; &nbsp; &nbsp; this.document = document;&nbsp; &nbsp; &nbsp; &nbsp; this.writer = writer;&nbsp; &nbsp; &nbsp; &nbsp; newPage();&nbsp; &nbsp; }&nbsp; &nbsp; void closeDocument()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; try&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; document.close();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; finally&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.document = null;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.writer = null;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.yPosition = 0;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; void newPage()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; document.newPage();&nbsp; &nbsp; &nbsp; &nbsp; yPosition = pageSize.getTop(topMargin);&nbsp; &nbsp; }&nbsp; &nbsp; void merge(PdfReader reader) throws IOException&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; PdfReaderContentParser parser = new PdfReaderContentParser(reader);&nbsp; &nbsp; &nbsp; &nbsp; for (int page = 1; page <= reader.getNumberOfPages(); page++)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; merge(reader, parser, page);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; void merge(PdfReader reader, PdfReaderContentParser parser, int page) throws IOException&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; PdfImportedPage importedPage = writer.getImportedPage(reader, page);&nbsp; &nbsp; &nbsp; &nbsp; PdfContentByte directContent = writer.getDirectContent();&nbsp; &nbsp; &nbsp; &nbsp; PageVerticalAnalyzer finder = parser.processContent(page, new PageVerticalAnalyzer());&nbsp; &nbsp; &nbsp; &nbsp; if (finder.verticalFlips.size() < 2)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; Rectangle pageSizeToImport = reader.getPageSize(page);&nbsp; &nbsp; &nbsp; &nbsp; int startFlip = finder.verticalFlips.size() - 1;&nbsp; &nbsp; &nbsp; &nbsp; boolean first = true;&nbsp; &nbsp; &nbsp; &nbsp; while (startFlip > 0)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!first)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newPage();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; float freeSpace = yPosition - pageSize.getBottom(bottomMargin);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int endFlip = startFlip + 1;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while ((endFlip > 1) && (finder.verticalFlips.get(startFlip) - finder.verticalFlips.get(endFlip - 2) < freeSpace))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; endFlip -=2;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (endFlip < startFlip)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; float height = finder.verticalFlips.get(startFlip) - finder.verticalFlips.get(endFlip);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; directContent.saveState();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; directContent.rectangle(0, yPosition - height, pageSizeToImport.getWidth(), height);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; directContent.clip();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; directContent.newPath();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; writer.getDirectContent().addTemplate(importedPage, 0, yPosition - (finder.verticalFlips.get(startFlip) - pageSizeToImport.getBottom()));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; directContent.restoreState();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; yPosition -= height + gap;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; startFlip = endFlip - 1;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else if (!first)&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new IllegalArgumentException(String.format("Page %s content sections too large.", page));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; first = false;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; Document document = null;&nbsp; &nbsp; PdfWriter writer = null;&nbsp; &nbsp; float yPosition = 0;&nbsp;&nbsp; &nbsp; final Rectangle pageSize;&nbsp; &nbsp; final float topMargin;&nbsp; &nbsp; final float bottomMargin;&nbsp; &nbsp; final float gap;}(PdfVeryDenseMergeTool.java)该工具利用了RenderListener与iText解析器API一起使用的自定义:public class PageVerticalAnalyzer implements RenderListener{&nbsp; &nbsp; @Override&nbsp; &nbsp; public void beginTextBlock() { }&nbsp; &nbsp; @Override&nbsp; &nbsp; public void endTextBlock() { }&nbsp; &nbsp; /*&nbsp; &nbsp; &nbsp;* @see RenderListener#renderText(TextRenderInfo)&nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; @Override&nbsp; &nbsp; public void renderText(TextRenderInfo renderInfo)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; LineSegment ascentLine = renderInfo.getAscentLine();&nbsp; &nbsp; &nbsp; &nbsp; LineSegment descentLine = renderInfo.getDescentLine();&nbsp; &nbsp; &nbsp; &nbsp; float[] yCoords = new float[]{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ascentLine.getStartPoint().get(Vector.I2),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ascentLine.getEndPoint().get(Vector.I2),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; descentLine.getStartPoint().get(Vector.I2),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; descentLine.getEndPoint().get(Vector.I2)&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; Arrays.sort(yCoords);&nbsp; &nbsp; &nbsp; &nbsp; addVerticalUseSection(yCoords[0], yCoords[3]);&nbsp; &nbsp; }&nbsp; &nbsp; /*&nbsp; &nbsp; &nbsp;* @see RenderListener#renderImage(ImageRenderInfo)&nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; @Override&nbsp; &nbsp; public void renderImage(ImageRenderInfo renderInfo)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; Matrix ctm = renderInfo.getImageCTM();&nbsp; &nbsp; &nbsp; &nbsp; float[] yCoords = new float[4];&nbsp; &nbsp; &nbsp; &nbsp; for (int x=0; x < 2; x++)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (int y=0; y < 2; y++)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Vector corner = new Vector(x, y, 1).cross(ctm);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; yCoords[2*x+y] = corner.get(Vector.I2);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; Arrays.sort(yCoords);&nbsp; &nbsp; &nbsp; &nbsp; addVerticalUseSection(yCoords[0], yCoords[3]);&nbsp; &nbsp; }&nbsp; &nbsp; /**&nbsp; &nbsp; &nbsp;* This method marks the given interval as used.&nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; void addVerticalUseSection(float from, float to)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (to < from)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; float temp = to;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; to = from;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; from = temp;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; int i=0, j=0;&nbsp; &nbsp; &nbsp; &nbsp; for (; i<verticalFlips.size(); i++)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; float flip = verticalFlips.get(i);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (flip < from)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (j=i; j<verticalFlips.size(); j++)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; flip = verticalFlips.get(j);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (flip < to)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; boolean fromOutsideInterval = i%2==0;&nbsp; &nbsp; &nbsp; &nbsp; boolean toOutsideInterval = j%2==0;&nbsp; &nbsp; &nbsp; &nbsp; while (j-- > i)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; verticalFlips.remove(j);&nbsp; &nbsp; &nbsp; &nbsp; if (toOutsideInterval)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; verticalFlips.add(i, to);&nbsp; &nbsp; &nbsp; &nbsp; if (fromOutsideInterval)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; verticalFlips.add(i, from);&nbsp; &nbsp; }&nbsp; &nbsp; final List<Float> verticalFlips = new ArrayList<Float>();}(PageVerticalAnalyzer.java)它的用法如下:PdfVeryDenseMergeTool tool = new PdfVeryDenseMergeTool(PageSize.A4, 18, 18, 5);tool.merge(output, inputs);(VeryDenseMerging.java)适用于OP的样本文件标题.pdf身体.pdf页脚.pdf它产生如果将目标文档页面尺寸定义为A5横向:PdfVeryDenseMergeTool tool = new PdfVeryDenseMergeTool(new RectangleReadOnly(595,421), 18, 18, 5);tool.merge(output, inputs);(VeryDenseMerging.java)它生成此:谨防!这仅是概念的证明,并未考虑所有可能性。例如,没有正确处理“旋转”值不重要的源页面或目标页面的情况。因此,它还没有准备好用于生产。当前(5.5.6 SNAPSHOT)iText版本的改进当前面向5.5.6的iText开发版本增强了解析器功能,还可以向矢量图形发出信号。因此,我扩展了PageVerticalAnalyzer,以利用此功能:public class PageVerticalAnalyzer implements ExtRenderListener{&nbsp; &nbsp; @Override&nbsp; &nbsp; public void beginTextBlock() { }&nbsp; &nbsp; @Override&nbsp; &nbsp; public void endTextBlock() { }&nbsp; &nbsp; @Override&nbsp; &nbsp; public void clipPath(int rule) { }&nbsp; &nbsp; ...&nbsp; &nbsp; static class SubPathSection&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; public SubPathSection(float x, float y, Matrix m)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; float effectiveY = getTransformedY(x, y, m);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pathFromY = effectiveY;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pathToY = effectiveY;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; void extendTo(float x, float y, Matrix m)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; float effectiveY = getTransformedY(x, y, m);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (effectiveY < pathFromY)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pathFromY = effectiveY;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else if (effectiveY > pathToY)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pathToY = effectiveY;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; float getTransformedY(float x, float y, Matrix m)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return new Vector(x, y, 1).cross(m).get(Vector.I2);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; float getFromY()&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return pathFromY;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; float getToY()&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return pathToY;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; private float pathFromY;&nbsp; &nbsp; &nbsp; &nbsp; private float pathToY;&nbsp; &nbsp; }&nbsp; &nbsp; /*&nbsp; &nbsp; &nbsp;* Beware: The implementation is not correct as it includes the control points of curves&nbsp; &nbsp; &nbsp;* which may be far outside the actual curve.&nbsp; &nbsp; &nbsp;*&nbsp;&nbsp; &nbsp; &nbsp;* @see ExtRenderListener#modifyPath(PathConstructionRenderInfo)&nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; @Override&nbsp; &nbsp; public void modifyPath(PathConstructionRenderInfo renderInfo)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; Matrix ctm = renderInfo.getCtm();&nbsp; &nbsp; &nbsp; &nbsp; List<Float> segmentData = renderInfo.getSegmentData();&nbsp; &nbsp; &nbsp; &nbsp; switch (renderInfo.getOperation())&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; case PathConstructionRenderInfo.MOVETO:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subPath = null;&nbsp; &nbsp; &nbsp; &nbsp; case PathConstructionRenderInfo.LINETO:&nbsp; &nbsp; &nbsp; &nbsp; case PathConstructionRenderInfo.CURVE_123:&nbsp; &nbsp; &nbsp; &nbsp; case PathConstructionRenderInfo.CURVE_13:&nbsp; &nbsp; &nbsp; &nbsp; case PathConstructionRenderInfo.CURVE_23:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i < segmentData.size()-1; i+=2)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (subPath == null)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subPath = new SubPathSection(segmentData.get(i), segmentData.get(i+1), ctm);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; path.add(subPath);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subPath.extendTo(segmentData.get(i), segmentData.get(i+1), ctm);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; case PathConstructionRenderInfo.RECT:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; float x = segmentData.get(0);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; float y = segmentData.get(1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; float w = segmentData.get(2);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; float h = segmentData.get(3);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SubPathSection section = new SubPathSection(x, y, ctm);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; section.extendTo(x+w, y, ctm);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; section.extendTo(x, y+h, ctm);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; section.extendTo(x+w, y+h, ctm);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; path.add(section);&nbsp; &nbsp; &nbsp; &nbsp; case PathConstructionRenderInfo.CLOSE:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subPath = null;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; default:&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; /*&nbsp; &nbsp; &nbsp;* @see ExtRenderListener#renderPath(PathPaintingRenderInfo)&nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; @Override&nbsp; &nbsp; public Path renderPath(PathPaintingRenderInfo renderInfo)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (renderInfo.getOperation() != PathPaintingRenderInfo.NO_OP)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (SubPathSection section : path)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addVerticalUseSection(section.getFromY(), section.getToY());&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; path.clear();&nbsp; &nbsp; &nbsp; &nbsp; subPath = null;&nbsp; &nbsp; &nbsp; &nbsp; return null;&nbsp; &nbsp; }&nbsp; &nbsp; List<SubPathSection> path = new ArrayList<SubPathSection>();&nbsp; &nbsp; SubPathSection subPath = null;&nbsp; &nbsp; ...}(PageVerticalAnalyzer.java)一个简单的测试(VeryDenseMerging.java方法testMergeOnlyGraphics)合并这些文件但是,再次提防:这仅仅是概念的证明。尤其modifyPath()需要改进,实现方式不正确,因为它包括可能远远超出实际曲线的曲线控制点。
打开App,查看更多内容
随时随地看视频慕课网APP