diff --git a/CHANGELOG.md b/CHANGELOG.md index a263486..1816266 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [1.2.0-sa.1] - 2023-11-17 +### Added + +- document metadata handling (doc-title, doc-author, doc-language, doc-subject, doc-creator) ### Changed -- fj-doc version set to 3.2.0 -- openpdf version 1.3.33 +- fj-doc version set to 3.1.3 ## [1.1.0-sa.1] - 2023-09-16 diff --git a/pom.xml b/pom.xml index 2406900..ed336af 100644 --- a/pom.xml +++ b/pom.xml @@ -7,13 +7,13 @@ org.fugerit.java fj-doc - 3.2.0 + 3.1.3 fj-doc-mod-openpdf Fugerit DOC module for output in PDF, RTF and HTML using OpenPDF (Itext fork) - 1.2.0-sa.1 + 1.2.0-SNAPSHOT @@ -25,7 +25,7 @@ ${project.parent.version} - 1.3.33 + 1.3.30 1.2.1 diff --git a/src/main/java/org/fugerit/java/doc/mod/openpdf/PdfTypeHandler.java b/src/main/java/org/fugerit/java/doc/mod/openpdf/PdfTypeHandler.java index 9d76261..8e9ab20 100644 --- a/src/main/java/org/fugerit/java/doc/mod/openpdf/PdfTypeHandler.java +++ b/src/main/java/org/fugerit/java/doc/mod/openpdf/PdfTypeHandler.java @@ -8,6 +8,7 @@ import org.fugerit.java.doc.base.config.DocTypeHandler; import org.fugerit.java.doc.base.config.DocTypeHandlerDefault; import org.fugerit.java.doc.base.model.DocBase; +import org.fugerit.java.doc.mod.openpdf.events.PageNumbersEventHandler; import org.fugerit.java.doc.mod.openpdf.helpers.OpenPpfDocHandler; import com.lowagie.text.Document; @@ -16,13 +17,14 @@ public class PdfTypeHandler extends DocTypeHandlerDefault { - /** - * - */ private static final long serialVersionUID = 5459938865782356227L; public static final DocTypeHandler HANDLER = new PdfTypeHandler(); + /* + * OpenPDF examples : https://github.com/LibrePDF/OpenPDF/tree/master/pdf-toolbox/src/test/java/com/lowagie/examples + */ + public PdfTypeHandler() { super( OpenPpfDocHandler.DOC_OUTPUT_PDF, OpenPpfDocHandler.MODULE ); } @@ -42,17 +44,7 @@ public void handle(DocInput docInput, DocOutput docOutput) throws Exception { PdfWriter pdfWriter = PdfWriter.getInstance( document, baos ); // create doc handler OpenPpfDocHandler handler = new OpenPpfDocHandler( document, pdfWriter ); - if ( "true".equalsIgnoreCase( docBase.getInfo().getProperty( "set-total-page" ) ) ) { - handler.handleDoc( docBase ); - int totalPageCount = pdfWriter.getCurrentPageNumber()-1; - document = new Document( PageSize.A4, Integer.parseInt( margins[0] ), - Integer.parseInt( margins[1] ), - Integer.parseInt( margins[2] ), - Integer.parseInt( margins[3] ) ); - baos = new ByteArrayOutputStream(); - pdfWriter = PdfWriter.getInstance( document, baos ); - handler = new OpenPpfDocHandler(document, pdfWriter, totalPageCount ); - } + //pdfWriter.setPageEvent( new PageNumbersEventHandler( docBase ) ); handler.handleDoc( docBase ); baos.writeTo( outputStream ); baos.close(); diff --git a/src/main/java/org/fugerit/java/doc/mod/openpdf/events/PageNumbersEventHandler.java b/src/main/java/org/fugerit/java/doc/mod/openpdf/events/PageNumbersEventHandler.java new file mode 100644 index 0000000..23219f0 --- /dev/null +++ b/src/main/java/org/fugerit/java/doc/mod/openpdf/events/PageNumbersEventHandler.java @@ -0,0 +1,139 @@ +package org.fugerit.java.doc.mod.openpdf.events; + +import org.fugerit.java.core.function.SafeFunction; +import org.fugerit.java.doc.base.model.DocBase; +import org.fugerit.java.doc.base.model.DocElement; +import org.fugerit.java.doc.base.model.DocPara; +import org.fugerit.java.doc.base.model.DocPhrase; +import org.fugerit.java.doc.mod.openpdf.helpers.PageNumberHelper; + +import com.lowagie.text.Document; +import com.lowagie.text.Rectangle; +import com.lowagie.text.pdf.BaseFont; +import com.lowagie.text.pdf.PdfContentByte; +import com.lowagie.text.pdf.PdfPageEventHelper; +import com.lowagie.text.pdf.PdfTemplate; +import com.lowagie.text.pdf.PdfWriter; + +import lombok.Getter; + +/** + *

