TwelveMonkeys ImageIO fournit une prise en charge étendue du format de fichier image pour la plate-forme Java, via des plugins pour le package javax.imageio.*
.
L'objectif principal de ce projet est de fournir la prise en charge des formats de fichiers non couverts par le JDK. La prise en charge de ces formats est importante, pour pouvoir lire les données trouvées « dans la nature », ainsi que pour maintenir l'accès aux données dans les formats existants. Comme il existe de nombreuses données existantes, nous constatons la nécessité d'implémentations ouvertes de lecteurs pour les formats populaires.
Plugin | Format | Description | R. | W | Métadonnées | Remarques |
---|---|---|---|---|---|---|
Batik | SVG | Graphiques vectoriels évolutifs | ✔ | - | - | Nécessite du batik |
WMF | Métafichier MS Windows | ✔ | - | - | Nécessite du batik | |
PGB | PGB | Bitmap indépendant du périphérique MS Windows et IBM OS/2 | ✔ | ✔ | Natif, Standard | |
CUR | Format du curseur MS Windows | ✔ | - | - | ||
OIC | Format d'icône MS Windows | ✔ | ✔ | - | ||
DDS | DDS | Format de surface de dessin direct MS | ✔ | - | Standard | |
HDR | HDR | Format RVBE à plage dynamique élevée Radiance | ✔ | - | Standard | |
ICNS | ICNS | Image d'icône de pomme | ✔ | ✔ | - | |
FIF | FIF | Format de fichier d'échange Commodore Amiga/Electronic Arts | ✔ | ✔ | Standard | |
JPEG | JPEG | Groupe conjoint d'experts en photographes | ✔ | ✔ | Natif, Standard | |
JPEG sans perte | ✔ | - | Natif, Standard | |||
PCX | PCX | Format de pinceau ZSoft | ✔ | - | Standard | |
DCX | Document de télécopie PCX multipage | ✔ | - | Standard | ||
PICT | PICT | Format d'image Apple QuickTime | ✔ | ✔ | Standard | |
PNTG | Format d'image Apple MacPaint | ✔ | - | Standard | ||
PNM | PAM | NetPBM portable n'importe quelle carte | ✔ | ✔ | Standard | |
PBM | Carte de bits portable NetPBM | ✔ | - | Standard | ||
PGM | Carte grise portable NetPBM | ✔ | - | Standard | ||
ppm | Carte Pix portable NetPBM | ✔ | ✔ | Standard | ||
GFP | Carte flottante portable | ✔ | - | Standard | ||
PSD | PSD | Document Adobe Photoshop | ✔ | ( ✔ ) | Natif, Standard | |
PSB | Document volumineux Adobe Photoshop | ✔ | - | Natif, Standard | ||
SIG | SIG | Format d'image graphique en silicium | ✔ | - | Standard | |
TGA | TGA | Format d'image Truevision TGA | ✔ | ✔ | Standard | |
ThumbsDB | Thumbs.db | Base de données MS Windows Thumbs | ✔ | - | - | Format basé sur un document composé OLE2 uniquement |
TIFF | TIFF | Format de fichier image balisé Aldus/Adobe | ✔ | ✔ | Natif, Standard | |
BigTIFF | ✔ | ✔ | Natif, Standard | |||
WebP | WebP | Format Google WebP | ✔ | - | Standard | |
XWD | XWD | Format de vidage de fenêtre X11 | ✔ | - | Standard |
Remarque importante sur l'utilisation de Batik : veuillez lire The Apache™ XML Graphics Project - Security et assurez-vous d'utiliser une version mise à jour et sécurisée.
Notez que les formats GIF, PNG et WBMP sont déjà pris en charge via l'API ImageIO, en utilisant les plugins standards du JDK. Pour les formats BMP, JPEG et TIFF, les plugins TwelveMonkeys offrent une prise en charge étendue des formats et des fonctionnalités supplémentaires.
La plupart du temps, il vous suffit simplement d’inclure les plugins dans votre projet et d’écrire :
BufferedImage image = ImageIO . read ( file );
Cela chargera la première image du fichier, entièrement en mémoire.
La forme d’écriture de base et la plus simple est :
if (! ImageIO . write ( image , format , file )) {
// Handle image not written case
}
Cela écrira l'intégralité de l'image dans un seul fichier, en utilisant les paramètres par défaut pour le format donné.
Les plugins sont découverts automatiquement au moment de l'exécution. Consultez la FAQ pour plus d'informations sur le fonctionnement de ce mécanisme.
Si vous avez besoin de plus de contrôle sur les paramètres de lecture et le processus de lecture, l'expression courante pour la lecture est quelque chose comme :
// 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 ();
}
}
Interrogez le lecteur pour connaître les dimensions de l'image source à l'aide de reader.getWidth(n)
et reader.getHeight(n)
sans lire au préalable l'intégralité de l'image en mémoire.
Il est également possible de lire plusieurs images du même fichier en boucle, en utilisant reader.getNumImages()
.
Si vous avez besoin de plus de contrôle sur les paramètres d'écriture et le processus d'écriture, l'expression courante pour l'écriture est quelque chose comme :
// 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 ();
}
Pour une utilisation plus avancée et des informations sur l'utilisation de l'API ImageIO, je vous suggère de lire le guide de l'API Java Image I/O d'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...
}
Voir Prise en charge d'Adobe Clipping Path sur le Wiki pour plus de détails et un exemple de code.
La bibliothèque est livrée avec une opération de rééchantillonnage (redimensionnement d'image), qui contient de nombreux algorithmes différents pour fournir d'excellents résultats à une vitesse raisonnable.
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 bibliothèque est livrée avec une opération de tramage, qui peut être utilisée pour convertir BufferedImage
en IndexColorModel
à l'aide du tramage à diffusion d'erreur Floyd-Steinberg.
import com . twelvemonkeys . image . DiffusionDither ;
...
BufferedImage input = ...; // Image to dither
BufferedImageOp ditherer = new DiffusionDither ();
BufferedImage output = ditherer . filter ( input , null );
Lorsque vous utilisez les modèles normaux pour charger des images, essayer de charger une image endommagée entraînera la levée d’une IOException
.
BufferedImage image = null ;
try {
image = ImageIO . read ( file );
} catch ( IOException exception ) {
// Handle, log a warning/error etc
}
Dans ce scénario, si l'image est endommagée et que ImageIO.read
lève une exception, image
est toujours null
- il n'est pas possible pour une fonction de renvoyer une valeur et de lever une exception.
Cependant, dans certains cas, il peut être possible d'obtenir des données d'image utilisables à partir d'une image endommagée. La façon de procéder consiste à utiliser un ImageReadParam
pour définir un BufferedImage
comme destination.
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 théorie, cela devrait fonctionner pour tous les plugins, mais le résultat est très spécifique au plugin/à l'implémentation. Avec certains formats et certaines formes de fichiers endommagés, vous pouvez obtenir une image particulièrement utile. Cependant, vous devez vous préparer à la possibilité que cela donne simplement une image vide ou vide.
Téléchargez le projet (en utilisant Git) :
$ git clone [email protected]:haraldk/TwelveMonkeys.git
Cela devrait créer un dossier nommé TwelveMonkeys
dans votre répertoire actuel. Changez de répertoire pour le dossier TwelveMonkeys
et exécutez la commande ci-dessous pour construire.
Construisez le projet (en utilisant Maven) :
$ mvn package
Actuellement, le JDK recommandé pour créer une build est Oracle JDK 8.x.
Il est possible de construire avec OpenJDK, mais certains tests peuvent échouer en raison de différences mineures entre les systèmes de gestion des couleurs utilisés. Vous devrez soit désactiver les tests en question, soit créer complètement sans tests.
Étant donné que les tests unitaires nécessitent beaucoup de mémoire pour s'exécuter, vous devrez peut-être définir la variable d'environnement MAVEN_OPTS
pour donner plus de mémoire au processus Java qui exécute Maven. Je suggère quelque chose comme -Xmx512m -XX:MaxPermSize=256m
.
Facultativement, vous pouvez installer le projet dans votre référentiel Maven local en utilisant :
$ mvn install
Pour installer les plug-ins, utilisez Maven et ajoutez les dépendances nécessaires à votre projet, ou ajoutez manuellement les JAR nécessaires ainsi que les dépendances requises dans le chemin de classe.
Le registre ImageIO et le mécanisme de recherche de services garantiront que les plugins sont disponibles.
Pour vérifier que le plugin JPEG est installé et utilisé au moment de l'exécution, vous pouvez utiliser le code suivant :
Iterator < ImageReader > readers = ImageIO . getImageReadersByFormatName ( "JPEG" );
while ( readers . hasNext ()) {
System . out . println ( "reader: " + readers . next ());
}
La première ligne doit afficher :
reader: com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReader@somehash
Pour dépendre du plugin JPEG et TIFF utilisant Maven, ajoutez ce qui suit à votre 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 >
Pour dépendre du plugin JPEG et TIFF dans votre IDE ou programme, ajoutez tous les JAR suivants à votre chemin de classe :
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
Étant donné que le registre du plug-in ImageIO
( IIORegistry
) est « VM global », il ne fonctionne pas bien avec les contextes de servlet tels quels. Cela est particulièrement évident si vous chargez des plugins depuis le dossier WEB-INF/lib
ou classes
. À moins que vous n'ajoutiez ImageIO.scanForPlugins()
quelque part dans votre code, les plugins pourraient ne jamais être disponibles du tout.
De plus, les contextes de servlet chargent et déchargent dynamiquement les classes (en utilisant un nouveau chargeur de classe par contexte). Si vous redémarrez votre application, les anciennes classes resteront par défaut en mémoire pour toujours (car la prochaine fois que scanForPlugins
sera appelé, c'est un autre ClassLoader
qui analyse/charge les classes, et ce seront donc de nouvelles instances dans le registre). Si une lecture est tentée à l'aide de l'un des "anciens" lecteurs restants, des exceptions étranges (comme les NullPointerException
lors de l'accès aux champs initialisés static final
ou les NoClassDefFoundError
pour les classes internes non initialisées) peuvent se produire.
Pour contourner à la fois le problème de découverte et la fuite de ressources, il est fortement recommandé d'utiliser IIOProviderContextListener
qui implémente le chargement et le déchargement dynamiques des plugins ImageIO pour les applications 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 >
Le chargement de plugins depuis WEB-INF/lib
sans l'écouteur de contexte installé n'est pas pris en charge et ne fonctionnera pas correctement.
L'écouteur de contexte n'a aucune dépendance avec les plugins TwelveMonkeys ImageIO et peut également être utilisé avec JAI ImageIO ou d'autres plugins ImageIO.
Une autre option sûre consiste à placer les fichiers JAR dans le dossier lib partagé ou commun du serveur d'applications.
Pour ceux qui passent de l'ancien javax.servlet
au nouveau package jakarta.servlet
, une dépendance distincte est disponible. Il contient exactement les mêmes classes de servlets que celles mentionnées ci-dessus, mais construites avec les nouveaux packages Jakarta EE. La dépendance a le même nom de groupe et le même identifiant qu'avant, mais un classificateur jakarta
est ajouté, pour la distinguer du package non-Jakarta.
Consultez l'exemple de dépendance Maven pour savoir comment l'activer avec Maven. Gradle ou d'autres outils de construction auront des options similaires.
La manière recommandée d'utiliser les plugins consiste simplement à inclure les JAR tels quels dans votre projet, via une dépendance Maven ou similaire. Le reconditionnement n'est pas nécessaire pour utiliser la bibliothèque et n'est pas recommandé.
Cependant, si vous souhaitez créer un "gros" JAR, ou si vous souhaitez reconditionner les JAR pour une raison quelconque, il est important de se rappeler que la découverte automatique des plugins par ImageIO dépend du mécanisme de l'interface du fournisseur de services (SPI). En bref, chaque JAR contient un dossier spécial, nommé META-INF/services
, contenant un ou plusieurs fichiers, généralement javax.imageio.spi.ImageReaderSpi
et javax.imageio.spi.ImageWriterSpi
. Ces fichiers existent avec le même nom dans chaque JAR , donc si vous décompressez simplement tout dans un seul dossier ou créez un JAR, les fichiers seront écrasés et le comportement ne sera pas spécifié (vous vous retrouverez très probablement avec un seul plugin installé).
La solution consiste à s'assurer que tous les fichiers portant le même nom sont fusionnés en un seul fichier, contenant toutes les informations SPI de chaque type. Si vous utilisez le plugin Maven Shade, vous devez utiliser ServicesResourceTransformer pour fusionner correctement ces fichiers. Vous souhaiterez peut-être également utiliser ManifestResourceTransforme pour obtenir le nom correct du fournisseur, les informations de version, etc. D'autres bundles JAR "gros" auront probablement des mécanismes similaires pour fusionner les entrées portant le même nom.
La dernière version qui fonctionnera sur Java 7 est la 3.9.4. Les versions ultérieures nécessiteront Java 8 ou version ultérieure.
Dépendances communes
Dépendances ImageIO
Plugins ImageIO
Plugins ImageIO nécessitant des bibliothèques tierces
Prise en charge de Photoshop Path pour ImageIO
Prise en charge des servlets
Ce projet est fourni sous la licence BSD approuvée par l'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.
Q : Comment puis-je l'utiliser ?
a : Le moyen le plus simple est de créer votre propre projet à l'aide de Maven, Gradle ou d'un autre outil de construction avec gestion des dépendances, et d'ajouter simplement des dépendances aux plug-ins spécifiques dont vous avez besoin. Si vous n'utilisez pas un tel outil de construction, assurez-vous d'avoir tous les JAR nécessaires dans le chemin de classe. Voir la section Installer ci-dessus.
q : Quelles modifications dois-je apporter à mon code pour pouvoir utiliser les plug-ins ?
a : La réponse courte est : Aucun. Pour une utilisation de base, comme ImageIO.read(...)
ou ImageIO.getImageReaders(...)
, il n'est pas nécessaire de modifier votre code. La plupart des fonctionnalités sont disponibles via les API ImageIO standard, et un grand soin a été pris pour ne pas introduire d'API supplémentaire là où aucune n'est nécessaire.
Si vous souhaitez utiliser des fonctionnalités très spécifiques/avancées de certains formats, vous devrez peut-être utiliser des API spécifiques, comme définir l'URL de base pour une image SVG composée de plusieurs fichiers ou contrôler la compression de sortie d'un fichier TIFF.
q : Comment ça marche ?
a : Le projet TwelveMonkeys ImageIO contient des plug-ins pour ImageIO. ImageIO utilise un mécanisme de recherche de service pour découvrir les plug-ins au moment de l'exécution.
Tout ce que vous avez à faire est de vous assurer que vous disposez des fichiers JAR TwelveMonkeys ImageIO dans votre chemin de classe.
Vous pouvez en savoir plus sur le registre et le mécanisme de recherche dans la documentation de l'API IIORegistry.
Les petits caractères : les fournisseurs de services TwelveMonkeys pour JPEG, BMP et TIFF remplacent la méthode onRegistration et utilisent le mécanisme de commande partielle par paire de IIOServiceRegistry
pour s'assurer qu'il est installé avant que Sun/Oracle ne fournisse JPEGImageReader
, BMPImageReader
TIFFImageReader
et Apple. fourni TIFFImageReader
sur OS X, respectivement. L'utilisation du classement par paires ne supprimera aucune fonctionnalité de ces implémentations, mais dans la plupart des cas, vous finirez par utiliser les plug-ins TwelveMonkeys à la place.
q : Pourquoi les formats courants tels que GIF ou PNG ne sont-ils pas pris en charge ?
a : La réponse courte est simplement que la prise en charge intégrée dans ImageIO pour ces formats est considérée comme suffisamment bonne telle quelle. Si vous recherchez de meilleures performances d’écriture PNG sur Java 7 et 8, consultez JDK9 PNG Writer Backport.
q : Quand aura lieu la prochaine version ? Quel est le calendrier de sortie actuel ?
a : L'objectif est de publier des versions mensuelles contenant des corrections de bugs et de nouvelles fonctionnalités mineures. Et des versions trimestrielles avec des fonctionnalités plus « majeures ».
q : J'adore ce projet ! Comment puis-je aider ?
a : Jetez un œil aux problèmes en suspens et voyez s'il y a des problèmes que vous pouvez aider à résoudre, ou fournir un exemple de fichier ou créer des cas de test pour lesquels. Il est également possible pour vous ou votre organisation de devenir sponsor, via GitHub Sponsors. Fournir un financement nous permettra de consacrer plus de temps à la correction des bugs et à la mise en œuvre de nouvelles fonctionnalités.
Q : Et JAI ? Plusieurs formats sont déjà pris en charge par JAI.
a : Bien que JAI (et jai-imageio en particulier) prenne en charge certains des mêmes formats, JAI a des problèmes majeurs. Le plus évident étant :
q : Qu'en est-il de JMagick ou IM4Java ? Ne pouvez-vous pas simplement utiliser ce qui est déjà disponible ?
a : Bien que d'excellentes bibliothèques prennent en charge un large éventail de formats, les bibliothèques basées sur ImageMagick présentent certains inconvénients par rapport à ImageIO.
Nous l'avons fait