ENI (5) ENI Expedient for Sedipualba: Resolutions in ENI format
1. Introduction
In the previous post, the resolutions in ENI format have been achieved.
Let's build the "Expedient" in ENI format
2. SedipualbaDecretsUtilsPaso2.class
package openadmin.sedipualba.decrets; import java.io.File; import java.io.FileWriter; import java.net.URL; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Properties; import org.apache.commons.io.FilenameUtils; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.json.JSONObject; import eni.exp.TipoExpediente; import eni.exp.TipoIndiceContenido; import jakarta.xml.bind.JAXBContext; import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.Marshaller; import jakarta.xml.bind.Unmarshaller; import openadmin.utils.decrets.PDFUtils; import ximodante.basic.utils.basic.ExecutionTypeEnum; import ximodante.basic.utils.basic.FileUtilsEdu; import ximodante.basic.utils.basic.PropertyUtilsEdu; import ximodante.basic.utils.command.CmdUtils; public class SedipualbaDecretsUtilsPaso2 { /** * Replaces the String "$(RESOURCES)/" by the route to the resources file * @param str * @param isExecutedFromJar * @return */ //public static String replaceResourcesFilename(String str, boolean isExecutedFromJar) { public static String replaceResourcesFilename(String str, ExecutionTypeEnum execType) { String f1="locator.txt"; String fName=""; if (execType==ExecutionTypeEnum.JAR) { try { fName=FileUtilsEdu.getJarContainingFolder() + File.separator ; } catch (Exception e) { e.printStackTrace(); } } else { URL url = ClassLoader.getSystemResource(f1); fName=url.getFile().replace(f1,""); } String result= str.replace("$(RESOURCES)/", fName); System.out.println(result); return result; } //XML Marshaller for TipoExpediente private static Marshaller getENIExpMarshaller() throws JAXBException { JAXBContext context = JAXBContext.newInstance(TipoExpediente.class); Marshaller mar= context.createMarshaller(); mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); return mar; } private static Unmarshaller getENIExpUnmarshaller() throws JAXBException { JAXBContext context = JAXBContext.newInstance(TipoExpediente.class); Unmarshaller unmar= context.createUnmarshaller(); //unmar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); return unmar; } //Write a TipoDocumento object to a xml file public static void marshallENIExp(TipoExpediente eniExp, String fileName) throws JAXBException { Marshaller mar=getENIExpMarshaller(); mar.marshal(eniExp, new File(fileName)); } //Write a TipoDocumento from a xml file to object public static TipoExpediente unmarshallENIExp(String fileName) throws JAXBException { Unmarshaller unmar=getENIExpUnmarshaller(); TipoExpediente eniExp=(TipoExpediente) unmar.unmarshal(new File(fileName)); return eniExp; } //XML Marshaller for TipoExpediente private static Marshaller getENIExpIndContMarshaller() throws JAXBException { JAXBContext context = JAXBContext.newInstance(TipoIndiceContenido.class); Marshaller mar= context.createMarshaller(); mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); return mar; } //Write a TipoDocumento object to a xml file private static void marshallENIExpIndCont(TipoIndiceContenido eniExp, String fileName) throws JAXBException { Marshaller mar=getENIExpIndContMarshaller(); mar.marshal(eniExp, new File(fileName)); } public static void showMessage(String message) { showMessage(message, false); } public static void showMessage(String message, boolean isError) { //myUI.access(() -> v1.add(new Span(message))); if (! isError) System.out.println("CessarLlibreDecrets " + ".showMessage: "+message); else System.out.println("ERROR:" + "CessarLlibreDecrets " + ".showMessage: "+message); } public static void execute(String[] args, ExecutionTypeEnum execType) throws Exception{ int year=Integer.parseInt(args[1].trim()); String organoDIR3=args[2].trim(); String outputFolder=args[3].trim()+year; String decretNumformat=args[5].trim(); String resolutionInfoFile=outputFolder+"/INFO"+year+".txt"; String errors=""; String fileError=outputFolder+"/0ERRORS.txt"; //1. Documents PDDocument docIndexPdfWithLinks = null; PDDocument docIndexPdfNoLinks = null; Object[] docAndPageWithLinks=null; Object[] docAndPageNoLinks=null; //4. Properties Properties appProps=PropertyUtilsEdu.getProperties(execType, "app_encrypt"); //5. Certificate's path. Certificate's parameters String certParams=appProps.getProperty("cert.params"); certParams=replaceResourcesFilename(certParams, execType); System.out.println(certParams); //6. Autofirma's path //String autofirmaURL=appProps.getProperty("autofirma.url"); SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy"); SimpleDateFormat dayFormat = new SimpleDateFormat("dd"); //-------------------------------------------------------- //Capçalera de l'Index del llibre de resolucions //-------------------------------------------------------- List<String> lines = Files.readAllLines(Paths.get(resolutionInfoFile), Charset.defaultCharset()); int resCount=lines.size(); JSONObject json=new JSONObject(lines.get(0)); int resIni=json.getInt("numDecreto"); Date date =ENIDocSedipualba.getFecha(json.get("fechaDecreto").toString()).toGregorianCalendar().getTime(); int diaIni=Integer.parseInt(dayFormat.format(date)); json=new JSONObject(lines.get(resCount-1)); int resFi=json.getInt("numDecreto"); date =ENIDocSedipualba.getFecha(json.get("fechaDecreto").toString()).toGregorianCalendar().getTime(); int diaFi=Integer.parseInt(dayFormat.format(date)); docAndPageWithLinks= ENIExpSedipualba.getFirstIndexPage(execType, year, resCount, diaIni, diaFi, resIni, resFi); docAndPageNoLinks= ENIExpSedipualba.getFirstIndexPage(execType, year, resCount, diaIni, diaFi, resIni, resFi); //-------------------------------------------------------- //FI Capçalera de l'Index del llibre de resolucions //-------------------------------------------------------- List<String[]>contentWithLinks=new ArrayList<String[]>(); List<String[]>contentNoLinks=new ArrayList<String[]>(); List<String[]>links =new ArrayList<String[]>(); List<String[]>noLinks =new ArrayList<String[]>(); String fileNameIndexWithLinks=outputFolder + java.io.File.separator + "Index."+year+".links.pdf" ; String fileNameIndexNoLinks=outputFolder + java.io.File.separator + "Index."+year+".nolinks.pdf" ; int lastDecret=0; int i=0; for (String line: lines) { System.out.println(i++); json=new JSONObject(line); int numDecret=json.getInt("numDecreto"); //if (line.getNumero()<0) continue; //if (i >10) break; showMessage("Decret "+ numDecret); if ((lastDecret+1)!=numDecret) errors+="\n Error en comptador de decrets: Hem passat de " + lastDecret + " a " + numDecret; lastDecret=numDecret; date =ENIDocSedipualba.getFecha(json.get("fechaDecreto").toString()).toGregorianCalendar().getTime(); String fecha=dateFormat.format(date); System.out.println("6.Fila de la taula de decrets"); String[] lineContentWithLinks= { String.format("%1$5s", numDecret), "Vincle","Vincle","Vincle", //PDFUtils.arregla(decret.getNombre()), PDFUtils.arregla(json.getString("descripcion")), fecha }; contentWithLinks.add(lineContentWithLinks); String fileName=outputFolder+"/Decret_"+year+"_"+String.format(decretNumformat, numDecret)+".orig.pdf"; String fileNameCSV=outputFolder+"/Decret_"+year+"_"+String.format(decretNumformat, numDecret)+".aut.pdf"; int pkDoc=json.getInt("pkdocumento"); String fileNameENI=outputFolder+"/ES_" + organoDIR3 + "_"+ year + "_DOC_RESOLUCIO_" + String.format(decretNumformat, numDecret) + "_"+ pkDoc+".xml"; String[] lineLink= {null, FilenameUtils.getName(fileName), FilenameUtils.getName(fileNameCSV), FilenameUtils.getName(fileNameENI), //null, null, null }; links.add(lineLink); String[] lineContentNoLinks= { String.format("%1$5s", numDecret), PDFUtils.arregla(json.getString("descripcion")), fecha }; contentNoLinks.add(lineContentNoLinks); String[] lineNoLink= {null, null, //null, null }; noLinks.add(lineNoLink); } System.out.println("7. taula de decrets"); docIndexPdfWithLinks=ENIExpSedipualba.saveIndexDecretsWithLinks(execType, (PDDocument)docAndPageWithLinks[0],(PDPage)docAndPageWithLinks[1],(float)docAndPageWithLinks[2], contentWithLinks,links,fileNameIndexWithLinks ); //2. ENI Expedient TipoExpediente expENI=new TipoExpediente(); expENI.setId(ENIExpSedipualba.getIdentificadorExp(year)); //1. Posem totes les metadades expENI.setMetadatosExp(ENIExpSedipualba.getMetadatosExp(year)); //2. Fiquem l'índex buit expENI.setIndice(ENIExpSedipualba.getIndiceExp(year)); docIndexPdfNoLinks=ENIExpSedipualba.saveIndexDecretsNoLinks(execType, (PDDocument)docAndPageNoLinks[0],(PDPage)docAndPageNoLinks[1],(float)docAndPageNoLinks[2], contentNoLinks,noLinks,fileNameIndexNoLinks ); expENI=ENIExpSedipualba.addPDFDocIndx(expENI, docIndexPdfNoLinks, year); //Firma del contenido String expContenidoFileName=outputFolder+"/contenido.xml"; String expContenidoFirmaFileNameXades=outputFolder+"/contenido_firma.edu.XAdES-Detached.xsig"; //xmlMapper.ObjectToFile(expENI.getIndice().getIndiceContenido(),expContenidoFileName ); marshallENIExpIndCont(expENI.getIndice().getIndiceContenido(),expContenidoFileName); String expEniJaxbFName=outputFolder+"/0"+ENIExpSedipualba.getIdentificadorExp(year)+".ENI.NOSIGNED.xml"; marshallENIExp(expENI,expEniJaxbFName); String AFirmaCmd= "/usr/bin/AutoFirma sign " + " -i " + expContenidoFileName + //" -o " + expContenidoFirmaFileNameCades + "-o " + expContenidoFirmaFileNameXades + " -format xades " + "-store" + " pkcs11:/usr/lib/libaetpkss.so " + //Tarjeta criptografica "-alias "+ " EPN1" + "-config" + "format=XAdES Detached"; CmdUtils.executeCommand(AFirmaCmd); byte[] firmaContent=FileUtilsEdu.readFileAsByteArray(expContenidoFirmaFileNameXades); expENI=ENIExpSedipualba.firmarContenido(expENI, firmaContent, year, expContenidoFirmaFileNameXades); String expEniJaxbFNameSigned=outputFolder+"/0"+ENIExpSedipualba.getIdentificadorExp(year)+".ENI.xml"; marshallENIExp(expENI,expEniJaxbFNameSigned); FileWriter writerObj = new FileWriter(fileError, false); writerObj.write(errors); writerObj.close(); } public static void main(String[] args) { //OJO: Hen de tindre creat l'expedient "1355414W" que arreplega els decrets sense expedient try { // descripcio any organoDIR3 carpeta a guardar "fitxer excel a llegir format num decret" "expedient" SedipualbaDecretsUtilsPaso2.execute(new String[]{"LLIBRE_DECRETS","2022","L01462384","/home/eduard/SEGRA","SEGRAAdministrador.xlsx","%05d", "1355414W" }, ExecutionTypeEnum.NO_JAR); } catch (Exception e) { // e.printStackTrace(); } } }
3. ENIExpSedipualba utility class
This class is for managing "expedients"
package openadmin.sedipualba.decrets; import java.awt.Color; import java.awt.Dimension; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Base64; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; import java.util.Map; import java.util.Properties; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; import org.apache.commons.lang3.StringUtils; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDType0Font; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; import eni.exp.EnumeracionEstados; import eni.exp.Firmas; import eni.exp.SignatureType; import eni.exp.TipoContenido; import eni.exp.TipoDocumentoIndizado; import eni.exp.TipoExpediente; import eni.exp.TipoFirmasElectronicas; import eni.exp.TipoFirmasElectronicas.ContenidoFirma; import eni.exp.TipoFirmasElectronicas.ContenidoFirma.FirmaConCertificado; import eni.exp.TipoIndice; import eni.exp.TipoIndiceContenido; import eni.exp.TipoMetadatos; import eni.exp.TipoMetadatos.Estado; import openadmin.model.gexflow.original.document.ExpDocumento; import openadmin.model.gexflow.original.document.decreto.ExpLineaLibroDecreto; import openadmin.utils.decrets.PDFTables; import openadmin.utils.decrets.PDFUtils; import openadmin.utils.decrets.PDF_AUtils; import openadmin.xsig.classes.AFirma; import openadmin.xsig.classes.Object_EduContent_Type; import openadmin.xsig.classes.SignatureEduType; import ximodante.basic.utils.basic.ExecutionTypeEnum; import ximodante.basic.utils.basic.FileUtilsEdu; import ximodante.basic.utils.basic.HashUtils; import ximodante.basic.utils.basic.PropertyUtilsEdu; import ximodante.basic.utils.cmis.CMISEduImp; import ximodante.basic.utils.cmis.ICMISEdu; public class ENIExpSedipualba { public static String Titol = "DILIGÈNCIA I ÍNDEX ELECTR�'NIC DE L'AGRUPACI�" DOCUMENTAL COMPRENSIVA DEL LLIBRE DE RESOLUCIONS DEL ${any}" + " (ENLLAÇ A L'EXPEDIENT ENI)"; public static String diligencia01= "Per fer constar que, en la data de la signatura electrònica d'este document, a través d’esta " + "Diligència que l'encapçala, es formalitza i es tanca l'agrupació documental comprensiva del Llibre de " + "Resolucions, corresponents a les emeses per l'Alcaldia i Regidories Delegades durant l'any ${any}. Açò " + "es duu a terme en compliment de l'obligació d'esta Secretaria Municipal de transcriure al Llibre de " + "Resolucions, siga quin sigui el seu suport, les dictades per la presidència, pels membres de la " + "corporació que resolguen per delegació i les de qualsevol altre òrgan amb competències " + "resolutives, tal com preveu l'article 3 del Reial Decret 128/2018, de 16 de març, pel qual es regula el " + "règim jurídic dels funcionaris d'administració local amb habilitació de caràcter nacional , amb el " + "contingut expressat en l'índex electrònic que també s'hi incorpora.\n" + "El Llibre de Resolucions de ${any}, queda integrat, conforme es detalla a l'índex electrònic " + "a continuació, per ${resCount} resolucions en l'original electrònic, que es corresponen amb les dictades " + "del dia ${diaIni} de gener al ${diaFi} de desembre de 2021 , numerades correlativament de la número ${resIni} a la ${resFi}, " + "i que compleixen els requisits de l'art. 26 de la Llei 39/2015, d'1 d'octubre, del procediment administratiu comú " + "de les administracions públiques i la resta de normativa aplicable.\n"; public static String diligencia02= "Índex electrònic del Llibre de Resolucions de ${any}:\n"; public static String diligencia03= "Este Índex electrònic de l'agrupació documental del Llibre de Resolucions de ${any} conté la identificació " + "substancial de tots els documents electrònics (resolucions electròniques) que el componen, " + "degudament ordenat per a reflectir-ne la seva disposició, i també altres dades, a fi de preservar-ne la " + "integritat i permetre'n la recuperació, en els termes de l'article 70.3 de l'esmentada Llei 39/2015, d'1 " + "d'octubre de 2015 en format XML conforme a l'annex II de la Norma Tècnica d'Interoperabilitat de Document " + "Electrònic i de l'annex II de la Norma Tècnica dInteroperabilitat dExpedient Electrònic.\n" + "L'Índex comprèn i reflecteix, de manera individualitzada, per cada una de les resolucions emeses durant " + "l'exercici ${any} els camps per columnes següents:\n" + "Núm. de resolució: es correspon amb el número de Resolució.\n" + "Original: enllaç al document original en format pdf.\n" + "Autèntic: enllaç al document en format pdf, amb el codi segur de verificació (CSV) i detall de les firmes practicades.\n" + "ENI: Enllaç al document en format ENI.\n" + "Nom o designació de la Resolució: esta descripció incorpora dades que identifiquen el departament emissor " + "de la resolució i l'expedient en què s'ha generat.\n" + "Descripció: breu resum del contingut de la resolució que es correspon amb la que hauria de ser la capçalera " + "de la resolució\n" + "Data: es correspon amb el dia i l'hora en què l'últim signant, regidoria o secretari, va firmar i, per tant, " + "es va incorporar al Llibre.\n" + "Enllaços al format Document.xml\n\n" + "Este document es signa electrònicament incorporant-hi tots els camps transcrits i les metadades " + "corresponents per garantir l'autenticitat i la integritat del contingut d'esta Diligència, de l'índex, i " + "per extensió, dels documents electrònics (resolucions) formen el Llibre de Resolucions de ${any} així " + "com la seva estructura. La signatura correspon, en virtut del RD 128/2018 en connexió amb l'art. 92bis de la " + "Llei 7/1985, de 2 dabril, Reguladora de les Bases de Règim Local, amb el secretari " + "municipal, ja que es refereix a una atribució reservada en exclusiva a este lloc de treball."; public static String DIR3ORGANO = "L01462384"; public static XMLGregorianCalendar getDate2XMLGregorian(Date date) throws DatatypeConfigurationException { if (date==null) return null; GregorianCalendar cal = new GregorianCalendar(); cal.setTime(date); XMLGregorianCalendar xmlGregCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal); return xmlGregCal; } /********************************************************************** * * 1. METADATOS DEL EXPEDIENTE * ***********************************************************************/ public static String getClasificacion(int any) { return DIR3ORGANO + "_PRO_" + "LLIBRE_RESOLUCIONS_" + any; } public static String getIdentificadorExp(int any) { return "ES_" + DIR3ORGANO + "_" + any + "_EXP_" + "LLIBRE_RESOLUCIONS"; } public static List<String> getOrgano() { List<String> organos = new ArrayList<String>(); organos.add(DIR3ORGANO); return organos; } public static Estado getEstado() { Estado estado = new Estado(); estado.setValue(EnumeracionEstados.E_02);// E_02=Cerrado return estado; } public static XMLGregorianCalendar getFechaAperturaExpediente(int any) throws ParseException, DatatypeConfigurationException { DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Date date = format.parse("" + any + "-01-01 00:00:00"); GregorianCalendar cal = new GregorianCalendar(); cal.setTime(date); XMLGregorianCalendar xmlGregCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal); return xmlGregCal; } public static TipoMetadatos getMetadatosExp(int any) throws ParseException, DatatypeConfigurationException { TipoMetadatos metaExpENI = new TipoMetadatos(); metaExpENI.setVersionNTI("http://administracionelectronica.gob.es/ENI/XSD/v1.0/expediente-e"); metaExpENI.setIdentificador(getIdentificadorExp(any)); metaExpENI.setOrgano(getOrgano()); metaExpENI.setFechaAperturaExpediente(getFechaAperturaExpediente(any)); metaExpENI.setClasificacion(getClasificacion(any)); metaExpENI.setEstado(getEstado()); metaExpENI.setInteresado(getOrgano()); metaExpENI.setId(DIR3ORGANO + "_" + any + "_METADADES_LLIBRE_RESOLUCIONS"); return metaExpENI; } /********************************************** * METADADES ADDICIONALS **********************************************/ public static void getMetadatosAddicExp(int any) { //TipoMetadadosAdicionales } /********************************************** * INDICE **********************************************/ public static String getIdentificadorDocIndex(int any) { return "ES_" + DIR3ORGANO + "_" + any + "_INDEX_LLIBRE_RESOLUCIONS"; } public static String getIdentificadorDocIndexContenido(int any) { return "ES_" + DIR3ORGANO + "_" + any + "_INDEX_CONTENIDO_LLIBRE_RESOLUCIONS"; } public static TipoIndice getIndiceExp(int any) throws DatatypeConfigurationException { TipoIndice indiceENI = new TipoIndice(); TipoIndiceContenido indiceContenidoENI = new TipoIndiceContenido(); indiceContenidoENI.setFechaIndiceElectronico(getDate2XMLGregorian(new Date(System.currentTimeMillis()))); //indiceContenidoENI.setId(any + "_LLIBRE_RESOLUCIONS"); indiceContenidoENI.setId(getIdentificadorDocIndexContenido(any)); indiceENI.setIndiceContenido(indiceContenidoENI); indiceENI.setId(getIdentificadorDocIndex(any)); return indiceENI; } /** * Afegeix la referencia a un document (TipoDocumentoIndizado) a l'index de * l'expedient * * @param expENI * @param docContent * @param linea * @param any * @param formatNumDecret * @return * @throws DatatypeConfigurationException */ public static TipoExpediente addDoc2Indx(TipoExpediente expENI, byte[] docContent, ExpLineaLibroDecreto linea, int any, String formatNumDecret) throws DatatypeConfigurationException { ExpDocumento decret = linea.getExpDocumento(); TipoDocumentoIndizado docInd = new TipoDocumentoIndizado(); docInd.setId(linea.getCodigo().replace("Nº Decreto: ","Decret_")); docInd.setIdentificadorDocumento(getIdentificadorDoc(any, linea.getNumero(), formatNumDecret)); docInd.setValorHuella(HashUtils.getSH512Hash(docContent)); docInd.setFuncionResumen("http://www.w3.org/2001/04/xmlenc#sha512"); docInd.setFechaIncorporacionExpediente(ENIExpSedipualba.getDate2XMLGregorian(decret.getFechaUltimaFirma())); docInd.setOrdenDocumentoExpediente(String.format(formatNumDecret, linea.getNumero())); expENI.getIndice().getIndiceContenido().getDocumentoIndizadoOrExpedienteIndizadoOrCarpetaIndizada().add(docInd); return expENI; } /* OBSOLETE OJO !!!! Hay que firmar el contenido*/ public static TipoExpediente firmarContenido(TipoExpediente expENI, byte[] firmaContent, int any, String tipo) { FirmaConCertificado unaFrmCCert= new FirmaConCertificado(); unaFrmCCert.setFirmaBase64(Base64.getEncoder().encodeToString(firmaContent)); //unaFrmCCert.setReferenciaFirma(null); //???? //unaFrmCCert.setSignature(null); ContenidoFirma unContenido=new ContenidoFirma(); unContenido.setFirmaConCertificado(unaFrmCCert); TipoFirmasElectronicas unaFirma=new TipoFirmasElectronicas(); unaFirma.setId("Contenido_"+ any); if (tipo.toLowerCase().contains("xades")) unaFirma.setTipoFirma("TF02");//Xades internally detached if (tipo.toLowerCase().contains("cades")) unaFirma.setTipoFirma("TF05"); unaFirma.setTipoFirma("TF05"); //CADES implicid (attached) //unaFirma.setTipoFirma("TF04"); //NO PERMITIT EN EXPEDIENTS !!!! CADES explicid (NOT attached) unaFirma.setContenidoFirma(unContenido); unaFirma.setRef("#"+getIdentificadorDocIndexContenido(any)); expENI.getIndice().setFirmas(new Firmas()); expENI.getIndice().getFirmas().getFirma().add(unaFirma); return expENI; } /********************************************** * CONTENIDO **********************************************/ public static String getIdentificadorDoc(int any, long nRes, String formatNumDecret) { return "ES_" + DIR3ORGANO + "_" + any + "_DOC_RESOLUCIO_" + String.format(formatNumDecret, nRes); } /********************************************** * VISUALIZACION INDICE **********************************************/ /** * Afegeix el document index a l'expedient (TipoContenido= Visualización índice) * * @param expENI * @param docContent * @param any * @return * @throws DatatypeConfigurationException * @throws IOException */ public static TipoExpediente addPDFDocIndx(TipoExpediente expENI, PDDocument docIndexPdf, int any) throws DatatypeConfigurationException, IOException { byte[] docContent = PDFUtils.getContent(docIndexPdf); TipoContenido content = new TipoContenido(); content.setId("VISUALITZACIO_INDEX"); //content.setValorBinario(Base64.getEncoder().encode(docContent)); content.setValorBinario(new String(Base64.getEncoder().encode(docContent))); content.setNombreFormato("PDF"); expENI.setVisualizacionIndice(content); return expENI; } /********************************************** * INDICE * @throws Exception **********************************************/ /** * Create the first page of the pdf index document * @param execType * @param any * @param resCount * @param diaIni * @param diaFi * @param resIni * @param resFi * @return * @throws Exception */ public static Object[] getFirstIndexPage(ExecutionTypeEnum execType, int any, int resCount, int diaIni, int diaFi, int resIni, int resFi) throws Exception { float FONT_SIZE = 9; float TITLE_FONT_SIZE = 12;//15 //float LEADING = -1.5f * FONT_SIZE; float LEADING = 1.5f * FONT_SIZE; PDDocument doc=new PDDocument(); PDPage page = new PDPage(); doc.addPage(page); //PDFont FONT = PDType1Font.HELVETICA; //Arial // Create a new font object by loading a TrueType font into the document //PDFont FONT = PDTrueTypeFont.loadTTF(doc, "Arial.ttf"); PDFont FONT = PDType0Font.load(doc, new File(FileUtilsEdu.getRelativeResourceFile(execType, "fonts/Arial.ttf"))); PDFont FONT_BOLD = PDType0Font.load(doc, new File(FileUtilsEdu.getRelativeResourceFile(execType, "fonts/FontsFree-Net-arial-bold.ttf"))); PDPageContentStream contentStream = new PDPageContentStream(doc, page); PDRectangle mediaBox = page.getMediaBox(); float mil2Point=mediaBox.getWidth()/210; float marginY = 10*mil2Point; // 15; 80; float marginX = 25*mil2Point;//60; float width = mediaBox.getWidth() - 35*mil2Point;//2 * marginX; float startX = mediaBox.getLowerLeftX() + marginX; float startY = mediaBox.getUpperRightY() - marginY; float posY=startY; String titol=StringUtils.replace(Titol, "${any}", ""+any, 1000); String text01 = StringUtils.replace(diligencia01, "${any}", ""+any,1000); text01 = StringUtils.replace(text01, "${resCount}", ""+resCount,1000); text01 = StringUtils.replace(text01, "${diaIni}", ""+diaIni,1000); text01 = StringUtils.replace(text01, "${diaFi}", ""+diaFi,1000); text01 = StringUtils.replace(text01, "${resIni}", ""+resIni,1000); text01 = StringUtils.replace(text01, "${resFi}", ""+resFi,1000); String text02 = StringUtils.replace(diligencia02, "${any}", ""+any,1000); text02 = StringUtils.replace(text02, "${resCount}", ""+resCount,1000); text02 = StringUtils.replace(text02, "${diaIni}", ""+diaIni,1000); text02 = StringUtils.replace(text02, "${diaFi}", ""+diaFi,1000); text02 = StringUtils.replace(text02, "${resIni}", ""+resIni,1000); text02 = StringUtils.replace(text02, "${resFi}", ""+resFi,1000); String text03 = StringUtils.replace(diligencia03, "${any}", ""+any,1000); text03 = StringUtils.replace(text03, "${resCount}", ""+resCount,1000); text03 = StringUtils.replace(text03, "${diaIni}", ""+diaIni,1000); text03 = StringUtils.replace(text03, "${diaFi}", ""+diaFi,1000); text03 = StringUtils.replace(text03, "${resIni}", ""+resIni,1000); text03 = StringUtils.replace(text03, "${resFi}", ""+resFi,1000); String imagePath=FileUtilsEdu.getRelativeResourceFile(execType, "images/capsalera1.png"); PDImageXObject capsalera = PDImageXObject.createFromFile(imagePath,doc); contentStream.drawImage(capsalera, marginX, startY-30*mil2Point,width, 30*mil2Point); //35 contentStream.close(); startY=(float) (startY-30*mil2Point-1*TITLE_FONT_SIZE); contentStream = new PDPageContentStream(doc, page,AppendMode.APPEND,false); contentStream.beginText(); PDFUtils.addParagraph(contentStream, width, startX, startY, titol, true, TITLE_FONT_SIZE, FONT_BOLD, LEADING, Color.BLACK, posY); PDFUtils.addParagraph(contentStream, width, 0, -TITLE_FONT_SIZE, text01, true, FONT_SIZE, FONT, LEADING, Color.BLACK, posY); PDFUtils.addParagraph(contentStream, width, 0, -TITLE_FONT_SIZE, text02, true, FONT_SIZE, FONT_BOLD, LEADING, Color.BLACK, posY); float posYNow= PDFUtils.addParagraph(contentStream, width, 0, -TITLE_FONT_SIZE, text03, true, FONT_SIZE, FONT, LEADING, Color.BLACK, posY); contentStream.endText(); contentStream.close(); Object[] obs= {doc, page, posYNow}; return obs; } /** * Add resolutions to the pdf index documents * @param execType * @param doc * @param page * @param posYNow * @param lContent * @param lLinks * @param fileName * @throws Exception */ public static PDDocument saveIndexDecretsWithLinks(ExecutionTypeEnum execType, PDDocument doc, PDPage page, float posYNow, List<String[]>lContent, List<String[]> lLinks, String fileName) throws Exception { String[] titles= {"Núm Reso- lució","Original","Autèntic","ENI","Descripció","Data resolució"}; boolean[] titleRotates= {false,true,true,true,false,false}; boolean[] textRotates= {false,true,true,true,false,false}; boolean[] textLinks=textRotates; float[] proportions={6.8f,2.75f,2.75f,2.75f,60f,9.5f}; //float margin = 50; float leftMargin = 25/0.375f; // starting y position is whole page height subtracted by top and bottom margin //float yStartNewPage = page.getMediaBox().getHeight() - (2 * margin); //float yStart = page.getMediaBox().getHeight() - (500); float yStart =page.getMediaBox().getHeight() - posYNow -15/0.375f; float yStartNewPage = page.getMediaBox().getHeight() - (40 /0.375f); // we want table across whole page width (subtracted by left and right margin ofcourse) float tableWidth = page.getMediaBox().getWidth() - (25+15)/0.375f ; boolean drawContent = true; boolean drawLines = true; //float yStart = yStartNewPage; //float bottomMargin = 70; float bottomMargin = 20/0.375f; // y position is your coordinate of top left corner of the table float yPosition = 550; float rowHeight=20; PDRectangle mediaBox = page.getMediaBox(); float pageWidth = mediaBox.getWidth(); float pageHeight = mediaBox.getHeight(); /* System.out.println("pageWidth="+pageWidth); System.out.println("pageHeight="+pageHeight); System.out.println("leftMargin="+leftMargin); // System.out.println("rightMargin="+rightMargin); System.out.println("bottomMargin="+bottomMargin); System.out.println("yStartNewPage="+yStartNewPage); System.out.println("tableWidth="+tableWidth); */ //createTable(yStart, yStartNewPage, bottomMargin, tableWidth, margin, rowHeight, doc, page, drawLines, drawContent, content); Map<Integer,List<Object[]>> possitions= PDFTables.createTable01(yStart, yStartNewPage, bottomMargin, tableWidth, leftMargin, rowHeight, doc, page, drawLines, drawContent, proportions, titles, titleRotates, lContent, textRotates, textLinks, lLinks, execType); PDFTables.createLinks(doc,possitions); PDFTables.addPageNumbers(execType, doc, leftMargin, 15/0.375f, 15/0.375f,bottomMargin); //doc.save("/home/eduard/kk/provaTaula.pdf"); //Fem que siga PDF v1.7 (PDF/A) segons email Jesús Romero doc=PDF_AUtils.setVersionPDFA(doc, fileName, execType); doc.save(fileName); return doc; } public static PDDocument saveIndexDecretsNoLinks(ExecutionTypeEnum execType, PDDocument doc, PDPage page, float posYNow, List<String[]>lContent, List<String[]> lLinks, String fileName) throws Exception { String[] titles= {"Núm Reso- lució","Descripció","Data última firma"}; boolean[] titleRotates= {false,false,false}; boolean[] textRotates= {false,false,false}; boolean[] textLinks=textRotates; float[] proportions={6.8f,65f,9.5f}; //float margin = 50; float leftMargin = 25/0.375f; // starting y position is whole page height subtracted by top and bottom margin //float yStartNewPage = page.getMediaBox().getHeight() - (2 * margin); //float yStart = page.getMediaBox().getHeight() - (500); float yStart =page.getMediaBox().getHeight() - posYNow -15/0.375f; float yStartNewPage = page.getMediaBox().getHeight() - (40 /0.375f); // we want table across whole page width (subtracted by left and right margin ofcourse) float tableWidth = page.getMediaBox().getWidth() - (25+15)/0.375f ; boolean drawContent = true; boolean drawLines = true; //float yStart = yStartNewPage; //float bottomMargin = 70; float bottomMargin = 20/0.375f; // y position is your coordinate of top left corner of the table float yPosition = 550; float rowHeight=20; PDRectangle mediaBox = page.getMediaBox(); float pageWidth = mediaBox.getWidth(); float pageHeight = mediaBox.getHeight(); /* System.out.println("pageWidth="+pageWidth); System.out.println("pageHeight="+pageHeight); System.out.println("leftMargin="+leftMargin); // System.out.println("rightMargin="+rightMargin); System.out.println("bottomMargin="+bottomMargin); System.out.println("yStartNewPage="+yStartNewPage); System.out.println("tableWidth="+tableWidth); */ //createTable(yStart, yStartNewPage, bottomMargin, tableWidth, margin, rowHeight, doc, page, drawLines, drawContent, content); Map<Integer,List<Object[]>> possitions= PDFTables.createTable01(yStart, yStartNewPage, bottomMargin, tableWidth, leftMargin, rowHeight, doc, page, drawLines, drawContent, proportions, titles, titleRotates, lContent, textRotates, textLinks, lLinks, execType); //PDFTables.createLinks(doc,possitions); PDFTables.addPageNumbers(execType, doc, leftMargin, 15/0.375f, 15/0.375f,bottomMargin); //doc.save("/home/eduard/kk/provaTaula.pdf"); //Fem que siga PDF v1.7 (PDF/A) segons email Jesús Romero doc=PDF_AUtils.setVersionPDFA(doc, fileName, execType); doc.save(fileName); return doc; } public static void main(String[] args) { } }
4. PDFUtils Utility class
public class PDFUtils { /** * Convert html to pdf * * @param inputHtmlPath * @param outputPdfPath * @throws IOException */ public static final void html2Pdf(String inputHtmlPath, String outputPdfPath) throws IOException { // Read the html document Document doc = Jsoup.parse(inputHtmlPath, "UTF-8"); doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml); // Write the pdf document OutputStream os = new FileOutputStream(outputPdfPath); PdfRendererBuilder builder = new PdfRendererBuilder(); builder.withUri(outputPdfPath); builder.toStream(os); builder.withW3cDocument(new W3CDom().fromJsoup(doc), "/"); builder.run(); os.close(); } public static final void createPdfWithLink(String outputPdfPath) throws IOException { PDDocument doc = new PDDocument (); PDPage page = new PDPage (new PDRectangle (250, 150)); doc.addPage (page); PDPageContentStream contentStream = new PDPageContentStream (doc, page); PDAnnotationLink txtLink = new PDAnnotationLink (); PDAnnotationLink txtLink1 = new PDAnnotationLink (); // border style PDBorderStyleDictionary linkBorder = new PDBorderStyleDictionary (); linkBorder.setStyle (PDBorderStyleDictionary.STYLE_UNDERLINE); linkBorder.setWidth (10); txtLink.setBorderStyle (linkBorder); txtLink1.setBorderStyle (linkBorder); // Border color final Color color = Color.GREEN; final float [] components = new float [] { color.getRed () / 255f, color.getGreen () / 255f, color.getBlue () / 255f }; txtLink.setColor (new PDColor (components, PDDeviceRGB.INSTANCE)); txtLink1.setColor (new PDColor (components, PDDeviceRGB.INSTANCE)); // Destination URI final PDActionURI action = new PDActionURI (); //action.setURI ("https://www.helger.com"); //OK //action.setURI ("pdf.pdf"); //OK //action.setURI ("/home/edu/Descargas/Diptico de VALIDe.pdf"); //MAL //action.setURI ("file:///home/edu/Documentos/Transporte%20Musical.pdf"); //OK //action.setURI ("file://./Transporte%20Musical.pdf"); // MAL //action.setURI ("file://Transporte%20Musical.pdf"); // MAL //action.setURI ("file:Transporte%20Musical.pdf"); // MAL //action.setURI ("Transporte%20Musical.pdf"); // MAL action.setURI ("Transporte Musical.pdf"); // BIEN //action.setURI ("//home/edu/Descargas/Diptico de VALIDe.pdf"); //MAL //action.setURI ("file:///home/edu/Descargas/Diptico de VALIDe.pdf"); //OK txtLink.setAction (action); //Destination file //PDSimpleFileSpecification dest=new PDSimpleFileSpecification(); PDFileSpecification dest=new PDSimpleFileSpecification(); dest.setFile("/home/edu/Descargas/Diptico de VALIDe.pdf"); PDActionRemoteGoTo action1= new PDActionRemoteGoTo(); //PDActionGoTo action1= new PDActionGoTo(); action1.setOpenInNewWindow(OpenMode.NEW_WINDOW); //action1.setDestination(dest); action1.setFile(dest); txtLink1.setAction (action1); // Position final PDRectangle position = new PDRectangle (); position.setLowerLeftX (10); position.setLowerLeftY (10); position.setUpperRightX (200); position.setUpperRightY (10 + 2 + 10 + 2); txtLink.setRectangle (position); page.getAnnotations().add (txtLink); // Position final PDRectangle position1 = new PDRectangle (); position1.setLowerLeftX (10); position1.setLowerLeftY (90); position1.setUpperRightX (200); position1.setUpperRightY (90 + 2 + 10 + 2); txtLink1.setRectangle (position1); page.getAnnotations().add (txtLink1); // Main page content contentStream.beginText (); contentStream.newLineAtOffset (12, 12); contentStream.setFont (PDType1Font.COURIER_BOLD, 10); contentStream.showText ("This is linked to the outside world"); contentStream.endText (); contentStream.beginText (); contentStream.newLineAtOffset (12, 92); contentStream.setFont (PDType1Font.COURIER_BOLD, 10); contentStream.showText ("This is linked to the outside world 111111111111"); contentStream.endText (); contentStream.close(); doc.save(outputPdfPath); } /** * Write texLine ant a possition and create a link to a file in the same folder and adds an image to the top of the page. * @param doc * @param textLine * @param posX * @param posY * @param linkedPDFRelativePath * @param imageHeaderPath * @return * @throws IOException */ public static final PDDocument newTextWithLink(PDDocument doc, String textLine, int posX, int posY, String linkedPDFRelativePath, String imageHeaderPath) throws IOException { PDPage page=null; if (doc==null) doc = new PDDocument (); int lastPage= doc.getNumberOfPages()-1; if (lastPage<0 || posY<136) { page = new PDPage (PDRectangle.A4); System.out.println("HEIGHT="+page.getMediaBox().getHeight()); System.out.println("WIDTH="+page.getMediaBox().getWidth());; System.out.println("LowerLeftX="+page.getMediaBox().getLowerLeftX()); System.out.println("LowerLeftY="+page.getMediaBox().getLowerLeftY()); System.out.println("UpperRightX="+page.getMediaBox().getUpperRightX()); System.out.println("UpperRightY="+page.getMediaBox().getUpperRightY()); doc.addPage (page); float scale=0.55f; PDImageXObject pdImage = PDImageXObject.createFromFile(imageHeaderPath, doc); PDPageContentStream headerContentStream = new PDPageContentStream(doc, page,AppendMode.APPEND,false); //headerContentStream.drawImage(pdImage, 10, page.getMediaBox().getHeight()-130); headerContentStream.drawImage(pdImage, 10, page.getMediaBox().getHeight()-100, pdImage.getWidth()* scale, pdImage.getHeight() * scale); headerContentStream.beginText (); headerContentStream.newLineAtOffset (200, page.getMediaBox().getHeight() - 110); //contentStream.setFont (PDType1Font.COURIER_BOLD, 14); headerContentStream.setFont(PDType1Font.HELVETICA_BOLD, 16); headerContentStream.showText ("RELACI�" DE DECRETS"); headerContentStream.newLineAtOffset (0, page.getMediaBox().getHeight() - 500); headerContentStream.endText (); headerContentStream.beginText (); headerContentStream.newLineAtOffset (page.getMediaBox().getWidth()-100, 50 ); headerContentStream.setFont(PDType1Font.HELVETICA_OBLIQUE, 12); int myPage=lastPage+2; headerContentStream.showText ("Pàgina:" + myPage); headerContentStream.endText (); //headerContentStream.drawLine(0, 0, posY, lastPage); headerContentStream.moveTo(200, page.getMediaBox().getHeight() - 110-4); headerContentStream.lineTo(383, page.getMediaBox().getHeight() - 110-4); /* for (int i=0; i<100; i++) { headerContentStream.moveTo(100,100); headerContentStream.lineTo(100+5*i,100*i); //headerContentStream.drawLine(0, 0, 300, 400+i); }*/ headerContentStream.stroke(); headerContentStream.close(); } else page=doc.getPage(lastPage); PDPageContentStream contentStream = new PDPageContentStream (doc, page,AppendMode.APPEND, false); PDAnnotationLink txtLink = new PDAnnotationLink (); // border style PDBorderStyleDictionary linkBorder = new PDBorderStyleDictionary (); //linkBorder.setStyle (PDBorderStyleDictionary.STYLE_UNDERLINE); linkBorder.setStyle (PDBorderStyleDictionary.STYLE_BEVELED); linkBorder.setWidth (0); txtLink.setBorderStyle (linkBorder); // Border color (NOT USED) //final Color color = Color.GREEN; final Color color = Color.CYAN; final float [] components = new float [] { color.getRed()/255f, color.getGreen()/255f, color.getBlue()/255f }; txtLink.setColor (new PDColor (components, PDDeviceRGB.INSTANCE)); // Destination URI final PDActionURI action = new PDActionURI (); action.setURI(linkedPDFRelativePath); //action.setURI ("https://www.helger.com"); //OK //action.setURI ("pdf.pdf"); //OK //action.setURI ("file:///home/edu/Documentos/Transporte%20Musical.pdf"); //OK //action.setURI ("Transporte Musical.pdf"); // OK //action.setURI ("file:///home/edu/Descargas/Diptico de VALIDe.pdf"); //OK //action.setURI ("/home/edu/Descargas/Diptico de VALIDe.pdf"); //MAL //action.setURI ("file://./Transporte%20Musical.pdf"); // MAL //action.setURI ("file://Transporte%20Musical.pdf"); // MAL //action.setURI ("file:Transporte%20Musical.pdf"); // MAL //action.setURI ("Transporte%20Musical.pdf"); // MAL //action.setURI ("//home/edu/Descargas/Diptico de VALIDe.pdf"); //MAL txtLink.setAction (action); // Position final PDRectangle position = new PDRectangle (); position.setLowerLeftX (posX); position.setLowerLeftY (page.getMediaBox().getHeight()-posY); position.setUpperRightX (page.getMediaBox().getUpperRightX()-posX); position.setUpperRightY (page.getMediaBox().getHeight() -(posY + 2 + 10 + 2)); txtLink.setRectangle (position); page.getAnnotations().add (txtLink); // Main page content contentStream.beginText (); contentStream.newLineAtOffset (posX, page.getMediaBox().getHeight() - (posY + 2 + 10 + 2)); //contentStream.setFont (PDType1Font.COURIER_BOLD, 14); contentStream.setFont(PDType1Font.HELVETICA_OBLIQUE, 12); final Color color1 = Color.BLUE; final float [] components1 = new float [] { color1.getRed()/255f, color1.getGreen()/255f, color1.getBlue()/255f }; //contentStream.setStrokingColor(new PDColor (components1, PDDeviceRGB.INSTANCE)); contentStream.setNonStrokingColor(new PDColor (components1, PDDeviceRGB.INSTANCE)); contentStream.showText ( textLine); contentStream.endText (); contentStream.close(); return doc; } /* public static void main(String[] args) throws IOException { //html2Pdf("/home/edu/TYPESCRIPT/prova20/pdf.html", "/home/edu/TYPESCRIPT/prova20/pdf.pdf"); //createPdfWithLink("/home/edu/TYPESCRIPT/prova20/pdf1.pdf"); //Create a PDF document with a header PDDocument doc=null; int posX=80; int posY=135-25; for (int i=0; i<100; i++) { System.out.println(i); posY =posY +20; if (posY>PDRectangle.A4.getHeight()-90) posY=135; //doc= newTextWithLink(doc, "Hola " +i, 20, posY, "doc"+i+".pdf", "/home/edu/Imágenes/escut.png"); String headerFile=FileUtilsEdu.getPathFromResourcesFolder("images/capsalera.png"); doc= newTextWithLink(doc, "Hola " +i, posX, posY, "doc"+i+".pdf", headerFile); } doc.save("/home/eduard/kk/pdf_prova.pdf"); } */ /************************************************************************* * PARAGRAPHS !!! * see https://memorynotfound.com/apache-pdfbox-adding-multiline-paragraph/ *************************************************************************/ public static void main(String... args) { PDFont FONT = PDType1Font.HELVETICA; float FONT_SIZE = 12; //float LEADING = -1.5f * FONT_SIZE; //float LEADING = 1.5f * FONT_SIZE; float LEADING = 1.1f * FONT_SIZE; try (final PDDocument doc = new PDDocument()){ PDPage page = new PDPage(); doc.addPage(page); PDPageContentStream contentStream = new PDPageContentStream(doc, page); PDRectangle mediaBox = page.getMediaBox(); float marginY = 80; float marginX = 60; float width = mediaBox.getWidth() - 2 * marginX; float startX = mediaBox.getLowerLeftX() + marginX; float startY = mediaBox.getUpperRightY() - marginY; float posY=startY; String text = "Lorem ipsum\n dolor sit amet, \nconsectetur adipiscing elit, \nsed do eiusmod tempor incididunt" + " ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco" + " laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in " + " ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco" + " laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in " + "voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + " non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; contentStream.beginText(); addParagraph(contentStream, width, startX, startY, text, true, FONT_SIZE, FONT, LEADING, Color.BLACK, posY); addParagraph(contentStream, width, 0, -FONT_SIZE, text, FONT_SIZE, FONT, LEADING, Color.BLACK, posY); addParagraph(contentStream, width, 0, -FONT_SIZE, text, false, FONT_SIZE, FONT, LEADING, Color.BLACK, posY); contentStream.endText(); contentStream.close(); doc.save(new File("/tmp/example.pdf")); } catch (IOException e){ System.err.println("Exception while trying to create pdf document - " + e); } } public static float addParagraph(PDPageContentStream contentStream, float width, float sx, float sy, String text, float fontSize, PDFont font, float leading, Color color, float posY) throws IOException { return addParagraph(contentStream, width, sx, sy, text, false, fontSize, font, leading, color, posY); } public static float addParagraph(PDPageContentStream contentStream, float width, float sx, float sy, String text, boolean justify, float fontSize, PDFont font, Float leading, Color color, float posY) throws IOException { List<String> lines = parseLines(text, width, fontSize, font); return addParagraph(contentStream, width, sx, sy, lines , justify, fontSize, font, leading, color, posY); } public static float addParagraph(PDPageContentStream contentStream, float width, float sx, float sy, List<String> lines , boolean justify, float fontSize, PDFont font, Float leading, Color color, float posY) throws IOException { //List<String> lines = parseLines(text, width, fontSize, font); if (color==null) color=Color.BLACK; final float [] components1 = new float [] { color.getRed()/255f, color.getGreen()/255f, color.getBlue()/255f }; contentStream.setNonStrokingColor(new PDColor (components1, PDDeviceRGB.INSTANCE)); contentStream.setFont(font, fontSize); contentStream.newLineAtOffset(sx, sy); for (String line: lines) { float charSpacing = 0; if (justify){ if (line.length() > 1) { float size = fontSize * font.getStringWidth(line) / 1000; float free = width - size; if (free<0.15*width && free > 0 && !lines.get(lines.size() - 1).equals(line)) { charSpacing = free / (line.length() - 1); } } } contentStream.setCharacterSpacing(charSpacing); //contentStream.beginText(); line = arregla(line); if (line.contains("?9")) { System.out.println("voila"); } contentStream.showText(line); //contentStream.newLineAtOffset(0, leading); contentStream.newLineAtOffset(0, -Math.round(leading)); posY=posY+Math.round(leading); //contentStream.endText(); } return posY; } public static List<String> parseLines(String text, float width, float fontSize, PDFont font) throws IOException { List<String> lines = new ArrayList<String>(); int lastSpace = -1; while (text.length() > 0) { int spaceIndex = text.indexOf(' ', lastSpace + 1); if (spaceIndex < 0) spaceIndex = text.length(); String subString = text.substring(0, spaceIndex); if (subString.contains("?9")) { System.out.println("voila"); } int newLineIndex = subString.indexOf('\n'); if (newLineIndex>=0) { subString = text.substring(0, newLineIndex); subString = arregla(subString); lines.add(subString); text = text.substring(newLineIndex+1).trim(); lastSpace = -1; } else { //float size = FONT_SIZE * FONT.getStringWidth(subString) / 1000; float size = fontSize * font.getStringWidth(subString) / 1000; if (size > width) { if (lastSpace < 0){ lastSpace = spaceIndex; } subString = text.substring(0, lastSpace); subString = arregla(subString); lines.add(subString); text = text.substring(lastSpace).trim(); lastSpace = -1; } else if (spaceIndex == text.length()) { text = arregla(text); lines.add(text); text = ""; } else { lastSpace = spaceIndex; } } } return lines; } public static String arregla(String linea) { return linea .replace("\n", "").replace("\r", "") .replace("\u2019", "'").replace("\u0092", "'") .replace("\u0080", "€").replace("\u0009", "€") .replace("\u0093", "") .replace("\u0094", "") .replace("\u0015", " ").replace("\u0095", " "); //U+000D ('controlCR') } public static byte[] getContent(PDDocument doc) throws IOException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); doc.save(byteArrayOutputStream); doc.close(); return byteArrayOutputStream.toByteArray(); } }
5. PDF_AUtils.class
This class is for converting PDF to PDF-A
package openadmin.utils.decrets; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import javax.xml.transform.TransformerException; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.common.PDMetadata; import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent; import org.apache.xmpbox.XMPMetadata; import org.apache.xmpbox.schema.DublinCoreSchema; import org.apache.xmpbox.schema.PDFAIdentificationSchema; import org.apache.xmpbox.type.BadFieldValueException; import org.apache.xmpbox.xml.XmpSerializer; import ximodante.basic.utils.basic.ExecutionTypeEnum; import ximodante.basic.utils.basic.FileUtilsEdu; public class PDF_AUtils { // Convert a PDF 1.4 to 1.7 (PDF/A) s/Jesús Romero public static PDDocument setVersionPDFA(PDDocument doc, String fileName, ExecutionTypeEnum execType) { // add XMP metadata XMPMetadata xmp = XMPMetadata.createXMPMetadata(); try { DublinCoreSchema dc = xmp.createAndAddDublinCoreSchema(); dc.setTitle(fileName); PDFAIdentificationSchema id = xmp.createAndAddPFAIdentificationSchema(); id.setPart(1); id.setConformance("B"); XmpSerializer serializer = new XmpSerializer(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); serializer.serialize(xmp, baos, true); PDMetadata metadata = new PDMetadata(doc); metadata.importXMPMetadata(baos.toByteArray()); doc.getDocumentCatalog().setMetadata(metadata); // sRGB output intent //InputStream colorProfile = PDF_AUtils.class.getResourceAsStream("/org/apache/pdfbox/resources/pdfa/sRGB.icc"); String fileICM=FileUtilsEdu.getRelativeResourceFile(execType, "icm"+File.separator+ "sRGB_Color_Space_Profile.icm"); InputStream colorProfile = new FileInputStream(fileICM); PDOutputIntent intent; intent = new PDOutputIntent(doc, colorProfile); intent.setInfo("sRGB IEC61966-2.1"); intent.setOutputCondition("sRGB IEC61966-2.1"); intent.setOutputConditionIdentifier("sRGB IEC61966-2.1"); intent.setRegistryName("http://www.color.org"); doc.getDocumentCatalog().addOutputIntent(intent); } catch (BadFieldValueException e) { // won't happen here, as the provided value is valid throw new IllegalArgumentException(e); } catch (TransformerException e) { // e.printStackTrace(); } catch (IOException e) { // e.printStackTrace(); } catch (Exception e) { // e.printStackTrace(); } return doc; } public static void main(String[] args) { // } } PDPageContentStream contentStream = new PDPageContentStream (doc, page); PDAnnotationLink txtLink = new PDAnnotationLink (); PDAnnotationLink txtLink1 = new PDAnnotationLink (); // border style PDBorderStyleDictionary linkBorder = new PDBorderStyleDictionary (); linkBorder.setStyle (PDBorderStyleDictionary.STYLE_UNDERLINE); linkBorder.setWidth (10); txtLink.setBorderStyle (linkBorder); txtLink1.setBorderStyle (linkBorder); // Border color final Color color = Color.GREEN; final float [] components = new float [] { color.getRed () / 255f, color.getGreen () / 255f, color.getBlue () / 255f }; txtLink.setColor (new PDColor (components, PDDeviceRGB.INSTANCE)); txtLink1.setColor (new PDColor (components, PDDeviceRGB.INSTANCE)); // Destination URI final PDActionURI action = new PDActionURI (); //action.setURI ("https://www.helger.com"); //OK //action.setURI ("pdf.pdf"); //OK //action.setURI ("/home/edu/Descargas/Diptico de VALIDe.pdf"); //MAL //action.setURI ("file:///home/edu/Documentos/Transporte%20Musical.pdf"); //OK //action.setURI ("file://./Transporte%20Musical.pdf"); // MAL //action.setURI ("file://Transporte%20Musical.pdf"); // MAL //action.setURI ("file:Transporte%20Musical.pdf"); // MAL //action.setURI ("Transporte%20Musical.pdf"); // MAL action.setURI ("Transporte Musical.pdf"); // BIEN //action.setURI ("//home/edu/Descargas/Diptico de VALIDe.pdf"); //MAL //action.setURI ("file:///home/edu/Descargas/Diptico de VALIDe.pdf"); //OK txtLink.setAction (action); //Destination file //PDSimpleFileSpecification dest=new PDSimpleFileSpecification(); PDFileSpecification dest=new PDSimpleFileSpecification(); dest.setFile("/home/edu/Descargas/Diptico de VALIDe.pdf"); PDActionRemoteGoTo action1= new PDActionRemoteGoTo(); //PDActionGoTo action1= new PDActionGoTo(); action1.setOpenInNewWindow(OpenMode.NEW_WINDOW); //action1.setDestination(dest); action1.setFile(dest); txtLink1.setAction (action1); // Position final PDRectangle position = new PDRectangle (); position.setLowerLeftX (10); position.setLowerLeftY (10); position.setUpperRightX (200); position.setUpperRightY (10 + 2 + 10 + 2); txtLink.setRectangle (position); page.getAnnotations().add (txtLink); // Position final PDRectangle position1 = new PDRectangle (); position1.setLowerLeftX (10); position1.setLowerLeftY (90); position1.setUpperRightX (200); position1.setUpperRightY (90 + 2 + 10 + 2); txtLink1.setRectangle (position1); page.getAnnotations().add (txtLink1); // Main page content contentStream.beginText (); contentStream.newLineAtOffset (12, 12); contentStream.setFont (PDType1Font.COURIER_BOLD, 10); contentStream.showText ("This is linked to the outside world"); contentStream.endText (); contentStream.beginText (); contentStream.newLineAtOffset (12, 92); contentStream.setFont (PDType1Font.COURIER_BOLD, 10); contentStream.showText ("This is linked to the outside world 111111111111"); contentStream.endText (); contentStream.close(); doc.save(outputPdfPath); } /** * Write texLine ant a possition and create a link to a file in the same folder and adds an image to the top of the page. * @param doc * @param textLine * @param posX * @param posY * @param linkedPDFRelativePath * @param imageHeaderPath * @return * @throws IOException */ public static final PDDocument newTextWithLink(PDDocument doc, String textLine, int posX, int posY, String linkedPDFRelativePath, String imageHeaderPath) throws IOException { PDPage page=null; if (doc==null) doc = new PDDocument (); int lastPage= doc.getNumberOfPages()-1; if (lastPage<0 || posY<136) { page = new PDPage (PDRectangle.A4); System.out.println("HEIGHT="+page.getMediaBox().getHeight()); System.out.println("WIDTH="+page.getMediaBox().getWidth());; System.out.println("LowerLeftX="+page.getMediaBox().getLowerLeftX()); System.out.println("LowerLeftY="+page.getMediaBox().getLowerLeftY()); System.out.println("UpperRightX="+page.getMediaBox().getUpperRightX()); System.out.println("UpperRightY="+page.getMediaBox().getUpperRightY()); doc.addPage (page); float scale=0.55f; PDImageXObject pdImage = PDImageXObject.createFromFile(imageHeaderPath, doc); PDPageContentStream headerContentStream = new PDPageContentStream(doc, page,AppendMode.APPEND,false); //headerContentStream.drawImage(pdImage, 10, page.getMediaBox().getHeight()-130); headerContentStream.drawImage(pdImage, 10, page.getMediaBox().getHeight()-100, pdImage.getWidth()* scale, pdImage.getHeight() * scale); headerContentStream.beginText (); headerContentStream.newLineAtOffset (200, page.getMediaBox().getHeight() - 110); //contentStream.setFont (PDType1Font.COURIER_BOLD, 14); headerContentStream.setFont(PDType1Font.HELVETICA_BOLD, 16); headerContentStream.showText ("RELACI�" DE DECRETS"); headerContentStream.newLineAtOffset (0, page.getMediaBox().getHeight() - 500); headerContentStream.endText (); headerContentStream.beginText (); headerContentStream.newLineAtOffset (page.getMediaBox().getWidth()-100, 50 ); headerContentStream.setFont(PDType1Font.HELVETICA_OBLIQUE, 12); int myPage=lastPage+2; headerContentStream.showText ("Pàgina:" + myPage); headerContentStream.endText (); //headerContentStream.drawLine(0, 0, posY, lastPage); headerContentStream.moveTo(200, page.getMediaBox().getHeight() - 110-4); headerContentStream.lineTo(383, page.getMediaBox().getHeight() - 110-4); /* for (int i=0; i<100; i++) { headerContentStream.moveTo(100,100); headerContentStream.lineTo(100+5*i,100*i); //headerContentStream.drawLine(0, 0, 300, 400+i); }*/ headerContentStream.stroke(); headerContentStream.close(); } else page=doc.getPage(lastPage); PDPageContentStream contentStream = new PDPageContentStream (doc, page,AppendMode.APPEND, false); PDAnnotationLink txtLink = new PDAnnotationLink (); // border style PDBorderStyleDictionary linkBorder = new PDBorderStyleDictionary (); //linkBorder.setStyle (PDBorderStyleDictionary.STYLE_UNDERLINE); linkBorder.setStyle (PDBorderStyleDictionary.STYLE_BEVELED); linkBorder.setWidth (0); txtLink.setBorderStyle (linkBorder); // Border color (NOT USED) //final Color color = Color.GREEN; final Color color = Color.CYAN; final float [] components = new float [] { color.getRed()/255f, color.getGreen()/255f, color.getBlue()/255f }; txtLink.setColor (new PDColor (components, PDDeviceRGB.INSTANCE)); // Destination URI final PDActionURI action = new PDActionURI (); action.setURI(linkedPDFRelativePath); //action.setURI ("https://www.helger.com"); //OK //action.setURI ("pdf.pdf"); //OK //action.setURI ("file:///home/edu/Documentos/Transporte%20Musical.pdf"); //OK //action.setURI ("Transporte Musical.pdf"); // OK //action.setURI ("file:///home/edu/Descargas/Diptico de VALIDe.pdf"); //OK //action.setURI ("/home/edu/Descargas/Diptico de VALIDe.pdf"); //MAL //action.setURI ("file://./Transporte%20Musical.pdf"); // MAL //action.setURI ("file://Transporte%20Musical.pdf"); // MAL //action.setURI ("file:Transporte%20Musical.pdf"); // MAL //action.setURI ("Transporte%20Musical.pdf"); // MAL //action.setURI ("//home/edu/Descargas/Diptico de VALIDe.pdf"); //MAL txtLink.setAction (action); // Position final PDRectangle position = new PDRectangle (); position.setLowerLeftX (posX); position.setLowerLeftY (page.getMediaBox().getHeight()-posY); position.setUpperRightX (page.getMediaBox().getUpperRightX()-posX); position.setUpperRightY (page.getMediaBox().getHeight() -(posY + 2 + 10 + 2)); txtLink.setRectangle (position); page.getAnnotations().add (txtLink); // Main page content contentStream.beginText (); contentStream.newLineAtOffset (posX, page.getMediaBox().getHeight() - (posY + 2 + 10 + 2)); //contentStream.setFont (PDType1Font.COURIER_BOLD, 14); contentStream.setFont(PDType1Font.HELVETICA_OBLIQUE, 12); final Color color1 = Color.BLUE; final float [] components1 = new float [] { color1.getRed()/255f, color1.getGreen()/255f, color1.getBlue()/255f }; //contentStream.setStrokingColor(new PDColor (components1, PDDeviceRGB.INSTANCE)); contentStream.setNonStrokingColor(new PDColor (components1, PDDeviceRGB.INSTANCE)); contentStream.showText ( textLine); contentStream.endText (); contentStream.close(); return doc; } /* public static void main(String[] args) throws IOException { //html2Pdf("/home/edu/TYPESCRIPT/prova20/pdf.html", "/home/edu/TYPESCRIPT/prova20/pdf.pdf"); //createPdfWithLink("/home/edu/TYPESCRIPT/prova20/pdf1.pdf"); //Create a PDF document with a header PDDocument doc=null; int posX=80; int posY=135-25; for (int i=0; i<100; i++) { System.out.println(i); posY =posY +20; if (posY>PDRectangle.A4.getHeight()-90) posY=135; //doc= newTextWithLink(doc, "Hola " +i, 20, posY, "doc"+i+".pdf", "/home/edu/Imágenes/escut.png"); String headerFile=FileUtilsEdu.getPathFromResourcesFolder("images/capsalera.png"); doc= newTextWithLink(doc, "Hola " +i, posX, posY, "doc"+i+".pdf", headerFile); } doc.save("/home/eduard/kk/pdf_prova.pdf"); } */ /************************************************************************* * PARAGRAPHS !!! * see https://memorynotfound.com/apache-pdfbox-adding-multiline-paragraph/ *************************************************************************/ public static void main(String... args) { PDFont FONT = PDType1Font.HELVETICA; float FONT_SIZE = 12; //float LEADING = -1.5f * FONT_SIZE; //float LEADING = 1.5f * FONT_SIZE; float LEADING = 1.1f * FONT_SIZE; try (final PDDocument doc = new PDDocument()){ PDPage page = new PDPage(); doc.addPage(page); PDPageContentStream contentStream = new PDPageContentStream(doc, page); PDRectangle mediaBox = page.getMediaBox(); float marginY = 80; float marginX = 60; float width = mediaBox.getWidth() - 2 * marginX; float startX = mediaBox.getLowerLeftX() + marginX; float startY = mediaBox.getUpperRightY() - marginY; float posY=startY; String text = "Lorem ipsum\n dolor sit amet, \nconsectetur adipiscing elit, \nsed do eiusmod tempor incididunt" + " ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco" + " laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in " + " ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco" + " laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in " + "voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + " non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; contentStream.beginText(); addParagraph(contentStream, width, startX, startY, text, true, FONT_SIZE, FONT, LEADING, Color.BLACK, posY); addParagraph(contentStream, width, 0, -FONT_SIZE, text, FONT_SIZE, FONT, LEADING, Color.BLACK, posY); addParagraph(contentStream, width, 0, -FONT_SIZE, text, false, FONT_SIZE, FONT, LEADING, Color.BLACK, posY); contentStream.endText(); contentStream.close(); doc.save(new File("/tmp/example.pdf")); } catch (IOException e){ System.err.println("Exception while trying to create pdf document - " + e); } } public static float addParagraph(PDPageContentStream contentStream, float width, float sx, float sy, String text, float fontSize, PDFont font, float leading, Color color, float posY) throws IOException { return addParagraph(contentStream, width, sx, sy, text, false, fontSize, font, leading, color, posY); } public static float addParagraph(PDPageContentStream contentStream, float width, float sx, float sy, String text, boolean justify, float fontSize, PDFont font, Float leading, Color color, float posY) throws IOException { List<String> lines = parseLines(text, width, fontSize, font); return addParagraph(contentStream, width, sx, sy, lines , justify, fontSize, font, leading, color, posY); } public static float addParagraph(PDPageContentStream contentStream, float width, float sx, float sy, List<String> lines , boolean justify, float fontSize, PDFont font, Float leading, Color color, float posY) throws IOException { //List<String> lines = parseLines(text, width, fontSize, font); if (color==null) color=Color.BLACK; final float [] components1 = new float [] { color.getRed()/255f, color.getGreen()/255f, color.getBlue()/255f }; contentStream.setNonStrokingColor(new PDColor (components1, PDDeviceRGB.INSTANCE)); contentStream.setFont(font, fontSize); contentStream.newLineAtOffset(sx, sy); for (String line: lines) { float charSpacing = 0; if (justify){ if (line.length() > 1) { float size = fontSize * font.getStringWidth(line) / 1000; float free = width - size; if (free<0.15*width && free > 0 && !lines.get(lines.size() - 1).equals(line)) { charSpacing = free / (line.length() - 1); } } } contentStream.setCharacterSpacing(charSpacing); //contentStream.beginText(); line = arregla(line); if (line.contains("?9")) { System.out.println("voila"); } contentStream.showText(line); //contentStream.newLineAtOffset(0, leading); contentStream.newLineAtOffset(0, -Math.round(leading)); posY=posY+Math.round(leading); //contentStream.endText(); } return posY; } public static List<String> parseLines(String text, float width, float fontSize, PDFont font) throws IOException { List<String> lines = new ArrayList<String>(); int lastSpace = -1; while (text.length() > 0) { int spaceIndex = text.indexOf(' ', lastSpace + 1); if (spaceIndex < 0) spaceIndex = text.length(); String subString = text.substring(0, spaceIndex); if (subString.contains("?9")) { System.out.println("voila"); } int newLineIndex = subString.indexOf('\n'); if (newLineIndex>=0) { subString = text.substring(0, newLineIndex); subString = arregla(subString); lines.add(subString); text = text.substring(newLineIndex+1).trim(); lastSpace = -1; } else { //float size = FONT_SIZE * FONT.getStringWidth(subString) / 1000; float size = fontSize * font.getStringWidth(subString) / 1000; if (size > width) { if (lastSpace < 0){ lastSpace = spaceIndex; } subString = text.substring(0, lastSpace); subString = arregla(subString); lines.add(subString); text = text.substring(lastSpace).trim(); lastSpace = -1; } else if (spaceIndex == text.length()) { text = arregla(text); lines.add(text); text = ""; } else { lastSpace = spaceIndex; } } } return lines; } public static String arregla(String linea) { return linea .replace("\n", "").replace("\r", "") .replace("\u2019", "'").replace("\u0092", "'") .replace("\u0080", "€").replace("\u0009", "€") .replace("\u0093", "") .replace("\u0094", "") .replace("\u0015", " ").replace("\u0095", " "); //U+000D ('controlCR') } public static byte[] getContent(PDDocument doc) throws IOException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); doc.save(byteArrayOutputStream); doc.close(); return byteArrayOutputStream.toByteArray(); } }
6. PDFTables.class
This class is for managing classes in a PDF document
package openadmin.utils.decrets; import java.awt.Color; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDType0Font; import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.graphics.color.PDColor; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI; import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink; import org.apache.pdfbox.pdmodel.interactive.annotation.PDBorderStyleDictionary; import be.quodlibet.boxable.BaseTable; import be.quodlibet.boxable.Cell; import be.quodlibet.boxable.HorizontalAlignment; import be.quodlibet.boxable.Row; import be.quodlibet.boxable.VerticalAlignment; import ximodante.basic.utils.basic.ExecutionTypeEnum; import ximodante.basic.utils.basic.FileUtilsEdu; public class PDFTables { /** * Creates a table * @param yStart * @param yStartNewPage * @param bottomMargin * @param tableWidth * @param margin * @param rowHeigth * @param document * @param currentPage * @param drawLines * @param drawContent * @param content * @throws IOException */ public static void createTable(float yStart, float yStartNewPage, float bottomMargin, float tableWidth, float margin, float rowHeigth, PDDocument document, PDPage currentPage, boolean drawLines, boolean drawContent, String[][] content) throws IOException { BaseTable table = new BaseTable( yStart, yStartNewPage, bottomMargin, tableWidth, margin, document, currentPage, true, drawContent); //Create Header row Row<PDPage> headerRow = table.createRow(15f); //Heigth Cell<PDPage> cell = headerRow.createCell(100, "Awesome Facts About Belgium"); cell.setFont(PDType1Font.HELVETICA_BOLD); cell.setFillColor(Color.YELLOW); table.addHeaderRow(headerRow); for (String[] lineContent : content) { int nCols=lineContent.length; Row<PDPage> row = table.createRow(rowHeigth); //Heigth //cell = row.createCell((100 / 3.0f) * 2, lineContent[0]); cell = row.createCell((100 / nCols) , lineContent[0]); for (int i = 1; i < lineContent.length; i++) { //cell = row.createCell((100 / 9f), lineContent[i]); cell = row.createCell((100 / nCols), lineContent[i]); System.out.println("cell.getHeight()="+cell.getCellHeight()); } System.out.println("row.getHeight()="+row.getHeight()); //System.out.println("row.getWidth()="+row.getWidth()); } table.draw(); } /** * Verify that the arrays have the corrent dimensions * @param proportions 1 dimension Array of proportion of the cells * @param titles 1 dimension Array of titles of the table * @param content 2 dimension array of the content * @param links 2 dimension array of the links to the documents * @return true if no errors * @throws Exception if error */ private static boolean checkErrors_createTable01(float[] proportions, String[] titles, List<String[]> content, List<String[]> links) throws Exception { if (proportions.length!=links.get(0).length) throw new Exception("ERROR in createTable01: links must have the same number of components as proportions"); if (content.get(0).length!=links.get(0).length) throw new Exception("ERROR in createTable01: content must have the same number of components as proportions"); if (proportions.length!=titles.length) throw new Exception("ERROR in createTable01: proportions must have the same number of components as titles"); return true; } /** * Sum the array element * @param values * @return */ public static float sum(float[] values) { float total=0; for (float value: values) total +=value; return total; } /** * Get the column withs * @param tableWidth * @param proportions * @return */ public static float[] getwidths(float tableWidth, float[] proportions) { float[] widths= new float[proportions.length]; float total=sum(proportions); for (int i=0; i<proportions.length; i++) { widths[i]=tableWidth*proportions[i]/total; } return widths; } /** * Get the x position of the beginning of the cells * @param leftMargin * @param tableWidth * @param proportions * @return */ public static float[] getPosXs(float leftMargin, float tableWidth, float[] proportions) { float[] posXs= new float[proportions.length]; float[] widths= getwidths(tableWidth, proportions) ; for (int i=0; i<proportions.length; i++) { if (i==0) posXs[i]=leftMargin; else posXs[i]=posXs[i-1]+widths[i-1]; } return posXs; } /** * Create a table and return a map whose key is the row of the table and its values * are for the cells that have a link * * Note that we cannot crete links with this library, so the links must be created * after the table is created * * The fields of the map are: * * myHeight: Height of the row (or the cell) * line: row number, * i: column number, * row.getHeight(): Height of the row, * links[line][i]: the link of the cell * posXs[i]: x position * widths[i]; Widrh of the cell * @param yStart * @param yStartNewPage * @param bottomMargin * @param tableWidth * @param leftMargin * @param rowHeigth * @param document * @param currentPage * @param drawLines * @param drawContent * @param proportions * @param titles * @param titleRotates * @param content * @param textRotates * @param links * @return * @throws Exception */ public static Map<Integer,List<Object[]>> createTable01(float yStart, float yStartNewPage, float bottomMargin, float tableWidth, float leftMargin, float rowHeigth, PDDocument document, PDPage currentPage, boolean drawLines, boolean drawContent, float[] proportions,String[] titles, boolean[] titleRotates, //String[][] content, boolean[] textRotates, String[][] links) List<String[]> content, boolean[] textRotates, boolean[] textLinks,List<String[]> links, ExecutionTypeEnum execType) throws Exception { checkErrors_createTable01(proportions, titles, content, links); float totalProportion=sum(proportions); float[] widths=getwidths(tableWidth, proportions); float[] posXs=getPosXs(leftMargin, tableWidth, proportions); PDFont FONT = PDType0Font.load(document, new File(FileUtilsEdu.getRelativeResourceFile(execType, "fonts/Arial.ttf"))); PDFont FONT_ITALIC = PDType0Font.load(document, new File(FileUtilsEdu.getRelativeResourceFile(execType, "fonts/Arial-corsivo.ttf"))); PDFont FONT_BOLD = PDType0Font.load(document, new File(FileUtilsEdu.getRelativeResourceFile(execType, "fonts/FontsFree-Net-arial-bold.ttf"))); float FONT_SIZE = 9; Map<Integer,List<Object[]>> possitions=new HashMap<Integer,List<Object[]>>(); //float pageHeight=currentPage.getMediaBox().getHeight(); BaseTable table = new BaseTable( yStart, yStartNewPage, bottomMargin, tableWidth, leftMargin, document, currentPage, true, drawContent); //Create Header row Row<PDPage> headerRow = table.createRow(15f); //Heigth for (int i = 0; i < posXs.length; i++) { Cell<PDPage> cell = headerRow.createCell((100 *proportions[i]/totalProportion), titles[i]); if (titleRotates[i]) cell.setTextRotated(titleRotates[i]); else { cell.setAlign(HorizontalAlignment.CENTER); cell.setValign(VerticalAlignment.MIDDLE); } //cell.setFont(PDType1Font.HELVETICA_BOLD); cell.setFont(FONT_BOLD); cell.setFontSize(FONT_SIZE); cell.setFillColor(Color.YELLOW); } table.addHeaderRow(headerRow); float myHeight=yStart- headerRow.getHeight(); int nPage=0; int line=0; List<Object[]> lst=new ArrayList<Object[]>(); for (String[] lineContent : content) { int nCols=lineContent.length; Row<PDPage> row = table.createRow(rowHeigth); //Heigth //cell = row.createCell((100 / 3.0f) * 2, lineContent[0]); //cell = row.createCell((100 / nCols) , lineContent[0]); //cell = row.createCell((100 *proportions[0]/totalProportion), lineContent[0]); /* cell = row.createTableCell((100 *proportions[0]/totalProportion), "<table><tr><td>20210001</td><td></td><td>xml</td></tr></table>", document, currentPage, 0, 0, 0); */ //System.out.println("CellHeight()="+cell.getCellHeight()); for (int i = 0; i < nCols; i++) { Cell<PDPage> cell = row.createCell((100 *proportions[i]/totalProportion), lineContent[i]); if (textLinks[i]) { cell.setTextColor(Color.BLUE); cell.setFont(FONT_ITALIC); cell.setFontSize(FONT_SIZE-3); cell.setAlign(HorizontalAlignment.RIGHT); } else { cell.setTextColor(Color.BLACK); cell.setFont(FONT); cell.setFontSize(FONT_SIZE-1); cell.setAlign(HorizontalAlignment.CENTER); } if (textRotates[i]) cell.setTextRotated(textRotates[i]); } if (myHeight - row.getHeight()<bottomMargin) { myHeight=yStartNewPage- headerRow.getHeight(); possitions.put(nPage,lst); lst=new ArrayList<Object[]>(); nPage++; } myHeight=myHeight - row.getHeight(); System.out.println("row.getHeight()="+row.getHeight()); System.out.println("page="+table.getCurrentPage().toString()); System.out.println("myHeight="+myHeight); System.out.println("line="+line); System.out.println("nPage="+nPage); System.out.println("-----------------------------------------"); //for (int i=0; i<links[line].length; i++) { String[] link=links.get(line); for (int i=0; i<link.length; i++) { if (link[i]!=null && link[i].trim().length()>0) { Object[] objs= {myHeight, line, i, row.getHeight(), link[i], posXs[i], widths[i]}; lst.add(objs); } } line++; } if (lst.size()>0) possitions.put(nPage,lst); table.draw(); return possitions; } /** * Create the links in the cells that should contain links * @param doc * @param possitions */ public static void createLinks(PDDocument doc,Map<Integer,List<Object[]>>possitions) { Integer[] nPage= new Integer[1]; nPage[0]=-1; doc.getPages().forEach(page->{ nPage[0]++; List<Object[]>lObs=possitions.get(nPage[0]); //{myHeight, line, i, row.getHeight(), links[line][i], posXs[i], widths[i]}; for(Object[] objs:lObs) { try { addLink(doc, page, (String) objs[4], (float) objs[5], (float) objs[0], (float) objs[6], (float) objs[3]); } catch (IOException e) { // e.printStackTrace(); } } }); } public static void addPageNumbers(ExecutionTypeEnum execType, PDDocument doc, float leftMargin, float rightMargin, float topMargin, float bottomMargin) throws IOException, Exception { Integer[] nPage= {0, doc.getNumberOfPages()}; float[] pos= {0, 0, 0, 0}; PDFont FONT = PDType0Font.load(doc, new File(FileUtilsEdu.getRelativeResourceFile(execType, "fonts/Arial.ttf"))); float fontSize=9; String imagePath=FileUtilsEdu.getRelativeResourceFile(execType, "images/capsalera1.png"); PDImageXObject capsalera = PDImageXObject.createFromFile(imagePath,doc); doc.getPages().forEach(page->{ nPage[0]++; try { if (nPage[0]==1) { PDRectangle mediaBox = page.getMediaBox(); pos[0]= mediaBox.getWidth()-rightMargin- fontSize * FONT.getStringWidth("Pàg: 100 / "+nPage[1]) / 1000; pos[1]= bottomMargin -fontSize; pos[2]= mediaBox.getWidth() - 35/0.375f; pos[3]= mediaBox.getHeight(); } PDPageContentStream contentStream = new PDPageContentStream(doc, page, AppendMode.APPEND, false); //contentStream.drawImage(capsalera, leftMargin, pos[3]-topMargin-30/0.375f,pos[2], 30/0.375f); //35 if (nPage[0]>1)contentStream.drawImage(capsalera, leftMargin, pos[3]-35/0.375f,pos[2], 30/0.375f); //35 //PDPageContentStream contentStream = new PDPageContentStream(doc, page, AppendMode.APPEND, false); contentStream.beginText(); contentStream.setFont(FONT, 10); contentStream.newLineAtOffset(pos[0], pos[1]); contentStream.showText("Pàg: "+nPage[0]+" / "+nPage[1]); contentStream.endText(); contentStream.close(); // don't forget that one! } catch (IOException e) { // e.printStackTrace(); } }); } /** * Add a link at a page in the positions indicated * @param doc * @param page * @param linkedPDFRelativePath * @param posX * @param posY * @param width * @param height * @throws IOException */ public static void addLink(PDDocument doc, PDPage page, String linkedPDFRelativePath, float posX, float posY, float width, float height) throws IOException { //PDPageContentStream contentStream = new PDPageContentStream (doc, page,AppendMode.APPEND, false); PDAnnotationLink txtLink = new PDAnnotationLink (); // border style PDBorderStyleDictionary linkBorder = new PDBorderStyleDictionary (); //linkBorder.setStyle (PDBorderStyleDictionary.STYLE_UNDERLINE); linkBorder.setStyle (PDBorderStyleDictionary.STYLE_BEVELED); linkBorder.setWidth (0); txtLink.setBorderStyle (linkBorder); // Border color (NOT USED) //final Color color = Color.GREEN; final Color color = Color.CYAN; final float [] components = new float [] { color.getRed()/255f, color.getGreen()/255f, color.getBlue()/255f }; txtLink.setColor (new PDColor (components, PDDeviceRGB.INSTANCE)); // Destination URI final PDActionURI action = new PDActionURI (); action.setURI(linkedPDFRelativePath); txtLink.setAction (action); // Position final PDRectangle position = new PDRectangle (); position.setLowerLeftX (posX); position.setLowerLeftY (posY); position.setUpperRightX (posX+width); position.setUpperRightY (posY+height); txtLink.setRectangle (position); page.getAnnotations().add (txtLink); } public static void main (String[] args) throws Exception { ExecutionTypeEnum execType=ExecutionTypeEnum.NO_JAR; PDFont FONT = PDType1Font.HELVETICA; float FONT_SIZE = 10; //float LEADING = -1.5f * FONT_SIZE; float LEADING = 1.5f * FONT_SIZE; PDDocument doc=new PDDocument(); PDPage page = new PDPage(); doc.addPage(page); PDPageContentStream contentStream = new PDPageContentStream(doc, page); PDRectangle mediaBox = page.getMediaBox(); float marginY = 80; float marginX = 60; float width = mediaBox.getWidth() - 2 * marginX; float startX = mediaBox.getLowerLeftX() + marginX; float startY = mediaBox.getUpperRightY() - marginY; float posY=startY; String text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, \nsed do eiusmod tempor incididunt" + " ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco" + " laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in " + " ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco" + " laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in " + "voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat" + " non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; contentStream.beginText(); PDFUtils.addParagraph(contentStream, width, startX, startY, text, true, FONT_SIZE, FONT, LEADING, Color.BLACK, posY); PDFUtils.addParagraph(contentStream, width, 0, -FONT_SIZE, text, FONT_SIZE, FONT, LEADING, Color.BLACK, posY); PDFUtils.addParagraph(contentStream, width, 0, -FONT_SIZE, text, false, FONT_SIZE, FONT, LEADING, Color.BLACK, posY); contentStream.endText(); contentStream.close(); String[][] content= { {"202100001",">",">",">","Departament d'Informàtica0","Decret per a comprar 10 paelles gegants per a la joventud","15/10/2021"}, {"202100002",">",">",">","Departament d'Informàtica1","Decret per a comprar 10 paelles gegants per a la joventud","15/11/2021"}, {"202100003",">",">",">","Departament d'Informàtica2","Decret per a comprar 10 paelles gegants per a la joventud","15/12/2021"}, {"202100004",">",">",">","Departament d'Informàtica3","Decret per a comprar 10 paelles gegants per a la joventud","3/9/2021"} }; String[][] links= { {"","a0.pdf","b0.pdf","c0.pdf","","",""}, {"","a1.pdf","b1.pdf","c1.pdf","","",""}, {"","a2.pdf","b2.pdf","c2.pdf","","",""}, {"","a3.pdf","b3.pdf","c3.pdf","","",""} }; String[] titles= {"Núm Resolució","Original","Autèntic","ENI","Nom o designació","Descripcio","Data última firma"}; boolean[] titleRotates= {false,true,true,true,false,false,false}; boolean[] textRotates= {false,true,true,true,false,false,false}; boolean[] textLinks= {false,true,true,true,false,false,false}; float[] proportions={9.5f,2.5f,2.5f,2.5f,25f,35f,9.5f}; //float margin = 50; float leftMargin = 25/0.375f; // starting y position is whole page height subtracted by top and bottom margin //float yStartNewPage = page.getMediaBox().getHeight() - (2 * margin); float yStart = page.getMediaBox().getHeight() - (500); float yStartNewPage = page.getMediaBox().getHeight() - (30 /0.375f); // we want table across whole page width (subtracted by left and right margin ofcourse) float tableWidth = page.getMediaBox().getWidth() - (25+20)/0.375f ; boolean drawContent = true; boolean drawLines = true; //float yStart = yStartNewPage; //float bottomMargin = 70; float bottomMargin = 20/0.375f; // y position is your coordinate of top left corner of the table float yPosition = 550; for (int i=0; i<content.length; i++) { String[] line=content[i]; for (int j=0; j<line.length; j++) { content[i][j]=StringUtils.repeat(content[i][j], i+1); } } float rowHeight=20; float pageWidth = mediaBox.getWidth(); float pageHeight = mediaBox.getHeight(); System.out.println("pageWidth="+pageWidth); System.out.println("pageHeight="+pageHeight); System.out.println("leftMargin="+leftMargin); // System.out.println("rightMargin="+rightMargin); System.out.println("bottomMargin="+bottomMargin); System.out.println("yStartNewPage="+yStartNewPage); System.out.println("tableWidth="+tableWidth); //createTable(yStart, yStartNewPage, bottomMargin, tableWidth, margin, rowHeight, doc, page, drawLines, drawContent, content); Map<Integer,List<Object[]>> possitions= createTable01(yStart, yStartNewPage, bottomMargin, tableWidth, leftMargin, rowHeight, doc, page, drawLines, drawContent, proportions, titles, titleRotates, Arrays.asList(content), textRotates, textLinks, Arrays.asList(links), execType); createLinks(doc,possitions); doc.save("/home/eduard/kk/provaTaula.pdf"); } }
Comments
Post a Comment