0. Introducción
Parece ser que los que han desarrollado el modelo PDF y por ende los de PDFBos, son unos talentos en álgebra, pero, salvando las diferencias con ellos se puede llegar a cierto nivel, si se tiene en cuenta las nociones básicas que vemos a continuación.
1. Operaciones básicas
1. Para empezar debemos crear un nuevo documento PDF o cargar uno existente, y escoger una página (en principio la primera)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //===================================== // DOCUMENTO EXISTENTE //===================================== //1.1 Cargar un documento existente PDDocument document = PDDocument.load(new File(filePath)); //1.2Seleccionar la primera página PDPage page = document.getDocumentCatalog().getPages().get(0); //===================================== // DOCUMENTO NUEVO //===================================== //2.Crear un nuevo documento PDDocument doc = new PDDocument(); //2.1 Crear una nueva página y añadirla al documento PDPage page1 = new PDPage(); doc.addPage(page1); |
2. Crear un marco (rectángulo), SIN AFECTAR AL GROSOR DE LOS MARCOS EXISTENTES. Esta acción debe de ser la primera que se haga, pues puede afectar seriamente al grosor de los marcos existentes. Para ello se utiliza la opción "PDPageContentStream.AppendMode.APPEND". Ojo hay que tener en cuenta que solo debemos hacer APPEND una vez y al principio, pues resetea los cambios hechos hasta ahora.
Para ello creamos un PDPageContentStream para ir añadiendo el marco
1 2 3 4 5 6 7 | // Hay que abrir siempre un PDPageContentStream sobre la página y documento PDPageContentStream cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, false, false); cs.addRect(0, 0, width, height); // Rectangul (marco) cs.setLineWidth(0.1f); (grosor de línea) cs.setStrokingColor(Color.RED); (Color de la línea) cs.stroke(); cs.close(); |
3. Posicionarse en la hoja para escribir texto: Para escribir texto se utiliza el método showText("texto a mostrar") aplicado al PDPageContentStream. El proceso és el siguiente tal como se muestra en el código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | // Hay que abrir siempre un PDPageContentStream sobre la página y documento cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, false, false); // Abrimos el procweso de escritura de texto cs.beginText(); //Opcionalmente definimos una matriz de transformación // En este caso Rotación de 90 sobre loas coordenadas (0,0) en sentido de las agujas del reloj Matrix matrix = Matrix.getRotateInstance(Math.toRadians(90), 0, 0); //Aplicamos la transformación cs.setTextMatrix(matrix); //Definimos el ipo de lera (fuente) cs.setFont(PDType1Font.HELVETICA,13); //Nos deslazamos relativamente del punto inicial // En este caso, al hacer un giro de 90 la hoja queda apaisada, por ta cs.newLineAtOffset(530, 6); //Escribimos "texto 1" cs.showText("texto 1"); //Sobre la misma línea y a continuación escribimos "texto2" // y no hemos hecho ningún desplazamiento cs.showText("texto 2"); //Nos situamos 10 puntos más abajo pero respecto de la translación anterior // (sin verse afectadas las coordenadas por el texto escrito) cs.newLineAtOffset(0, 10); // Y imprimimos "texto 3" justo debajo de donde se ha impreeso "texto 1" cs.showText("texto 1"); //Cuando terminamos de imprimir todo el texto debemos indicar el "endText()" cc.endText(); //Cerramos el stream cs.close(); |
4. Si nos perdemos (no sabemos donde andamos, o sea no sabemos cual es la posición del cursor actual). Cerramos el PDPageContentStream y lo volvemos a brir. Si no funciona cambiamos la matrix de giro del código anterior por esta que no hace nada y deja la posición al (0,0)
1 2 3 4 5 | //Opcionalmente definimos una matriz de transformación // En este caso Rotación de 0 sobre loas coordenadas (0,0) en sentido de las agujas del reloj Matrix matrix = Matrix.getRotateInstance(Math.toRadians(0), 0, 0); //Aplicamos la transformación cs.setTextMatrix(matrix); |
5. Vamos a aplicar una translación y posteriormente un escalado reductor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | / Factor de escalado de toda la página float factor=0.75f; PDPageContentStream cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, false, false); //Matriz de escalado reductor de 0.75 en ambos ejes (para no distorsionar) Matrix matrix = Matrix.getScaleInstance(factor,factor); //Aplicamos la transformación cs.transform(matrix); cs.close(); // Translación de 25 en eje x y 50 en eje y a toda la página float tx=25f; floatty=50f; PDPageContentStream cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, false, false); // Matriz de translación Matrix matrix = Matrix.getTranslateInstance(tx, ty); cs.transform(matrix); cs.close(); |
2. Ejemplo
En este ejemplo se muestra como se hace un documento como este:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | import java.awt.Color; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Properties; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.font.PDFont; import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; import org.apache.pdfbox.util.Matrix; import gexflowcsv.GexflowCSV; import openadmin.utils.other.BarCodeUtils; import openadmin.dao.base.DaoOperationFacadeEdu; import openadmin.dao.implem.DaoJpaEdu; import openadmin.model.control.User; import openadmin.utils.basic.ExecutionTypeEnum; import openadmin.utils.basic.PropertyUtilsEdu; import openadmin.utils.basic.StringUtilsEdu; import openadmin.utils.graphic.GraphicUtils; public class ActionKK { public static float mm2point = 2.834f; /** * Get the document and modify it for having a "Copia Auténtica" * * call: ImprimirDocPorCSV(daoGexflow, AlbaProps, CMISProps, * CSV,"/home/eduard/Myresources", 19f,8f,22f) ; * * @param props * @param CSV * @param filePath * @param LMarginMm * @param RMarginMm * @param TMarginMm * @throws Exception */ public static void ImprimirDocPorCSV(DaoOperationFacadeEdu DAOGexflow, Properties AlbaProps, Properties CMISProps, String CSV, String folderPath, float LMarginMm, float RMarginMm, float TMarginMm) throws Exception { // 0. Parameters float A4WMm = 210f; // A4 width in mm. float scaleX = 0.4f; // For Barcode float scaleY = 0.45f; // For Barcode float factor = (A4WMm - LMarginMm - RMarginMm) / A4WMm; // Scale of document into the frame String sedeURL = AlbaProps.getProperty("gexflow.csv.url"); // 1. Get info of the document List<Object[]> lDoc = GexflowCSV.getDocBycsv(DAOGexflow, CSV); // PDDocument document = PDDocument.load(new File(filePath)); // 2. Load the document form alfresco PDDocument document = PDDocument .load(GexflowCSV.getCMISContentStream(CMISProps, GexflowCSV.getPdfUuid(lDoc), "id")); // If has signatures then put the csv and modify document with signatures if (GexflowCSV.hasFirmantes(lDoc)) { int nPage = 1; int nPages = document.getDocumentCatalog().getPages().getCount(); // 3. Apply changes for every page // PDPage page = document.getDocumentCatalog().getPages().get(0); for (PDPage page : document.getDocumentCatalog().getPages()) { // 4. Get dimensions of crop box PDRectangle mediaBox = page.getMediaBox(); float width = mediaBox.getWidth(); float height = mediaBox.getHeight(); // System.out.println("width="+width + " height="+height); if ((width - 595.30396f) > 1) throw new Exception("Invalid paper size"); // 5. Draw a black rectangle APPEND-> For the first time!!!) PDPageContentStream cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, false, false); cs.addRect(0, height, width, -height); // APPEND cs.setLineWidth(0.1f * mm2point); cs.setStrokingColor(Color.RED); cs.stroke(); // cs.close(); // 6. Add the CSV barcode float heighToRest = 390; // BarCode Code128 BufferedImage bcImage = BarCodeUtils.writeBarcodeCode128Zxing2File(CSV, 1000, 80, null); // Rotate image bcImage = GraphicUtils.rotate(bcImage, -90); // Convert image to PDF object PDImageXObject pdImage = LosslessFactory.createFromImage(document, bcImage); cs.drawImage(pdImage, -50, height - heighToRest, pdImage.getWidth() * scaleX, pdImage.getHeight() * scaleY); // 6.1. Remove borders of bar code using white rectangle cs.addRect(-50, height - heighToRest, pdImage.getWidth() * scaleX, pdImage.getHeight() * scaleY); // APPEND cs.setLineWidth(1f * mm2point); cs.setStrokingColor(Color.WHITE); cs.stroke(); cs.close(); // 7. Rotate the page and print CSV text (From now on , use PREPEND and NOT // APPEND) cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, false, false); cs.beginText(); Matrix matrixkk = Matrix.getRotateInstance(Math.toRadians(90), 0, 0); cs.setTextMatrix(matrixkk); cs.setFont(PDType1Font.HELVETICA, 13); cs.newLineAtOffset(530, 6); // cs.showText(CSV); // 8. Print "Copia auténtica..." String rollet0 = "Copia auténtica. "; String rollet1 = "Mediante el código impreso puede combrobar la validez de la firma"; String rollet2 = " electrónica en la URL: "; cs.setNonStrokingColor(Color.DARK_GRAY); cs.setFont(PDType1Font.HELVETICA_BOLD_OBLIQUE, 10); cs.newLineAtOffset(-515, 30); // cs.showText(rollet0); cs.setFont(PDType1Font.HELVETICA_OBLIQUE, 10); cs.showText(rollet1); cs.newLineAtOffset(0, -15); // cs.showText(rollet2); cs.setFont(PDType1Font.HELVETICA_BOLD_OBLIQUE, 11); cs.showText(sedeURL); cs.endText(); // 9. Print "Fecha de impresion..." // 9.1 undo the rotation matrixkk = Matrix.getRotateInstance(Math.toRadians(0), 0, 0); cs.setFont(PDType1Font.HELVETICA_BOLD_OBLIQUE, 10); cs.beginText(); cs.setTextMatrix(matrixkk); String fechita1 = "Fecha de impresión: "; // String fechita2="Martes, 4 de Octubre de 2021 7:38"; String fechita2 = GexflowCSV.getInfoImpresion(); String paginitas = "Página " + nPage++ + " de " + nPages; cs.newLineAtOffset(5, -15); // cs.showText(fechita1); cs.setFont(PDType1Font.HELVETICA_OBLIQUE, 10); cs.showText(fechita2); cs.newLineAtOffset(500, 0); // cs.showText(paginitas); cs.endText(); // end undo rotation cs.close(); // 10. Scale the page cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, false, false); Matrix matrix = Matrix.getScaleInstance(factor, factor); cs.transform(matrix); cs.close(); // 11. Trasllate the page float trX = LMarginMm * mm2point; float trY = (1 - factor) * height - TMarginMm * mm2point; // System.out.println("trX="+trX + " trY="+trY); cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, false, false); Matrix matrix1 = Matrix.getTranslateInstance(trX, trY); cs.transform(matrix1); cs.close(); // 11. Write DECRETO and signatures cs = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, false, false); cs.setFont(PDType1Font.HELVETICA_BOLD, 9); cs.beginText(); // 11.1. Decreto / acta cs.newLineAtOffset(trX + 2 * mm2point, height - 5 * mm2point); String sDecret = GexflowCSV.getInfoDecret(lDoc); // If it is not Decreto or Acta then doen't print this line if (sDecret.trim().length() > 5) { cs.showText(GexflowCSV.getInfoDecret(lDoc)); // Decret nº 2021 -2 // 11.2. FIRMADO cs.newLineAtOffset(0, -11); } cs.showText("FIRMADO"); // 11.3 Firmantes cs.setFont(PDType1Font.HELVETICA, 7); for (String firmantes : GexflowCSV.getInfoFirmantes(lDoc)) { cs.newLineAtOffset(0, -7); cs.showText(firmantes); } cs.endText(); cs.close(); // don't forget that one! } } String myFileName = folderPath + "/" + GexflowCSV.getPdfFileName(lDoc).replace(".pdf", ".esc" + ((int) (100 * factor)) + ".pdf"); System.out.println(myFileName); File myFile = new File(myFileName); // myFile.createNewFile(); document.save(myFile); document.close(); } public static void main(String[] args) { try { Properties AlbaProps = PropertyUtilsEdu.getProperties(ExecutionTypeEnum.NO_JAR, "alba"); Properties CMISProps = PropertyUtilsEdu.getProperties(ExecutionTypeEnum.NO_JAR, "cmis"); Properties DAOProps = PropertyUtilsEdu.getProperties(ExecutionTypeEnum.NO_JAR, "dao"); String[] daos = StringUtilsEdu.splitAndTrim(DAOProps.getProperty("persistence.units"), ";"); String[] daoHosts = StringUtilsEdu.splitAndTrim(DAOProps.getProperty("persistence.hosts"), ";"); String[] daosActives = StringUtilsEdu.splitAndTrim(DAOProps.getProperty("persistence.units.active"), ";"); User myUser = new User(); myUser.setDescription("Liuardo"); short i = 1; DaoOperationFacadeEdu daoGexflow = new DaoJpaEdu(myUser, daos[i], daoHosts[i], i, null, Boolean.parseBoolean(daosActives[i]), "1.1.1.1", "Liuardo", "Chrome", "11111"); String myFolder = "/home/eduard/MyResources"; String CSV = "e-Aqhe5yWHNm5PK*Yt+8iIlTJ*fHwEXX71miw7w"; // Acta ImprimirDocPorCSV(daoGexflow, AlbaProps, CMISProps, CSV, myFolder, 19f, 8f, 22f); CSV = "XZW9VdYdgm3v3e-9uMZxF2mHIrzK+GcKqMb3MsQ"; // Decret ImprimirDocPorCSV(daoGexflow, AlbaProps, CMISProps, CSV, myFolder, 19f, 8f, 22f); CSV = "JveQte+exrJZ09xMw76*vzbvLYvCJLPT0iwFpOw"; // 6 firmes !! ImprimirDocPorCSV(daoGexflow, AlbaProps, CMISProps, CSV, myFolder, 19f, 8f, 22f); } catch (Exception e) { e.printStackTrace(); } } } |
No hay comentarios :
Publicar un comentario