Добавление нижнего колонтитула / заголовка в PDF через onEndPage с использованием Coldfusion и iText - PullRequest
0 голосов
/ 04 мая 2018

Я использую ColdFusion и iText для создания PDF-документов, и я хочу иметь возможность добавлять заголовок и нижний колонтитул в PDF «автоматически» всякий раз, когда iText решает сделать разрыв страницы. Я видел примеры того, как сделать это в Java, и вот основной способ сделать это:

public class MyHeaderFooterPageEvent extends PdfPageEventHelper {
    public void onEndPage(PdfWriter writer, Document document) {
        //add your content here
    }
} 

И затем, прежде чем приступить к составлению своего PDF-документа, вы «регистрируете» свое событие, как его:

    MyHeaderFooterPageEvent event = new HeaderFooterPageEvent();
    writer.setPageEvent(event);

(По крайней мере, насколько я понимаю.)

Мне удалось загрузить класс PdfPageEventHelper в ColdFusion, поэтому я знаю, что он есть:

<cfset local.PdfPageEventHelper=CreateObject("java","com.lowagie.text.pdf.PdfPageEventHelper")>

А когда я выкидываю local.PdfPageEventHelper, я получаю:

enter image description here

Так как мне сказать ColdFusion, что делать, когда вызывается onEndPage, и как зарегистрировать событие, чтобы оно вызывалось?

Я использую Coldfusion 11 на сервере Linux.

1 Ответ

0 голосов
/ 04 мая 2018

Это решение в основном основано на этом старое сообщение в блоге на cfSearching.blogspot.se .

Хотя в этом решении используется динамическая прокси-библиотека javaloader , в этом решении используется более новая (?) Функция CreateDynamicProxy (доступно из ColdFusion 10, я думаю), которая Ageax (большое спасибо!) Заставил меня осознать.

Это было успешно протестировано в ColdFusion 11 на сервере Linux .

Попробуйте сами:

  1. Скопируйте и вставьте содержимое ниже в один файл cfm и один файл cfc. Хотя вы можете назвать файл cfm как угодно, файл cfc должен иметь имя PdfPageEventHandler.cfc , чтобы этот код работал.
  2. Поместите файлы в ту же папку в корне www на сервере ColdFusion.
  3. Запустите код, перейдя к cfm-файлу.
  4. Браузер должен отображать PDF из 3 страниц с основным текстом и нижними колонтитулами.

содержимое cfm-файла:

<!---call function--->
<cfset _createPdf()>
<!---function for creating pdf with footer that is created via an event handler in onEndPage--->
<cffunction name="_createPdf" output="no" returntype="void">
    <cfargument name="pdfFile" type="string" default="document.pdf" hint="the file name to write to disc">
    <cfargument name="writeToBrowser" type="boolean" default="true" hint="will open the pdf document in the browser and delete the file when done">
    <cfscript>
        //set filePath for document
        local.filePath = ExpandPath('.')&"/"&arguments.pdfFile;
        //get BaseFont
        local.BaseFont = CreateObject("java", "com.lowagie.text.pdf.BaseFont");
        //get CMYK color
        local.CMYKColor = CreateObject("java", "com.lowagie.text.pdf.CMYKColor");
        //create color
        local.color = local.CMYKColor.init(JavaCast("int",0),JavaCast("int",0),JavaCast("int",0),JavaCast("int",256));
        //create font
        local.font = local.BaseFont.createFont(local.BaseFont.COURIER, local.BaseFont.CP1252, true);
        //compose custom config to make accessable in PdfPageEventHandler.cfc
        local.config = {myCustomFooter = {text = "Page number", color = local.color, font = local.font, size = 20}};
        //init the event handler (make sure the PdfPageEventHandler.cfc is present in the same folder as this template)
        local.eventHandler = CreateObject("component", "PdfPageEventHandler").init(config = local.config); 
        //we can pass in an array of strings which name all the interfaces we want out dynamic proxy to implement
        local.interfaces = ["com.lowagie.text.pdf.PdfPageEvent"];
        //create a dynamic proxy that we will pass to the iText writer
        local.eventHandlerProxy = CreateDynamicProxy(local.eventHandler, local.interfaces);
        //init success flag
        local.success = true;
        try {
            //init document
            local.document = CreateObject("java", "com.lowagie.text.Document").init();
            //init outstream
            local.outputStream = CreateObject("java", "java.io.FileOutputStream").init(local.filePath);
            //init writer
            local.writer = CreateObject("java", "com.lowagie.text.pdf.PdfWriter").getInstance(local.document, local.outputStream);
            //register the PROXY as the page event handler
            local.writer.setPageEvent(local.eventHandlerProxy);
            //open document
            local.document.open();
            //init paragraph
            local.paragraph = CreateObject("java", "com.lowagie.text.Paragraph");
            //output some pages with a simple text message. NOTE that our eventHandler will take care of adding footers on every page - that's the whole point with this example by the way :)
            for (local.i = 1; local.i lte 3; local.i = local.i + 1) {
                //add paragraph with text
                local.document.add(local.paragraph.init("This page should have a footer with a page number on it!"));
                //trigger new page
                local.document.newPage();
            }
        } catch (any e) {
            //an error occured
            WriteOutput("Error: " & e.message);
            //set success flag to false
            local.success = false;
        }
        if (StructKeyExists(local, "document")) {
            //close document
            local.document.close();
        }
        if (StructKeyExists(local, "outStream")) {
            //close outStream
            local.outputStream.close();
        }
        if (local.success && arguments.writeToBrowser) {
            _openPdf(filePath=local.filePath);
        }
    </cfscript>
