3

我目前正在使用 cfdocument 标签创建 PDF。PDF 只不过是一堆指向其他 PDF 的链接。

所以我创建了这个 PDF 索引,链接都是 HREF

<a href="Another_PDF.pdf">Another PDF</a>

如果我将 localURL 属性设置为“no”,我的 URL 中包含整个 Web 路径:

<a href="http://www.mywebsite.com/media/PDF/Another_PDF.pdf">Another PDF</a>

如果我将 localURL 属性设置为“是”,那么我得到:

<a href="File:/D:/website/media/PDF/Another_PDF.pdf">Another PDF</a>

所以这个索引 PDF 将进入 CD,所有链接的 PDF 都将放在它旁边,所以我需要一个相对链接......更像:

<a href="Another_PDF.pdf">Another PDF</a>

cfdocument 似乎没有这样做。我可以修改文档的文件名并将其设为“File:///Another_PDF.pdf”,但这不起作用,因为我不知道 CD 驱动器的驱动器号......或者文件是否要最终位于 CD 上的目录中。

有没有办法(可能使用 iText 或其他东西)在创建 PDF 并将 URL 链接转换为实际的 PDF GoTo 标签后打开它?

我知道这有点牵强,但我对此束手无策。

所以我设法进入了对象,但我仍在努力。

转换自:

5 0 obj<</C[0 0 1]/Border[0 0 0]/A<</URI(File:///75110_002.PDF)/S/URI>>/Subtype/Link/Rect[145 502 184 513]>>endobj

对此:

19 0 obj<</SGoToR/D[0/XYZ null null 0]/F(75110_002.PDF)>>endobj 
20 0 obj<</Subtype/Link/Rect[145 502 184 513]/Border[0 0 0]/A 19 0 R>>endobj 

哇,这真的是在踢我的屁股!:)

所以我设法打开文档,循环链接注释,捕获矩形坐标和链接到文档名称(保存到结构数组中),然后成功删除作为 URI 链接的注释。

所以现在我想我现在可以遍历该结构数组并使用 createLink 方法或 setAction 方法将注释放回文档中。但是我看到的所有这些方法的例子都附加到一个块(文本)上。但是我的文档已经有文本,所以我不需要重新制作文本链接,我只需要将链接放回同一个位置。

所以我想我可以重新打开文档并查找作为链接的实际文本,然后将 setAction 附加到已经存在的文本块中......我找不到文本!

我吸!:)

4

2 回答 2

1

I finally got it:

public function resetLinks( string source, string destination) {

    try {

        // initialize objects
        Local.reader = createObject("java", "com.lowagie.text.pdf.PdfReader").init( arguments.source );
        Local.pdfName = createObject("java", "com.lowagie.text.pdf.PdfName");
        Local.annot = createObject("java", "com.lowagie.text.pdf.PdfAnnotation");
        Local.out = createObject("java", "java.io.FileOutputStream").init( arguments.destination );
        Local.stamper = createObject("java", "com.lowagie.text.pdf.PdfStamper").init(Local.reader, Local.out);
        Local.PdfAction = createObject("java", "com.lowagie.text.pdf.PdfAction");
        Local.PdfRect = createObject("java", "com.lowagie.text.Rectangle");
        Local.PdfBorderArray = createObject("java", "com.lowagie.text.pdf.PdfBorderArray").init(javacast("float", "0"), javacast("float", "0"), javacast("float", "0"));
        Local.newAnnots = [];

        // check each page for hyperlinks
        // Save the data to a structure then write it to an array 
        // then delete the hyperlink Annotation
        for ( Local.i = 1; Local.i <= Local.reader.getNumberOfPages(); Local.i = Local.i + 1) {
            //Get all of the annotations for the current page
            Local.page = Local.reader.getPageN( Local.i );
            Local.annotations = Local.page.getAsArray( Local.PdfName.ANNOTS ).getArrayList();

            // search annotations for links
            for (Local.x = arrayLen(Local.annotations); !isNull( Local.annotations) && Local.x > 0; Local.x--) {
                // get current properties
                Local.current     = Local.annotations[ Local.x ]; 
                Local.dictionary  = Local.reader.getPdfObject( Local.current );
                Local.subType     = Local.dictionary.get( Local.PdfName.SUBTYPE );
                Local.action      = Local.dictionary.get( Local.PdfName.A );
                Local.hasLink     = true;

                //Skip this item if it does not have a link AND action
                if (Local.subType != Local.PdfName.LINK || isNull(Local.action)) {
                    Local.hasLink = false;
                }
                //Skip this item if it does not have a URI
                if ( Local.hasLink && Local.action.get( Local.PdfName.S ) != Local.PdfName.URI ) {
                    Local.hasLink = false;
                } 

                //If it is a valid URI, update link
                if (Local.hasLink) {
                    // extract file name from URL
                    Local.oldLink = Local.action.get( Local.pdfName.URI );
                    Local.newLink  = getFileFromPath( Local.oldLink );
                    Local.Rect = Local.dictionary.Get(PdfName.Rect);
                    arrayStruct = StructNew();
                    arrayStruct.rectSTR = Local.Rect.toString();
                    arrayStruct.link = Local.newLink;
                    arrayStruct.page = Local.i;
                    ArrayAppend(Local.newAnnots, arrayStruct);
                    // Delete
                    Local.annotations.remove(Local.current);
                }
            }

        }

        // Now really remove them!   
        Local.reader.RemoveUnusedObjects();

        // Now loop over the saved annotations and put them back!!
        for ( Local.z = 1; Local.z <= ArrayLen(Local.newAnnots); Local.z++) {
            // Parse the rect we got save into an Array
            theRectArray = ListToArray(ReplaceNoCase(ReplaceNoCase(Local.newAnnots[z].rectSTR, "[", ""), "]", ""));
            // Create the GoToR action
            theAction = Local.PdfAction.gotoRemotePage(javacast("string", '#Local.newAnnots[z].link#'), javacast("string", '#Local.newAnnots[z].link#'), javacast("boolean", "false"), javacast("boolean", "false"));
            // Create the Link Annotation with the above Action and the Rect
            theAnnot = Local.annot.createLink(Local.stamper.getWriter(), Local.PdfRect.init(javacast("int", theRectArray[1]), javacast("int", theRectArray[2]), javacast("int", theRectArray[3]), javacast("int", theRectArray[4])), Local.annot.HIGHLIGHT_INVERT, theAction);
            // Remove the border the underlying underlined text will flag item as a link
            theAnnot.setBorder(Local.PdfBorderArray);
            // Add the Annotation to the Page
            Local.stamper.addAnnotation(theAnnot, Local.newAnnots[z].page);
        }
    }

    finally {
        // cleanup
        if (structKeyExists(Local, "reader")) { Local.reader.close(); }
        if (structKeyExists(Local, "stamper")) { Local.stamper.close(); }
        if (structKeyExists(Local, "out")) { Local.out.close(); }
    }
}