+ * Event Helper for ${currentPage} and ${pageCount} properties + *

+ * + *

+ * Adapted from : + * https://github.com/LibrePDF/OpenPDF/blob/master/pdf-toolbox/src/test/java/com/lowagie/examples/directcontent/pageevents/PageNumbersWatermark.java + *

+ * + */ +public class PageNumbersEventHandler extends PdfPageEventHelper { + + public PageNumbersEventHandler(DocBase docBase) { + super(); + this.pageNumberHeader = PageNumberHelper.findPageNumberElement(docBase.getDocHeader()); + this.pageNumberFooter = PageNumberHelper.findPageNumberElement(docBase.getDocFooter()); + } + + /** A template that will hold the total number of pages. */ + private PdfTemplate tpl; + + /** The font that will be used. */ + private BaseFont helv; + + private DocElement pageNumberHeader; + + private DocElement pageNumberFooter; + + @Override + public void onOpenDocument(PdfWriter writer, Document document) { + if (this.pageNumberFooter != null || this.pageNumberHeader != null) { + SafeFunction.apply(() -> { + // initialization of the template + tpl = writer.getDirectContent().createTemplate(100, 100); + tpl.setBoundingBox(new Rectangle(-20, -20, 100, 100)); + // initialization of the font + helv = BaseFont.createFont("Helvetica", BaseFont.WINANSI, false); + }); + } + } + + private void headerFooterHelper(PdfWriter writer, Document document, DocElement element, boolean header) { + if (element!= null) { + ElementData data = new ElementData( element ); + PdfContentByte cb = writer.getDirectContent(); + cb.saveState(); + String text = data.parseText( writer.getPageNumber() ); + float textSize = helv.getWidthPoint(text, 12); + float textBase = document.bottom() - 20; + if ( header ) { + textBase = document.top() - 20; + } + float align = document.left(); + float templateAlign = align + textSize; + if ( data.getAlign() == DocPara.ALIGN_RIGHT ) { + templateAlign = document.right(); + align = templateAlign - textSize; + } else if ( data.getAlign() == DocPara.ALIGN_CENTER ) { + align = (document.right()-document.left()-textSize)/2; + templateAlign = align+textSize; + } + cb.beginText(); + cb.setFontAndSize(helv, 12); + cb.setTextMatrix(align, textBase); + cb.showText(text); + cb.endText(); + cb.addTemplate(tpl, templateAlign, textBase); + cb.restoreState(); + cb.sanityCheck(); + } + } + + @Override + public void onStartPage(PdfWriter writer, Document document) { + this.headerFooterHelper(writer, document, this.pageNumberHeader, true); + } + + @Override + public void onEndPage(PdfWriter writer, Document document) { + this.headerFooterHelper(writer, document, this.pageNumberFooter, false); + } + + @Override + public void onCloseDocument(PdfWriter writer, Document document) { + if (this.pageNumberFooter != null || this.pageNumberHeader != null) { + tpl.beginText(); + tpl.setFontAndSize(helv, 12); + tpl.setTextMatrix(0, 0); + tpl.showText(Integer.toString(writer.getPageNumber() - 1)); + tpl.endText(); + tpl.sanityCheck(); + } + } + +} + +class ElementData { + + @Getter private int align; + + @Getter private String text; + + public ElementData( DocElement element ) { + if ( element instanceof DocPhrase ) { + DocPhrase e = (DocPhrase)element; + this.align = DocPara.ALIGN_CENTER; + this.text = e.getText(); + } else if ( element instanceof DocPara ) { + DocPara e = (DocPara)element; + this.align = e.getAlign(); + this.text = e.getText(); + } + } + + public String parseText( int pageNumber ) { + return this.getText().replace( PageNumberHelper.CURRENT_PAGE , String.valueOf(pageNumber) ).replace( PageNumberHelper.PAGE_COUNT , "" ); + } + +} \ No newline at end of file diff --git a/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/OpenPpfDocHandler.java b/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/OpenPpfDocHandler.java index 5ad50c1..a7f279b 100644 --- a/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/OpenPpfDocHandler.java +++ b/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/OpenPpfDocHandler.java @@ -8,6 +8,7 @@ import java.util.Iterator; import java.util.List; import java.util.Properties; +import java.util.function.Consumer; import org.fugerit.java.core.cfg.ConfigRuntimeException; import org.fugerit.java.core.lang.helpers.StringUtils; @@ -28,6 +29,7 @@ import org.fugerit.java.doc.base.model.DocPhrase; import org.fugerit.java.doc.base.model.DocStyle; import org.fugerit.java.doc.base.model.DocTable; +import org.fugerit.java.doc.base.typehelper.generic.GenericConsts; import org.fugerit.java.doc.base.xml.DocModelUtils; import com.lowagie.text.Anchor; @@ -345,12 +347,25 @@ private void handleFooter( DocBase docBase, PdfHelper pdfHelper, OpenPdfHelper d } } + private void applyIfNotEmpty( String value, Consumer c ) { + if ( StringUtils.isNotEmpty( value ) ) { + c.accept(value); + } + } + /* (non-Javadoc) * @see org.fugerit.java.doc.base.DocHandler#handleDoc(org.fugerit.java.doc.base.DocBase) */ public void handleDoc(DocBase docBase) throws DocumentException, IOException { Properties info = docBase.getInfo(); + // set document metadata + applyIfNotEmpty( docBase.getStableInfo().getProperty( GenericConsts.INFO_KEY_DOC_TITLE ) , s -> this.document.addTitle( s ) ); + applyIfNotEmpty( docBase.getStableInfo().getProperty( GenericConsts.INFO_KEY_DOC_AUTHOR ) , s -> this.document.addAuthor( s ) ); + applyIfNotEmpty( docBase.getStableInfo().getProperty( GenericConsts.INFO_KEY_DOC_SUBJECT ) , s -> this.document.addSubject( s ) ); + applyIfNotEmpty( docBase.getStableInfo().getProperty( GenericConsts.INFO_KEY_DOC_CREATOR ) , s -> this.document.addCreator( s ) ); + applyIfNotEmpty( docBase.getStableInfo().getProperty( GenericConsts.INFO_KEY_DOC_LANGUAGE ) , s -> this.document.setDocumentLanguage( s ) ); + String defaultFontName = info.getProperty( DOC_DEFAULT_FONT_NAME, "helvetica" ); String defaultFontSize = info.getProperty( DOC_DEFAULT_FONT_SIZE, "10" ); String defaultFontStyle = info.getProperty( DOC_DEFAULT_FONT_STYLE, "normal" ); @@ -430,17 +445,9 @@ public static Element getElement( Document document, DocElement docElement, bool return result; } - private void handleHeaderFooterElement( DocElement docElement, float leading, OpenPdfHelper docHelper , Phrase phrase ) throws DocumentException, IOException { - if ( docElement instanceof DocPhrase ) { - DocPhrase docPhrase = (DocPhrase) docElement; - Chunk ck = createChunk( docPhrase, docHelper ); - if( docPhrase.getLeading() != null && docPhrase.getLeading().floatValue() != leading ) { - leading = docPhrase.getLeading().floatValue(); - phrase.setLeading( leading ); - } - phrase.add( ck ); - } else if ( docElement instanceof DocPara ) { - DocPara docPara = (DocPara) docElement; + private void handleHeaderFooterPara( DocElement docElement , Phrase phrase ) throws DocumentException { + DocPara docPara = (DocPara) docElement; + if ( !PageNumberHelper.isPageNumberContent( docPara.getText() ) ) { if ( docPara.getLeading() != null ) { phrase.setLeading( docPara.getLeading().floatValue() ); } @@ -454,6 +461,22 @@ private void handleHeaderFooterElement( DocElement docElement, float leading, Op } Chunk ck = new Chunk( docPara.getText(), f ); phrase.add( ck ); + } + } + + private void handleHeaderFooterElement( DocElement docElement, float leading, OpenPdfHelper docHelper , Phrase phrase ) throws DocumentException, IOException { + if ( docElement instanceof DocPhrase ) { + DocPhrase docPhrase = (DocPhrase) docElement; + if ( !PageNumberHelper.isPageNumberContent( docPhrase.getText() ) ) { + Chunk ck = createChunk( docPhrase, docHelper ); + if( docPhrase.getLeading() != null && docPhrase.getLeading().floatValue() != leading ) { + leading = docPhrase.getLeading().floatValue(); + phrase.setLeading( leading ); + } + phrase.add( ck ); + } + } else if ( docElement instanceof DocPara ) { + this.handleHeaderFooterPara(docElement, phrase); } else if ( docElement instanceof DocImage ) { DocImage docImage = (DocImage)docElement; Image img = createImage( docImage ); diff --git a/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/PageNumberHelper.java b/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/PageNumberHelper.java new file mode 100644 index 0000000..1d8c9f1 --- /dev/null +++ b/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/PageNumberHelper.java @@ -0,0 +1,38 @@ +package org.fugerit.java.doc.mod.openpdf.helpers; + +import org.fugerit.java.doc.base.model.DocContainer; +import org.fugerit.java.doc.base.model.DocElement; +import org.fugerit.java.doc.base.model.DocPara; +import org.fugerit.java.doc.base.model.DocPhrase; + +public class PageNumberHelper { + + private PageNumberHelper() {} + + public static final String CURRENT_PAGE = "${currentPage}"; + + public static final String PAGE_COUNT = "${pageCount}"; + + public static boolean isPageNumberContent( String text ) { + return text.contains( CURRENT_PAGE ) || text.contains( PAGE_COUNT ); + } + + public static DocElement findPageNumberElement( DocContainer c ) { + DocElement res = null; + for ( DocElement current : c.getElementList() ) { + if ( current instanceof DocPara ) { + DocPara element = (DocPara)current; + if ( isPageNumberContent( element.getText() ) ) { + res = element; + } + } else if ( current instanceof DocPhrase ) { + DocPhrase element = (DocPhrase)current; + if ( isPageNumberContent( element.getText() ) ) { + res = element; + } + } + } + return res; + } + +} diff --git a/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/ParentElement.java b/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/ParentElement.java index 2966406..461164f 100644 --- a/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/ParentElement.java +++ b/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/ParentElement.java @@ -4,6 +4,6 @@ public interface ParentElement { - public void add( Element element ) throws Exception; + public void add( Element element ); } diff --git a/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/PdfHelper.java b/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/PdfHelper.java index 718233b..b12dcc6 100644 --- a/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/PdfHelper.java +++ b/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/PdfHelper.java @@ -75,7 +75,7 @@ public void onEndPage(PdfWriter writer, Document document) { DocElement current = itElements.next(); if ( current instanceof DocPara ) { DocPara para = (DocPara) current; - String text = OpenPpfDocHandler.createText( docHelper.getParams(), para.getText() ); + String text = OpenPpfDocHandler.createText( docHelper.getParams(), para.getText() ).replace( PageNumberHelper.PAGE_COUNT , "" ); float textSize = baseFont.getWidthPoint(text, footerTextSize); float textBase = document.bottom() - totalOffset; int rowOffset = 10; @@ -90,7 +90,6 @@ public void onEndPage(PdfWriter writer, Document document) { cb.setTextMatrix(document.right() - textSize - adjust, textBase); cb.showText(text); } - totalOffset+= rowOffset; } else { throw new ConfigRuntimeException( "Element not allowed in footer (accepted only DocPara) : "+current ); @@ -110,6 +109,7 @@ public void onCloseDocument(PdfWriter writer, Document document) { totalPages.setTextMatrix(0, 0); totalPages.showText(String.valueOf( writer.getPageNumber() - 1) ); totalPages.endText(); + totalPages.sanityCheck(); } public void setPageNumberAlignment(int pageNumberAlignment) { diff --git a/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/PhraseParent.java b/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/PhraseParent.java index c181f79..4c5e45f 100644 --- a/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/PhraseParent.java +++ b/src/main/java/org/fugerit/java/doc/mod/openpdf/helpers/PhraseParent.java @@ -14,7 +14,7 @@ public PhraseParent( Phrase phrase ) { /* (non-Javadoc) * @see org.fugerit.java.doc.mod.itext.ParentElement#add(com.lowagie.text.Element) */ - public void add(Element element) throws Exception { + public void add(Element element) { this.phrase.add( element ); } diff --git a/src/test/java/test/org/fugerit/java/doc/mod/itext/poc/TestDefaultDoc.java b/src/test/java/test/org/fugerit/java/doc/mod/itext/poc/TestDefaultDoc.java index 7e62bb9..1d4077f 100644 --- a/src/test/java/test/org/fugerit/java/doc/mod/itext/poc/TestDefaultDoc.java +++ b/src/test/java/test/org/fugerit/java/doc/mod/itext/poc/TestDefaultDoc.java @@ -28,6 +28,10 @@ public static void init() { private static final String DEFAULT_DOC_ALT = "default_doc_alt"; + private static final String DEFAULT_DOC_ALT1 = "default_doc_alt1"; + + private static final String DEFAULT_DOC_ALT2 = "default_doc_alt2"; + @Test public void testOpenFailPDF() { Assert.assertThrows( AssertionError.class , () -> this.testDocWorker( "default_doc_fail1" , PdfTypeHandler.HANDLER ) ); @@ -75,4 +79,41 @@ public void testOpenAltRTF() { Assert.assertTrue(ok); } + + @Test + public void testOpenAlt1PDF() { + boolean ok = this.testDocWorker( DEFAULT_DOC_ALT1 , PdfTypeHandler.HANDLER ); + Assert.assertTrue(ok); + } + + @Test + public void testOpenAlt1HTML() { + boolean ok = this.testDocWorker( DEFAULT_DOC_ALT1 , HtmlTypeHandler.HANDLER ); + Assert.assertTrue(ok); + } + + @Test + public void testOpenAlt1RTF() { + boolean ok = this.testDocWorker( DEFAULT_DOC_ALT1 , RtfTypeHandler.HANDLER ); + Assert.assertTrue(ok); + } + + @Test + public void testOpenAlt2PDF() { + boolean ok = this.testDocWorker( DEFAULT_DOC_ALT2 , PdfTypeHandler.HANDLER ); + Assert.assertTrue(ok); + } + + @Test + public void testOpenAlt2HTML() { + boolean ok = this.testDocWorker( DEFAULT_DOC_ALT2 , HtmlTypeHandler.HANDLER ); + Assert.assertTrue(ok); + } + + @Test + public void testOpenAlt2RTF() { + boolean ok = this.testDocWorker( DEFAULT_DOC_ALT2 , RtfTypeHandler.HANDLER ); + Assert.assertTrue(ok); + } + } diff --git a/src/test/java/test/org/fugerit/java/doc/mod/itext/poc/PocIndex.java b/src/test/java/test/org/fugerit/java/doc/mod/itext/poc/TestPocIndex.java similarity index 99% rename from src/test/java/test/org/fugerit/java/doc/mod/itext/poc/PocIndex.java rename to src/test/java/test/org/fugerit/java/doc/mod/itext/poc/TestPocIndex.java index f88800f..4762536 100644 --- a/src/test/java/test/org/fugerit/java/doc/mod/itext/poc/PocIndex.java +++ b/src/test/java/test/org/fugerit/java/doc/mod/itext/poc/TestPocIndex.java @@ -19,7 +19,7 @@ import com.lowagie.text.pdf.PdfOutline; import com.lowagie.text.pdf.PdfWriter; -public class PocIndex { +public class TestPocIndex { private static final String VERSION = "002"; diff --git a/src/test/resources/xml/default_doc.xml b/src/test/resources/xml/default_doc.xml index c60ac37..f5a3dbb 100644 --- a/src/test/resources/xml/default_doc.xml +++ b/src/test/resources/xml/default_doc.xml @@ -17,11 +17,11 @@ true /css/test.css - header test + ${currentPage} / ${pageCount} test - ${r"${currentPage}"} / ${r"${pageCount}"} + ${currentPage} / ${pageCount} test diff --git a/src/test/resources/xml/default_doc_alt.xml b/src/test/resources/xml/default_doc_alt.xml index 1908770..b051ea1 100644 --- a/src/test/resources/xml/default_doc_alt.xml +++ b/src/test/resources/xml/default_doc_alt.xml @@ -12,14 +12,15 @@ Basic example fj doc venus sample source xml fugerit79 + Fugerit Venus OpenPDF DocTypeHandler en horizontal
- header test + ${currentPage} / ${pageCount}
- ${r"${currentPage}"} / ${r"${pageCount}"} + ${currentPage} of ${pageCount}
@@ -54,8 +55,14 @@ + + + + test page 3 + - + + \ No newline at end of file diff --git a/src/test/resources/xml/default_doc_alt1.xml b/src/test/resources/xml/default_doc_alt1.xml new file mode 100644 index 0000000..d1e4740 --- /dev/null +++ b/src/test/resources/xml/default_doc_alt1.xml @@ -0,0 +1,50 @@ + + + + + + 10;10;10;30 + excel-table=print + + Basic example + fj doc venus sample source xml + fugerit79 + en + + true + /css/test.css + + + Test times roman + Courier + Symbol + Symbol + Test default font + + + Name + Surname + Title + + + + + + + + + + + + + + + + +
+ + +
\ No newline at end of file diff --git a/src/test/resources/xml/default_doc_alt2.xml b/src/test/resources/xml/default_doc_alt2.xml new file mode 100644 index 0000000..c326f9b --- /dev/null +++ b/src/test/resources/xml/default_doc_alt2.xml @@ -0,0 +1,56 @@ + + + + + + 10;10;10;30 + excel-table=print + + Basic example + fj doc venus sample source xml + fugerit79 + en + + true + /css/test.css +
+ header +
+
+ footer +
+
+ + Test times roman + Courier + Symbol + Symbol + Test default font + + + Name + Surname + Title + + + + + + + + + + + + + + + + +
+ + +
\ No newline at end of file