</cffunction>
<!---function for opening pdf in browser--->
<cffunction name="_openPdf" output="no" returntype="void">
    <cfargument name="filePath" type="string" required="yes">
    <cfcontent type="application/pdf" file="#arguments.filePath#" deletefile="yes">
</cffunction>

Содержимое файла cfc, которое должно называться PdfPageEventHandler.cfc :

<cfcomponent output="false" hint="iText Event handler used to add headers, footers, etc.">
<!---1. INIT FUNCTION--->
    <cffunction name="init" access="public" returntype="PdfPageEventHandler" output="false">
        <!---come up with your own arguments that you want to have access to in onEndPage etc--->
        <cfargument name="config" type="any" required="true" hint="custom config" />
        <!---make sure the config is accessable by other functions--->
        <cfset variables.config = arguments.config>
        <cfreturn this />
    </cffunction>
<!---2. ON END PAGE - the function that is in focus in this example--->
    <cffunction name="onEndPage" access="public" returntype="void" output="true" hint="Called when a page is finished, just before being written to the document.">
        <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
        <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
        <!---edit below to make your own header / footer--->
        <cfscript>
            local.cb = arguments.writer.getDirectContent();
            local.cb.saveState();
            local.cb.beginText();
            local.cb.setColorFill(variables.config.myCustomFooter.color);
            local.cb.setFontAndSize(variables.config.myCustomFooter.font, variables.config.myCustomFooter.size);
            local.cb.setTextMatrix(arguments.document.left(), arguments.document.bottom() - 10);
            local.text = "#variables.config.myCustomFooter.text# #arguments.writer.getPageNumber()#";
            local.cb.showText(local.text);
            local.cb.endText();
            local.cb.restoreState();
        </cfscript>
    </cffunction>
<!---3. OTHER FUNCTIONS THAT MUST EXIST (at least in this example)--->
    <cffunction name="onOpenDocument" access="public" returntype="void" output="false" hint="Called when the document is opened.">
        <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
        <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
        <!---To be implemented: Code called when the document is opened--->
    </cffunction>
    <cffunction name="onCloseDocument" access="public" returntype="void" output="false" hint="Called when the document is closed">
        <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
        <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
        <!---To be implemented: Code called when the document is closed--->
    </cffunction>
    <cffunction name="onStartPage" access="public" returntype="void" output="false" hint="Called when a page is initialized.">
        <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
        <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
        <!---To be implemented: Code called when a page is initialized--->
    </cffunction>
    <cffunction name="onParagraph" access="public" returntype="void" output="false" hint="Called when a Paragraph is written">
        <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
        <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
        <cfargument name="paragraphPosition" type="numeric" required="true" hint="The position the chapter will be written to. Value is a java float" />
        <!---To be implemented: Code called when paragraph is written --->
    </cffunction>
    <cffunction name="onParagraphEnd" access="public" returntype="void" output="false" hint="Called when a Paragraph is written">
        <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
        <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
        <cfargument name="paragraphPosition" type="numeric" required="true" hint="The position the chapter will be written to. Value is a java float" />
        <!---To be implemented: Code called on end of paragraph is written--->
    </cffunction>
