TwelveMonkeys ImageIO proporciona soporte extendido de formato de archivo de imagen para la plataforma Java, a través de complementos para el paquete javax.imageio.*
.
El objetivo principal de este proyecto es brindar soporte para formatos de archivo no cubiertos por el JDK. La compatibilidad con estos formatos es importante para poder leer los datos que se encuentran "en la naturaleza", así como para mantener el acceso a los datos en formatos heredados. Como existen muchos datos heredados, vemos la necesidad de implementaciones abiertas de lectores para formatos populares.
Complemento | Formato | Descripción | R | W. | Metadatos | Notas |
---|---|---|---|---|---|---|
Batik | SVG | Gráficos vectoriales escalables | ✔ | - | - | Requiere batik |
WMF | Metarchivo de MS Windows | ✔ | - | - | Requiere batik | |
BMP | BMP | Mapa de bits independiente del dispositivo MS Windows e IBM OS/2 | ✔ | ✔ | Nativo, Estándar | |
CANALLA | Formato del cursor de MS Windows | ✔ | - | - | ||
ICO | Formato de iconos de MS Windows | ✔ | ✔ | - | ||
DDS | DDS | Formato de superficie de dibujo directo de MS | ✔ | - | Estándar | |
HDR | HDR | Formato RGBE de alto rango dinámico Radiance | ✔ | - | Estándar | |
ICNS | ICNS | Imagen del icono de Apple | ✔ | ✔ | - | |
FIB | FIB | Formato de archivo de intercambio Commodore Amiga/Electronic Arts | ✔ | ✔ | Estándar | |
JPEG | JPEG | Grupo conjunto de expertos en fotógrafos | ✔ | ✔ | Nativo, Estándar | |
JPEG sin pérdida | ✔ | - | Nativo, Estándar | |||
PCX | PCX | Formato de pincel ZSoft | ✔ | - | Estándar | |
DCX | Documento de fax PCX de varias páginas | ✔ | - | Estándar | ||
PICTO | PICTO | Formato de imagen Apple QuickTime | ✔ | ✔ | Estándar | |
PNTG | Formato de imagen Apple MacPaint | ✔ | - | Estándar | ||
PNM | PAM | NetPBM portátil cualquier mapa | ✔ | ✔ | Estándar | |
PBM | Mapa de bits portátil NetPBM | ✔ | - | Estándar | ||
PGM | Mapa gris portátil NetPBM | ✔ | - | Estándar | ||
ppm | Mapa de imágenes portátil de NetPBM | ✔ | ✔ | Estándar | ||
PFM | Mapa flotante portátil | ✔ | - | Estándar | ||
PSD | PSD | Documento de Adobe Photoshop | ✔ | (✔) | Nativo, Estándar | |
PSB | Documento grande de Adobe Photoshop | ✔ | - | Nativo, Estándar | ||
SGI | SGI | Formato de imagen de gráficos de silicio | ✔ | - | Estándar | |
TGA | TGA | Formato de imagen Truevision TGA | ✔ | ✔ | Estándar | |
PulgaresDB | Pulgares.db | Base de datos de miniaturas de MS Windows | ✔ | - | - | Formato basado en documento compuesto OLE2 únicamente |
PELEA | PELEA | Formato de archivo de imagen etiquetado Aldus/Adobe | ✔ | ✔ | Nativo, Estándar | |
TIFF grande | ✔ | ✔ | Nativo, Estándar | |||
WebP | WebP | Formato Google WebP | ✔ | - | Estándar | |
XWD | XWD | Formato de volcado de ventana X11 | ✔ | - | Estándar |
Nota importante sobre el uso de Batik: lea el Proyecto de gráficos XML de Apache™ - Seguridad y asegúrese de utilizar una versión actualizada y segura.
Tenga en cuenta que los formatos GIF, PNG y WBMP ya son compatibles a través de la API ImageIO, utilizando los complementos estándar JDK. Para los formatos BMP, JPEG y TIFF, los complementos de TwelveMonkeys brindan soporte de formato extendido y funciones adicionales.
La mayoría de las veces, todo lo que necesitas hacer es simplemente incluir los complementos en tu proyecto y escribir:
BufferedImage image = ImageIO . read ( file );
Esto cargará la primera imagen del archivo, completamente en la memoria.
La forma básica y más sencilla de escribir es:
if (! ImageIO . write ( image , format , file )) {
// Handle image not written case
}
Esto escribirá la imagen completa en un solo archivo, usando la configuración predeterminada para el formato dado.
Los complementos se descubren automáticamente en tiempo de ejecución. Consulte las preguntas frecuentes para obtener más información sobre cómo funciona este mecanismo.
Si necesita más control de los parámetros de lectura y del proceso de lectura, el lenguaje común para lectura es algo como:
// Create input stream (in try-with-resource block to avoid leaks)
try ( ImageInputStream input = ImageIO . createImageInputStream ( file )) {
// Get the reader
Iterator < ImageReader > readers = ImageIO . getImageReaders ( input );
if (! readers . hasNext ()) {
throw new IllegalArgumentException ( "No reader for: " + file );
}
ImageReader reader = readers . next ();
try {
reader . setInput ( input );
// Optionally, listen for read warnings, progress, etc.
reader . addIIOReadWarningListener (...);
reader . addIIOReadProgressListener (...);
ImageReadParam param = reader . getDefaultReadParam ();
// Optionally, control read settings like sub sampling, source region or destination etc.
param . setSourceSubsampling (...);
param . setSourceRegion (...);
param . setDestination (...);
// ...
// Finally read the image, using settings from param
BufferedImage image = reader . read ( 0 , param );
// Optionally, read thumbnails, meta data, etc...
int numThumbs = reader . getNumThumbnails ( 0 );
// ...
}
finally {
// Dispose reader in finally block to avoid memory leaks
reader . dispose ();
}
}
Consulte al lector las dimensiones de la imagen de origen utilizando reader.getWidth(n)
y reader.getHeight(n)
sin leer primero la imagen completa en la memoria.
También es posible leer varias imágenes del mismo archivo en un bucle, usando reader.getNumImages()
.
Si necesita más control de los parámetros de escritura y del proceso de escritura, el lenguaje común para escribir es algo como:
// Get the writer
Iterator < ImageWriter > writers = ImageIO . getImageWritersByFormatName ( format );
if (! writers . hasNext ()) {
throw new IllegalArgumentException ( "No writer for: " + format );
}
ImageWriter writer = writers . next ();
try {
// Create output stream (in try-with-resource block to avoid leaks)
try ( ImageOutputStream output = ImageIO . createImageOutputStream ( file )) {
writer . setOutput ( output );
// Optionally, listen to progress, warnings, etc.
ImageWriteParam param = writer . getDefaultWriteParam ();
// Optionally, control format specific settings of param (requires casting), or
// control generic write settings like sub sampling, source region, output type etc.
// Optionally, provide thumbnails and image/stream metadata
writer . write (..., new IIOImage (..., image , ...), param );
}
}
finally {
// Dispose writer in finally block to avoid memory leaks
writer . dispose ();
}
Para un uso más avanzado e información sobre cómo utilizar la API ImageIO, le sugiero que lea la Guía de la API Java Image I/O de Oracle.
import com . twelvemonkeys . imageio . path . Paths ;
...
try ( ImageInputStream stream = ImageIO . createImageInputStream ( new File ( "image_with_path.jpg" )) {
BufferedImage image = Paths . readClipped ( stream );
// Do something with the clipped image...
}
Consulte la compatibilidad con Adobe Clipping Path en la Wiki para obtener más detalles y código de ejemplo.
La biblioteca viene con una operación de remuestreo (cambio de tamaño de imagen), que contiene muchos algoritmos diferentes para proporcionar excelentes resultados a una velocidad razonable.
import com . twelvemonkeys . image . ResampleOp ;
...
BufferedImage input = ...; // Image to resample
int width , height = ...; // new width/height
BufferedImageOp resampler = new ResampleOp ( width , height , ResampleOp . FILTER_LANCZOS ); // A good default filter, see class documentation for more info
BufferedImage output = resampler . filter ( input , null );
La biblioteca viene con una operación de tramado, que se puede usar para convertir BufferedImage
s a IndexColorModel
usando el tramado de difusión de errores de Floyd-Steinberg.
import com . twelvemonkeys . image . DiffusionDither ;
...
BufferedImage input = ...; // Image to dither
BufferedImageOp ditherer = new DiffusionDither ();
BufferedImage output = ditherer . filter ( input , null );
Cuando se utilizan los patrones normales para cargar imágenes, intentar cargar una imagen dañada provocará una IOException
.
BufferedImage image = null ;
try {
image = ImageIO . read ( file );
} catch ( IOException exception ) {
// Handle, log a warning/error etc
}
En este escenario, si la imagen está dañada e ImageIO.read
genera una excepción, image
sigue siendo null
; no es posible que una función devuelva un valor y genere una excepción.
Sin embargo, en algunos casos es posible obtener datos de imagen utilizables a partir de una imagen dañada. La forma de hacerlo es utilizar ImageReadParam
para establecer BufferedImage
como destino.
int width = reader . getWidth ( 0 );
int height = reader . getHeight ( 0 );
ImageTypeSpecifier imageType = reader . getRawImageType ( 0 );
BufferedImage image = imageType . createBufferedImage ( width , height );
ImageReadParam param = reader . getDefaultReadParam ();
param . setDestination ( image );
try {
reader . read ( 0 , param );
}
catch ( IOException e ) {
// Handle, log a warning/error etc
}
En teoría, esto debería funcionar para todos los complementos, pero el resultado es muy específico del complemento/implementación. Con algunos formatos y algunas formas de archivos dañados, es posible que obtengas una imagen que sea muy útil. Sin embargo, debes estar preparado para la posibilidad de que esto solo proporcione una imagen en blanco o vacía.
Descargue el proyecto (usando Git):
$ git clone [email protected]:haraldk/TwelveMonkeys.git
Esto debería crear una carpeta llamada TwelveMonkeys
en su directorio actual. Cambie el directorio a la carpeta TwelveMonkeys
y ejecute el siguiente comando para compilar.
Construya el proyecto (usando Maven):
$ mvn package
Actualmente, el JDK recomendado para realizar una compilación es Oracle JDK 8.x.
Es posible compilar utilizando OpenJDK, pero algunas pruebas pueden fallar debido a algunas diferencias menores entre los sistemas de gestión de color utilizados. Deberá deshabilitar las pruebas en cuestión o compilarlas sin pruebas por completo.
Debido a que las pruebas unitarias necesitan bastante memoria para ejecutarse, es posible que deba configurar la variable de entorno MAVEN_OPTS
para darle más memoria al proceso Java que ejecuta Maven. Sugiero algo como -Xmx512m -XX:MaxPermSize=256m
.
Opcionalmente, puedes instalar el proyecto en tu repositorio local de Maven usando:
$ mvn install
Para instalar los complementos, use Maven y agregue las dependencias necesarias a su proyecto, o agregue manualmente los JAR necesarios junto con las dependencias requeridas en class-path.
El mecanismo de búsqueda de servicios y registro de ImageIO garantizará que los complementos estén disponibles para su uso.
Para verificar que el complemento JPEG esté instalado y utilizado en tiempo de ejecución, puede usar el siguiente código:
Iterator < ImageReader > readers = ImageIO . getImageReadersByFormatName ( "JPEG" );
while ( readers . hasNext ()) {
System . out . println ( "reader: " + readers . next ());
}
La primera línea debería imprimir:
reader: com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReader@somehash
Para depender del complemento JPEG y TIFF usando Maven, agregue lo siguiente a su POM:
...
< dependencies >
...
< dependency >
< groupId >com.twelvemonkeys.imageio</ groupId >
< artifactId >imageio-jpeg</ artifactId >
< version >3.12.0</ version >
</ dependency >
< dependency >
< groupId >com.twelvemonkeys.imageio</ groupId >
< artifactId >imageio-tiff</ artifactId >
< version >3.12.0</ version >
</ dependency >
<!--
Optional dependency. Needed only if you deploy ImageIO plugins as part of a web app.
Make sure you add the IIOProviderContextListener to your web.xml, see above.
-->
< dependency >
< groupId >com.twelvemonkeys.servlet</ groupId >
< artifactId >servlet</ artifactId >
< version >3.12.0</ version >
</ dependency >
<!--
Or Jakarta version, for Servlet API 5.0
-->
< dependency >
< groupId >com.twelvemonkeys.servlet</ groupId >
< artifactId >servlet</ artifactId >
< version >3.12.0</ version >
< classifier >jakarta</ classifier >
</ dependency >
</ dependencies >
Para depender del complemento JPEG y TIFF en su IDE o programa, agregue todos los siguientes archivos JAR a su ruta de clase:
twelvemonkeys-common-lang-3.12.0.jar
twelvemonkeys-common-io-3.12.0.jar
twelvemonkeys-common-image-3.12.0.jar
twelvemonkeys-imageio-core-3.12.0.jar
twelvemonkeys-imageio-metadata-3.12.0.jar
twelvemonkeys-imageio-jpeg-3.12.0.jar
twelvemonkeys-imageio-tiff-3.12.0.jar
Debido a que el registro del complemento ImageIO
( IIORegistry
) es "VM global", no funciona bien con contextos de servlet tal como están. Esto es especialmente evidente si carga complementos desde la carpeta WEB-INF/lib
o classes
. A menos que agregue ImageIO.scanForPlugins()
en algún lugar de su código, es posible que los complementos nunca estén disponibles.
Además, los contextos de servlet cargan y descargan clases dinámicamente (utilizando un nuevo cargador de clases por contexto). Si reinicia su aplicación, las clases antiguas permanecerán de forma predeterminada en la memoria para siempre (porque la próxima vez que se llame scanForPlugins
, es otro ClassLoader
el que escanea/carga las clases y, por lo tanto, serán instancias nuevas en el registro). Si se intenta una lectura utilizando uno de los lectores "antiguos" restantes, pueden ocurrir excepciones extrañas (como NullPointerException
al acceder a campos inicializados static final
o NoClassDefFoundError
para clases internas no inicializadas).
Para solucionar tanto el problema de descubrimiento como la fuga de recursos, se recomienda encarecidamente utilizar IIOProviderContextListener
que implementa la carga y descarga dinámica de complementos ImageIO para aplicaciones web.
< web-app ...>
...
< listener >
< display-name >ImageIO service provider loader/unloader</ display-name >
< listener-class >com.twelvemonkeys.servlet.image.IIOProviderContextListener</ listener-class >
</ listener >
...
</ web-app >
La carga de complementos desde WEB-INF/lib
sin el detector de contexto instalado no es compatible y no funcionará correctamente.
El detector de contexto no depende de los complementos ImageIO de TwelveMonkeys y también puede usarse con JAI ImageIO u otros complementos ImageIO.
Otra opción segura es colocar los archivos JAR en la carpeta lib común o compartida del servidor de aplicaciones.
Para aquellos que realizan la transición del antiguo javax.servlet
al nuevo paquete jakarta.servlet
, hay una dependencia separada disponible. Contiene exactamente las mismas clases de servlet que se mencionaron anteriormente, pero construidas con los nuevos paquetes Jakarta EE. La dependencia tiene el mismo nombre de grupo e identificador que antes, pero se le añade un clasificador jakarta
para distinguirlo del paquete que no es de Yakarta.
Consulte el ejemplo de dependencia de Maven para saber cómo habilitarla con Maven. Gradle u otras herramientas de compilación tendrán opciones similares.
La forma recomendada de utilizar los complementos es simplemente incluir los JAR tal cual en su proyecto, a través de una dependencia de Maven o similar. No es necesario volver a empaquetarlo para utilizar la biblioteca y no se recomienda.
Sin embargo, si desea crear un JAR "grueso", o desea volver a empaquetar los JAR por algún motivo, es importante recordar que el descubrimiento automático de los complementos por parte de ImageIO depende del mecanismo de la interfaz del proveedor de servicios (SPI). En resumen, cada JAR contiene una carpeta especial, denominada META-INF/services
, que contiene uno o más archivos, normalmente javax.imageio.spi.ImageReaderSpi
y javax.imageio.spi.ImageWriterSpi
. Estos archivos existen con el mismo nombre en cada JAR , por lo que si simplemente descomprime todo en una sola carpeta o crea un JAR, los archivos se sobrescribirán y el comportamiento no se especificará (lo más probable es que termine instalando un solo complemento).
La solución es asegurarse de que todos los archivos con el mismo nombre se fusionen en un solo archivo que contenga toda la información SPI de cada tipo. Si utiliza el complemento Maven Shade, debe utilizar ServicesResourceTransformer para fusionar correctamente estos archivos. También es posible que desee utilizar ManifestResourceTransforme para obtener el nombre correcto del proveedor, información de la versión, etc. Otros paquetes JAR "gordos" probablemente tendrán mecanismos similares para fusionar entradas con el mismo nombre.
La última versión que se ejecutará en Java 7 es la 3.9.4. Las versiones posteriores requerirán Java 8 o posterior.
Dependencias comunes
Dependencias de ImageIO
Complementos de ImageIO
Complementos de ImageIO que requieren bibliotecas de terceros
Soporte de ruta de Photoshop para ImageIO
Soporte de servlets
Este proyecto se proporciona bajo la licencia BSD aprobada por OSI:
Copyright (c) 2008-2022, Harald Kuhr
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
o Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
P: ¿Cómo lo uso?
R: La forma más sencilla es crear su propio proyecto utilizando Maven, Gradle u otra herramienta de compilación con administración de dependencias y simplemente agregar dependencias a los complementos específicos que necesita. Si no utiliza dicha herramienta de compilación, asegúrese de tener todos los JAR necesarios en classpath. Consulte la sección Instalación anterior.
P: ¿Qué cambios debo realizar en mi código para poder utilizar los complementos?
a: La respuesta corta es: Ninguna. Para uso básico, como ImageIO.read(...)
o ImageIO.getImageReaders(...)
, no es necesario cambiar el código. La mayor parte de la funcionalidad está disponible a través de las API estándar de ImageIO y se ha tenido mucho cuidado en no introducir API adicionales cuando no son necesarias.
Si desea utilizar funciones muy específicas/avanzadas de algunos de los formatos, es posible que deba utilizar API específicas, como configurar la URL base para una imagen SVG que consta de varios archivos o controlar la compresión de salida de un archivo TIFF.
P: ¿Cómo funciona?
a: El proyecto ImageIO de TwelveMonkeys contiene complementos para ImageIO. ImageIO utiliza un mecanismo de búsqueda de servicios para descubrir complementos en tiempo de ejecución.
Todo lo que tiene que hacer es asegurarse de tener los JAR ImageIO de TwelveMonkeys en su classpath.
Puede leer más sobre el registro y el mecanismo de búsqueda en el documento API IIORegistry.
La letra pequeña: Los proveedores de servicios TwelveMonkeys para JPEG, BMP y TIFF anulan el método onRegistration y utilizan el mecanismo de orden parcial por pares de IIOServiceRegistry
para asegurarse de que se instale antes que el JPEGImageReader
, BMPImageReader
, TIFFImageReader
proporcionado por Sun/Oracle y el Apple proporcionó TIFFImageReader
en OS X, respectivamente. El uso del orden por pares no eliminará ninguna funcionalidad de estas implementaciones, pero en la mayoría de los casos terminará usando los complementos de TwelveMonkeys.
P: ¿Por qué no hay soporte para formatos comunes como GIF o PNG?
R: La respuesta corta es simplemente que el soporte integrado en ImageIO para estos formatos se considera suficientemente bueno tal como está. Si está buscando un mejor rendimiento de escritura PNG en Java 7 y 8, consulte JDK9 PNG Writer Backport.
P: ¿Cuándo será el próximo lanzamiento? ¿Cuál es el calendario de lanzamiento actual?
R: El objetivo es realizar lanzamientos mensuales que contengan correcciones de errores y características nuevas menores. Y lanzamientos trimestrales con características más "importantes".
P: ¡Me encanta este proyecto! ¿Cómo puedo ayudar?
R: Eche un vistazo a los problemas abiertos y vea si hay algún problema que pueda ayudar a solucionar, o proporcione un archivo de muestra o cree casos de prueba. También es posible que usted o su organización se conviertan en patrocinadores a través de GitHub Sponsors. Proporcionar financiación nos permitirá dedicar más tiempo a corregir errores e implementar nuevas funciones.
P: ¿Qué pasa con JAI? Varios de los formatos ya son compatibles con JAI.
R: Si bien JAI (y jai-imageio en particular) admiten algunos de los mismos formatos, JAI tiene algunos problemas importantes. El más obvio es:
P: ¿Qué pasa con JMagick o IM4Java? ¿No puedes simplemente usar lo que ya está disponible?
R: Si bien son excelentes bibliotecas con una amplia gama de formatos compatibles, las bibliotecas basadas en ImageMagick tienen algunas desventajas en comparación con ImageIO.
Lo hicimos