【问题标题】:How to read bookmarks in PDF using itext at multi level?如何使用 itext 多级阅读 PDF 中的书签?
【发布时间】:2020-12-04 06:10:34
【问题描述】:

我正在使用 iText-Java 在书签级别拆分 PDF。 有没有人知道或有任何在 2 级或 3 级存在的书签处拆分 PDF 的示例? 例如:我有以下级别的书签:

父亲
|-儿子
|-儿子
|-女儿
|-|-孙子
|-|-孙女

现在我有下面的代码来读取读取基本书签(父亲)的书签。基本上 SimpleBookmark.getBookmark(reader) 行完成了所有工作。

但我想阅读 2 级和 3 级书签,以拆分这些内层书签之间存在的内容。

public static void splitPDFByBookmarks(String pdf, String outputFolder){ 
        try
        { 
            PdfReader reader = new PdfReader(pdf); 
            //List of bookmarks: each bookmark is a map with values for title, page, etc 
            List<HashMap> bookmarks = SimpleBookmark.getBookmark(reader); 
            for(int i=0; i<bookmarks.size(); i++){ 
                HashMap bm = bookmarks.get(i); 
                HashMap nextBM = i==bookmarks.size()-1 ? null : bookmarks.get(i+1); 
                //In my case I needed to split the title string 
                String title = ((String)bm.get("Title")).split(" ")[2]; 

                log.debug("Titel: " + title); 
                String startPage = ((String)bm.get("Page")).split(" ")[0]; 
                String startPageNextBM = nextBM==null ? "" + (reader.getNumberOfPages() + 1) : ((String)nextBM.get("Page")).split(" ")[0]; 
                log.debug("Page: " + startPage); 
                log.debug("------------------"); 
                extractBookmarkToPDF(reader, Integer.valueOf(startPage), Integer.valueOf(startPageNextBM), title + ".pdf",outputFolder); 
            } 
        } 
        catch (IOException e) 
        { 
            log.error(e.getMessage()); 
        } 
    } 

    private static void extractBookmarkToPDF(PdfReader reader, int pageFrom, int pageTo, String outputName, String outputFolder){ 
        Document document = new Document(); 
        OutputStream os = null; 

        try{ 
            os = new FileOutputStream(outputFolder + outputName); 

            // Create a writer for the outputstream 
            PdfWriter writer = PdfWriter.getInstance(document, os); 
            document.open(); 
            PdfContentByte cb = writer.getDirectContent(); // Holds the PDF data 
            PdfImportedPage page; 

            while(pageFrom < pageTo) { 
                document.newPage(); 
                page = writer.getImportedPage(reader, pageFrom); 
                cb.addTemplate(page, 0, 0); 
                pageFrom++; 
            } 

            os.flush(); 
            document.close(); 
            os.close(); 
        }catch(Exception ex){ 
            log.error(ex.getMessage()); 
        }finally { 
            if (document.isOpen()) 
                document.close(); 
            try { 
                if (os != null) 
                    os.close(); 
            } catch (IOException ioe) { 
                log.error(ioe.getMessage()); 
            } 
        } 
    } 

非常感谢您的帮助。 提前致谢! :)

【问题讨论】:

  • 只是一个注释,在我看来,您假设 PDF 中的书签将与文档中的页面顺序相同,这种假设是错误的。您可以拥有一个指向第 30 页的书签和指向第 25 页的下一个书签。您还可以拥有多个指向同一页面的书签,甚至指向外部 PDF 文档中的一个页面。
  • 为什么要使用 PdfWriter/PdfImportedPage 而不是 PdfCopy 来复制页面?这抛弃了所有的交互性!我是 iText 的原始开发者,我不明白你的代码。好像少了一部分。你能纠正这个吗?

标签: java pdf itext


【解决方案1】:

