Introducción
Aspose.PDF FOSS para Java es una biblioteca Java bajo licencia MIT para crear y editar documentos PDF. Sus clases están organizadas bajo el paquete org.aspose.pdf y sus subpaquetes (org.aspose.pdf.annotations, org.aspose.pdf.forms, org.aspose.pdf.facades y otros), y Document es el punto de entrada para la mayoría de los flujos de trabajo. La biblioteca no tiene dependencias de tiempo de ejecución de terceros; la única dependencia en su compilación Maven es JUnit, con alcance de prueba.
El anuncio de la biblioteca, el post de fachadas, y el post de edición de páginas ya cubren la creación de documentos, campos de formulario, las clases fachada para extracción, cifrado y estampado, y operaciones de página con PdfFileEditor. Este post cubre cinco áreas adicionales del mismo API que esos posts no demuestran: anotaciones de marcado de texto, llamadas de texto libre, acciones a nivel de documento, una protección de tamaño en la decodificación de flujos y registro diagnóstico.
Cada área es un API pequeño y autónomo. Las secciones siguientes muestran las llamadas, los valores predeterminados y los casos límite que las propias pruebas de la biblioteca determinan.
Características clave
Anotaciones de marcado de texto
HighlightAnnotation, UnderlineAnnotation, StrikeOutAnnotation y SquigglyAnnotation cada uno recibe un Page y un Rectangle. El constructor deriva los puntos cuádruples de la anotación a partir del rectángulo, por lo que getQuadPoints() devuelve ocho valores sin cálculo manual. Para el rectángulo (100, 200, 300, 250) el resultado es [100, 250, 300, 250, 100, 200, 300, 200]: superior-izquierda, superior-derecha, inferior-izquierda y luego inferior-derecha. setQuadPoints() reemplaza los valores derivados con tu propio arreglo de ocho valores, y una anotación reconstruida a partir de un diccionario existente conserva los puntos cuádruples ya almacenados allí. getSubtype() devuelve el nombre del subtipo PDF: Highlight, Underline, StrikeOut o Squiggly.
Construir una anotación no la adjunta a la página. Agrégala con page.getAnnotations().add(...).
try (Document doc = new Document()) {
Page page = doc.getPages().add();
HighlightAnnotation highlight = new HighlightAnnotation(page, new Rectangle(100, 200, 300, 250));
double[] quadPoints = highlight.getQuadPoints();
UnderlineAnnotation underline = new UnderlineAnnotation(page, new Rectangle(50, 100, 200, 120));
StrikeOutAnnotation strikeOut = new StrikeOutAnnotation(page, new Rectangle(50, 140, 200, 160));
SquigglyAnnotation squiggly = new SquigglyAnnotation(page, new Rectangle(50, 180, 200, 200));
page.getAnnotations().add(highlight);
page.getAnnotations().add(underline);
page.getAnnotations().add(strikeOut);
page.getAnnotations().add(squiggly);
doc.save("markup.pdf");
}
Llamados de texto libre
FreeTextAnnotation coloca texto directamente en una página. Su constructor de tres argumentos recibe un DefaultAppearance, que contiene el nombre de la fuente, el tamaño de la fuente y el color del texto. Tres propiedades definen el llamado:
setIntent()recibe unFreeTextIntent:FreeText,FreeTextCalloutoFreeTextTypeWriter. Una nueva anotación informaUndefined, y pasarnullla devuelve a ese estado.setCallout()toma la línea del llamado como una matriz de dos o tres puntos{x, y}. Una matriz de cualquier otra longitud se ignora y el llamado existente permanece en su lugar;nullelimina el llamado.setEndingStyle()recibe un valorLineEndingcomoOpenArrowoDiamond. Una nueva anotación informaLineEnding.None.
try (Document doc = new Document()) {
Page page = doc.getPages().add();
DefaultAppearance da = new DefaultAppearance("Helv", 10, Color.BLACK);
FreeTextAnnotation note = new FreeTextAnnotation(page, new Rectangle(50, 50, 200, 100), da);
note.setContents("Check this value");
note.setIntent(FreeTextIntent.FreeTextCallout);
note.setCallout(new double[][] {{10, 10}, {50, 50}, {100, 100}});
note.setEndingStyle(LineEnding.OpenArrow);
page.getAnnotations().add(note);
doc.save("callout.pdf");
}
El diccionario de anotaciones guardado almacena estos valores como /IT, /CL y /LE.
Acciones a nivel de documento
Document.getActions() devuelve una vista DocumentActions del catálogo de documentos. setOpenAction() almacena una acción en la entrada /OpenAction del catálogo. Cinco disparadores adicionales, setBeforeClosing(), setBeforeSaving(), setAfterSaving(), setBeforePrinting() y setAfterPrinting(), se almacenan de forma independiente en el diccionario de acciones adicionales /AA del catálogo.
Cada getter devuelve null hasta que su disparador se establece. Pasar null a un setter elimina esa entrada, y eliminar el último disparador también elimina el diccionario /AA. Las acciones son instancias PdfAction; GoToURIAction es un alias de UriAction, y su getType() devuelve URI. El objeto DocumentActions es una vista en vivo, por lo que una llamada posterior a getActions() ve los cambios realizados a través de una anterior, y los disparadores se leen nuevamente cuando el archivo guardado se abre de nuevo.
try (Document doc = new Document()) {
doc.getPages().add();
DocumentActions actions = doc.getActions();
actions.setOpenAction(new GoToURIAction("https://example.com"));
actions.setBeforeSaving(new GoToURIAction("https://example.com/saving"));
PdfAction open = doc.getActions().getOpenAction();
if (open instanceof UriAction) {
System.out.println(((UriAction) open).getUri());
}
actions.setBeforeSaving(null); // removes /WS; /AA is removed once it is empty
doc.save("actions.pdf");
}
Límites de decodificación para filtros de flujo
Los flujos PDF se almacenan en forma codificada, y un flujo corrupto o malicioso puede expandirse a mucho más que su tamaño almacenado. DecodeLimits es una protección compartida por los filtros FlateDecode, LZWDecode y RunLengthDecode. Cuando la salida decodificada de un flujo supera el límite, el filtro lanza DecodeSizeLimitException, una subclase de IOException, en lugar de decodificar hasta que se agote el montón.
El límite predeterminado es 256MB por flujo decodificado (DecodeLimits.DEFAULT_MAX_DECODED_BYTES). Para cambiarlo, establezca la propiedad del sistema nombrada por DecodeLimits.PROPERTY, que es aspose.pdf.maxDecodedStreamBytes, a un tamaño en bytes; un valor de 0 o menos deshabilita la protección. La propiedad se lee en cada decodificación, por lo que puede modificarse en tiempo de ejecución.
static byte[] decodeFlate(byte[] encoded) {
// Lower the cap to 16 MB (16777216 bytes) for this process
System.setProperty(DecodeLimits.PROPERTY, "16777216");
try {
return new FlateFilter().decode(encoded, null);
} catch (IOException e) {
// "FlateDecode: decoded output exceeds 16777216 bytes - likely a corrupt stream
// or decompression bomb (override with -Daspose.pdf.maxDecodedStreamBytes)"
return null;
}
}
Los flujos bajo el límite se decodifican como de costumbre. FlateFilter y RunLengthFilter realizan un ciclo completo de datos a través de encode() y decode() cuando la salida se mantiene por debajo del límite.
Registro de diagnóstico
La biblioteca registra a través de java.util.logging bajo el registrador org.aspose.pdf y está silenciosa por defecto: el nivel es OFF. AsposePdfLogging activa el registro.
setLevel(Level)establece el nivel desde el código;nulldevuelve la biblioteca aOFF.getLevel()lo lee de nuevo.- La propiedad del sistema
aspose.pdf.log(también disponible comoAsposePdfLogging.LOG_PROPERTY) la establece desde la línea de comandos.configureFromSystemProperty()aplica la propiedad y también se ejecuta cuando se carga la clase. Los valoresonywarningseleccionanWARNING,verboseseleccionaFINE,debugseleccionaALL, cualquier nombrejava.util.logging.LevelcomoSEVEREes aceptado, y un valor no reconocido vuelve aOFF.
WARNING permite que pasen las advertencias del motor; FINE, la configuración verbose, también permite que pasen los detalles de recuperación del analizador. AsposePdfLogging cambia solo la subárbol del registrador org.aspose.pdf. No cambia el nivel del registrador raíz, y el registrador de la biblioteca no pasa registros a los manejadores del registrador raíz. Si el registro está habilitado y no hay un manejador adjunto al registrador de la biblioteca, se instala un manejador de consola.
// Equivalent to starting the JVM with -Daspose.pdf.log=warning
AsposePdfLogging.setLevel(Level.WARNING);
System.setProperty(AsposePdfLogging.LOG_PROPERTY, "verbose");
AsposePdfLogging.configureFromSystemProperty();
System.out.println(AsposePdfLogging.getLevel()); // FINE
Inicio rápido
Agrega la dependencia a tu compilación:
<dependency>
<groupId>org.aspose</groupId>
<artifactId>aspose-pdf-foss</artifactId>
<version>26.8.0</version>
</dependency>El siguiente ejemplo crea una página, agrega un resaltado y una llamada de texto libre, y guarda el documento:
import org.aspose.pdf.*;
import org.aspose.pdf.annotations.*;
try (Document doc = new Document()) {
Page page = doc.getPages().add();
page.getAnnotations().add(new HighlightAnnotation(page, new Rectangle(100, 200, 300, 250)));
FreeTextAnnotation note = new FreeTextAnnotation(page, new Rectangle(50, 50, 200, 100),
new DefaultAppearance("Helv", 10, Color.BLACK));
note.setContents("Check this value");
note.setIntent(FreeTextIntent.FreeTextCallout);
note.setCallout(new double[][] {{10, 10}, {50, 50}, {100, 100}});
page.getAnnotations().add(note);
doc.save("core-features.pdf");
}
Formatos compatibles
Soporte de formatos según lo confirmado por las opciones de carga y guardado de la biblioteca y los dispositivos de renderizado:
| Formato | Extensión | Leer | Escribir |
|---|---|---|---|
| ✓ | ✓ | ||
| HTML | html | ✓ | ✓ |
| DOCX | docx | ✓ | ✓ |
| DOC | doc | ✓ | ✓ |
| XFDF | xfdf | ✓ | ✓ |
| BMP | bmp | — | ✓ |
| GIF | gif | — | ✓ |
| JPEG | jpeg | — | ✓ |
| TIFF | tiff | — | ✓ |
| Text | txt | — | ✓ |
Código abierto y licencias
Aspose.PDF FOSS para Java se publica bajo la licencia MIT, que permite el uso comercial, la modificación y la redistribución. El código fuente y el rastreador de incidencias están en github.com/aspose-pdf-foss/Aspose.PDF-FOSS-for-Java. La biblioteca está dirigida a Java 11 o posterior.