I couldn't have done this without the help of Leigh!!

于 2014-01-15T22:08:22.703 回答
1

该线程有一个通过修改 pdf 注释来更新链接操作的示例。它是用 iTextSharp 5.x 编写的,但 java 代码差别不大。

该线程提供了注释如何工作的可靠解释。但总而言之,您需要阅读源 pdf 并循环浏览各个页面以获取注释。提取链接并使用类似的东西getFileFromPath()仅用文件名替换它们。

我很好奇,所以我对上面的 iTextSharp 代码进行了快速而丑陋的转换。免责声明,它没有经过高度测试:

/**
    Usage:

    util = createObject("component", "path.to.ThisComponent");
    util.fixLinks( "c:/path/to/sourceFile.pdf", "c:/path/to/newFile.pdf");

*/
component {

    /**
        Convert all absolute links, in the given pdf, to relative links (file name only)
        @source - absolute path to the source pdf file
        @destination - absolute path to save copy
    */
    public function fixLinks( string source, string destination) {
        // initialize objects
        Local.reader = createObject("java", "com.lowagie.text.pdf.PdfReader").init( arguments.source );
        Local.pdfName = createObject("java", "com.lowagie.text.pdf.PdfName");

        // check each page for hyperlinks
        for ( Local.i = 1; Local.i <= Local.reader.getNumberOfPages(); Local.i++) {

            //Get all of the annotations for the current page
            Local.page = Local.reader.getPageN( Local.i );
            Local.annotations = Local.page.getAsArray( Local.PdfName.ANNOTS ).getArrayList();

            // search annotations for links
            for (Local.x = 1; !isNull( Local.annotations) && Local.x < arrayLen(Local.annotations); Local.x++) {

                  // get current properties
                  Local.current     = Local.annotations[ Local.x ]; 
                  Local.dictionary  = Local.reader.getPdfObject( Local.current );
                  Local.subType     = Local.dictionary.get( Local.PdfName.SUBTYPE );
                  Local.action      = Local.dictionary.get( Local.PdfName.A );
                  Local.hasLink     = true;

                  //Skip this item if it does not have a link AND action
                  if (Local.subType != Local.PdfName.LINK || isNull(Local.action)) {
                       Local.hasLink = false;
                  }
                  //Skip this item if it does not have a URI
                  if ( Local.hasLink && Local.action.get( Local.PdfName.S ) != Local.PdfName.URI ) {
                       Local.hasLink = false;
                  } 

                  //If it is a valid URI, update link
                  if (Local.hasLink) {
                      // extract file name from URL
                      Local.oldLink = Local.action.get( Local.pdfName.URI );
                      Local.newLink  = getFileFromPath( Local.oldLink );

                      // replace link
                      // WriteDump("Changed link from ["& Local.oldLink &"] ==> ["& Local.newLink &"]");
                      Local.pdfString = createObject("java", "com.lowagie.text.pdf.PdfString");
                      Local.action.put( Local.pdfName.URI, Local.pdfString.init( Local.newLink ) );
                  }
            }

        }

        // save all pages to new file   
        copyPDF( Local.reader , arguments.destination );    
    }

    /**
        Copy all pages in pdfReader to the given destination file
        @pdfReader - pdf to copy
        @destination - absolute path to save copy
    */
    public function copyPDF( any pdfReader, string destination) {
        try {

          Local.doc = createObject("java", "com.lowagie.text.Document").init();
          Local.out = createObject("java", "java.io.FileOutputStream").init( arguments.destination );
          Local.writer = createObject("java", "com.lowagie.text.pdf.PdfCopy").init(Local.doc, Local.out);

          // open document and save individual pages        
          Local.doc.open();
          for (Local.i = 1; i <= arguments.pdfReader.getNumberOfPages(); Local.i++) {
              Local.writer.addPage( Local.writer.getImportedPage( arguments.pdfReader,  Local.i) );
          }
          Local.doc.close();
        }
        finally 
        {
            // cleanup
            if (structKeyExists(Local, "doc")) { Local.doc.close(); }
            if (structKeyExists(Local, "writer")) { Local.writer.close(); }
            if (structKeyExists(Local, "out")) { Local.out.close(); }
        }
    }

}
于 2014-01-07T23:02:03.337 回答