当您调用SimpleBookmark.getBookmark(reader); 时,您会得到一个ArrayList&lt;HashMap&gt;(如果需要,请进行演员表)。尝试遍历该 Arraylist 并查看其结构。如果书签有子(如您所说),它将包含另一个具有相同结构的列表。

递归方法可能是解决方案。

【讨论】:

    【解决方案2】:

    给那些使用 itext7 看这个的人的参考

    public void walkOutlines(PdfOutline outline, Map<String, PdfObject> names, PdfDocument pdfDocument,List<String>titles,List<Integer>pageNum) { //----------loop traversing all paths
        
    for (PdfOutline child : outline.getAllChildren()){
        if(child.getDestination() != null) {
            prepareIndexFile(child,names,pdfDocument,titles,pageNum,list);
        }
      }
    }
    

    //-----从大纲中获取pageNumbers

     public void prepareIndexFile(PdfOutline outline, Map<String, PdfObject> names, PdfDocument pdfDocument,List<String>titles,List<Integer>pageNum) {
        
        String title = outline.getTitle();
        
        PdfDestination pdfDestination = outline.getDestination();
        String pdfStr = ((PdfString)pdfDestination.getPdfObject()).toUnicodeString();
        PdfArray array = (PdfArray) names.get(pdfStr);
        PdfObject pdfObj = array != null ? array.get(0) : null;
        
        Integer pageNumber = pdfDocument.getPageNumber((PdfDictionary)pdfObj);
        
        titles.add(title);
        pageNum.add(pageNumber);
        
        
        if(outline.getAllChildren().size() > 0) {
            
            for (PdfOutline child : outline.getAllChildren()){
                prepareIndexFile(child,names,pdfDocument,titles,pageNum);
            }
            
        }
        
     }
    
     public boolean splitPdf(String inputFile, final String outputFolder) {
    
        boolean splitSuccess = true;
        PdfDocument pdfDoc = null;
        try {
            PdfReader pdfReaderNew = new PdfReader(inputFile);
            pdfDoc = new PdfDocument(pdfReaderNew);
            
            final List<String> titles = new ArrayList<String>();
            List<Integer> pageNum = new ArrayList<Integer>();
            
            PdfNameTree destsTree = pdfDoc.getCatalog().getNameTree(PdfName.Dests);
            Map<String, PdfObject> names = destsTree.getNames();//--------------------------------------Core logic for getting names
            PdfOutline root = pdfDoc.getOutlines(false);//--------------------------------------Core logic for getting outlines
            
            walkOutlines(root,names, pdfDoc, titles, pageNum,content);  //------Logic to get bookmarks and pageNumbers
            
    
            if (titles == null || titles.size()==0) {
                splitSuccess = false;
            }else {                                                             //------Proceed if it has bookmarks
                
                for(int i=0;i<titles.size();i++) {
                     
                     String title = titles.get(i);
                     String startPageNmStr =""+pageNum.get(i);
                     int startPage = Integer.parseInt(startPageNmStr);
                     
                     int endPage = startPage;
                     
                     if(i == titles.size() - 1) {
                         endPage = pdfDoc.getNumberOfPages();
                     }else {
                         int nextPage =  pageNum.get(i+1);
                         if(nextPage > startPage) {
                             endPage = nextPage - 1;
                         }else {
                             endPage = nextPage;
                         }
                     }
                     
                     String outFileName = outputFolder + File.separator + getFileName(title) + ".pdf";
                     PdfWriter pdfWriter = new PdfWriter(outFileName);
                    
                     PdfDocument newDocument = new PdfDocument(pdfWriter, new DocumentProperties().setEventCountingMetaInfo(null));
                     pdfDoc.copyPagesTo(startPage, endPage, newDocument);
                     newDocument.close();
                     pdfWriter.close();
                }
            }
        }catch(Exception e){
            //---log
        }       
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-28
      • 1970-01-01
      • 1970-01-01
      • 2015-07-03
      相关资源
      最近更新 更多