【问题标题】:ColdFusion CFDOCUMENT with links to other PDFs带有其他 PDF 链接的 ColdFusion CFDOCUMENT
【发布时间】:2014-01-24 06:07:45
【问题描述】:

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

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

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

如果我将 localURL 属性设置为“否”,我的 URL 将包含整个网络路径:

<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 

哇,这真是让我大吃一惊! :)

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

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

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

我糟透了! :)

【问题讨论】:

  • CD 目录结构是否已知/始终相同?
  • 它不是......或者理想情况下它应该能够是动态的。现在,我正在查看一张 CD,其中包含一个名为“STD_FLD”的目录中的所有 PDF(包括索引),因此我计算机上的路径是 J:\STD_FLD,因为我的 CD 驱动器是我的 J 驱动器。
  • 索引 PDF 确实应该与自身相关。您应该能够将所有 PDF 从 CD 中拖出并将它们存储在任何地方,并且链接应该仍然有效。
  • This thread 有一个通过修改 pdf 的注释来更新链接操作的示例。它适用于 iTextSharp 5.x,但除了包名之外,java 代码并没有太大区别。
  • 您必须从 PDFAction 对象中获取 URI 键。它返回一个字符串。然后替换 URI 键的字符串。这就像替换结构中的值一样。即theActionObject.put( pdfName.URI, "theNewValueHere");

标签: pdf coldfusion itext cfdocument


【解决方案1】:

This thread 有一个通过修改 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(); }
        }
    }

}

【讨论】:

  • Leigh 非常感谢。我现在要试试你的代码。它使我能够编辑 URI 中的路径。如果超链接有效,我不确定是否将其从“File:///75110_002.PDF”编辑为“75110_002.PDF”。我的最终目标是将 Annotation 的 Action Dictionary 的“S”键从 URI 更改为 GoToR。我不确定这是否可能。因为 URI 和 GoToR Annotation 的 Keys 完全不同。
  • 只是为了让您知道代码像冠军一样工作!因此,现在位于我桌面目录中或刻录到 CD 上的 TOC PDF 将在 Web 浏览器中打开每个链接到 PDF 的文件,因为它仍然是一个 URI! :)
  • 很高兴它有帮助。该代码可以使用一些优化,但我认为在档案中有一个古怪而肮脏的例子会很有帮助:)
  • 当然我已经进去评论了这个Local.action.put( Local.pdfName.URI, Local.pdfString.init( Local.newLink ) );并添加了Local.action.put( Local.pdfName.S, Local.pdfString.init( '/GoToR' ) );Local.action.put( Local.pdfName.D, Local.pdfString.init( '[0, /XYZ, null, null, 0]' ) );Local.action.put( Local.pdfName.F, Local.pdfString.init( Local.newLink ) );Local.action.remove( Local.pdfName.URI );它完全坏了!! :)
  • 我现在无法测试它。但是,查看the source 表明有几个为GoToR 定制的PDFAction 构造函数。尝试创建一个新的 PdfAction,然后替换字典中现有的。
【解决方案2】:

我终于明白了:

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(); }
    }
}

如果没有 Leigh 的帮助,我不可能做到这一点!!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-06
    • 1970-01-01
    • 1970-01-01
    • 2017-05-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-21
    相关资源
    最近更新 更多