<!---4. FUNCTIONS THAT ONLY NEEDS TO EXIST IF YOU DO SOMETHING THAT TRIGGERS THEM
    <cffunction name="OnChapter" access="public" returntype="void" output="false" hint="Called when a Chapter is written">
        <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
        <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
        <cfargument name="paragraphPosition" type="numeric" required="true" hint="The position the chapter will be written to. Value is a java float" />
        <cfargument name="title" type="any" required="true" hint="Title of the chapter. Instance of com.lowagie.text.Paragraph" />
        <!---To be implemented: Code called when a Chapter is written--->
    </cffunction>
    <cffunction name="onChapterEnd" access="public" returntype="void" output="false" hint="Called when the end of a Chapter is reached">
        <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
        <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
        <cfargument name="position" type="numeric" required="true" hint="The position of the end of the chapter. Value is a java float" />
        <!---To be implemented: Code called when the end of a Chapter is reached--->
    </cffunction>
    <cffunction name="onGenericTag" access="public" returntype="void" output="false" hint="Called when a Chunk with a generic tag is written">
        <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
        <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
        <cfargument name="rect" type="any" required="true" hint="The Rectangle containing the Chunk. Instance of com.lowagie.text.Rectangle" />
        <cfargument name="text" type="string" required="true" hint="The text of the tag" />
        <!---To be implemented: Code called when a Chunk with a generic tag is written--->
    </cffunction>
    <cffunction name="onSection" access="public" returntype="void" output="false" hint="Called when a Section is written">
        <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
        <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
        <cfargument name="paragraphPosition" type="numeric" required="true" hint="The position the chapter will be written to. Value is a java float" />
        <cfargument name="depth" type="numeric" required="true" hint="The number depth of the Section. Value is a java int" />
        <cfargument name="title" type="any" required="true" hint="Title of the section. Instance of com.lowagie.text.Paragraph" />
        <!---To be implemented: Code called when a Section is written--->
    </cffunction>
    <cffunction name="onSectionEnd" access="public" returntype="void" output="false" hint="Called when the end of a Section is reached.">
        <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
        <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
        <cfargument name="paragraphPosition" type="numeric" required="true" hint="The position the chapter will be written to. Value is a java float" />
        <cfargument name="depth" type="numeric" required="true" hint="The number depth of the Section. Value is a java int" />
        <cfargument name="title" type="numeric" required="true" hint="Title of the section. Instance of com.lowagie.text.Paragraph" />
        <!---To be implemented: Code called when the end of a Section is reached--->
    </cffunction>
    --->
</cfcomponent>

UPDATE!

Вот тот же самый cfc, но в чистом cfscript, для вас, который предпочитает это:

<cfscript>
    component output="false"  hint="iText Event handler used to add headers, footers, etc." {
        property name="config" type="struct";
        //1. INIT FUNCTION
        public PdfPageEventHandler function init(required any config) {
            //make sure the config is accessable by other functions
            variables.config = arguments.config;
            return this;
        }
    //2. ON END PAGE - the function that is in focus in this example
        public void function onEndPage(required any writer, required any document) {
            //Called when a page is finished, just before being written to the document
            //edit below to make your own header / footer
            local.cb = arguments.writer.getDirectContent();
            local.cb.saveState();
            local.cb.beginText();
            local.cb.setColorFill(variables.config.myCustomFooter.color);
            local.cb.setFontAndSize(variables.config.myCustomFooter.font, variables.config.myCustomFooter.size);
            local.cb.setTextMatrix(arguments.document.left(), arguments.document.bottom() - 10);
            local.text = "#variables.config.myCustomFooter.text# #arguments.writer.getPageNumber()#";
            local.cb.showText(local.text);
            local.cb.endText();
            local.cb.restoreState();
        }
    //3. OTHER FUNCTIONS THAT MUST EXIST (at least in this example)
        public void function onOpenDocument(required any writer, required any document) {
            //Called when the document is opened
        }
        public void function onCloseDocument(required any writer, required any document) {
            //Called when the document is closed
        }
        public void function onStartPage(required any writer, required any document) {
            //Called when a page is initialized
        }
        public void function onParagraph(required any writer, required any document, required numeric paragraphPosition) {
            //Called when a Paragraph is written
            //paragraphPosition - The position the chapter will be written to. Value is a java float
        }
        public void function onParagraphEnd(required any writer, required any document, required numeric paragraphPosition) {
            //Called when a Paragraph is written
            //paragraphPosition - The position the chapter will be written to. Value is a java float
        }
    //4. FUNCTIONS THAT ONLY NEEDS TO EXIST IF YOU DO SOMETHING THAT TRIGGERS THEM
        public void function OnChapter(required any writer, required any document, required numeric paragraphPosition, required any title) {
            //Called when a Chapter is written
            //paragraphPosition - The position the chapter will be written to. Value is a java float
            //title - Title of the chapter. Instance of com.lowagie.text.Paragraph
        }
        public void function onChapterEnd(required any writer, required any document, required numeric position) {
            //Called when the end of a Chapter is reached
            //position - The position of the end of the chapter. Value is a java float
        }
        public void function onGenericTag(required any writer, required any document, required any rect, required string text) {
            //Called when a Chunk with a generic tag is written
            //rect - The Rectangle containing the Chunk. Instance of com.lowagie.text.Rectangle
            //text - The text of the tag
        }
        public void function onSection(required any writer, required any document, required numeric paragraphPosition, required numeric depth, required any title) {
            //Called when a Section is written
            //paragraphPosition - The position the section will be written to. Value is a java float
            //depth - The number depth of the Section. Value is a java int
            //title - Title of the section. Instance of com.lowagie.text.Paragraph
        }
        public void function onSectionEnd(required any writer, required any document, required numeric paragraphPosition, required numeric depth, required any title) {
            //Called when the end of a Section is reached
            //paragraphPosition - The position the section will be written to. Value is a java float
            //depth - The number depth of the Section. Value is a java int
            //title - Title of the section. Instance of com.lowagie.text.Paragraph
        }
    }
</cfscript>
...