Je suggère de regarder dans l'API Java Advanced Imaging (JAI). Vous utilisez probablement BufferedImage en ce moment, qui garde tout en mémoire: les images source ainsi que les images de sortie. Ceci est connu comme traitement "en mode immédiat". Lorsque vous appelez une méthode pour redimensionner l'image, cela arrive immédiatement. Par conséquent, vous gardez toujours les images en mémoire.
Avec JAI, vous bénéficiez de deux avantages.
- Traitement en mode différé.
- Calcul de carreaux.
Le mode différé signifie que les images de sortie ne sont pas calculées correctement lorsque vous appelez des méthodes sur les images. Au lieu de cela, un appel à redimensionner une image crée un petit objet "opérateur" qui peut effectuer le redimensionnement plus tard. Cela vous permet de construire des chaînes, des arbres ou des pipelines d'opérations. Ainsi, votre travail permettrait de construire un arbre d'opérations comme "recadrer, redimensionner, composite" pour chaque image de stock.La bonne partie est que les opérations ne sont que des objets de commande, donc vous ne consommez pas toute la mémoire pendant que vous construisez vos commandes.
Cette API est basée sur le pull. Il reporte le calcul jusqu'à ce que l'action de sortie tire pixels des opérateurs. Cela permet de gagner rapidement du temps et de la mémoire en évitant les opérations inutiles sur les pixels. Par exemple, supposons que vous ayez besoin d'une image de sortie de 2048 x 2048 pixels, mise à l'échelle à partir d'une image 512x512 issue d'une image source de 1600x512 pixels. Évidemment, cela n'a aucun sens d'agrandir l'image source entière de 1600x512, juste pour jeter les 2/3 des pixels. Au lieu de cela, l'opérateur de mise à l'échelle aura une "région d'intérêt" (ROI) basée sur ses dimensions de sortie. L'opérateur de mise à l'échelle projette le ROI sur l'image source et calcule uniquement ces pixels.
Les commandes doivent éventuellement être évaluées. Cela se produit dans quelques situations, principalement liées à la sortie de l'image finale. Donc, demander une BufferedImage pour afficher la sortie sur l'écran forcera toutes les commandes à évaluer. De même, l'écriture de l'image de sortie sur le disque force l'évaluation.
Dans certains cas, vous pouvez conserver le second avantage de JAI, qui est le rendu basé sur les vignettes. Tandis que BufferedImage effectue tout son travail immédiatement, sur tous les pixels, le rendu des vignettes ne fonctionne que sur des sections rectangulaires de l'image à la fois. En utilisant l'exemple d'avant, l'image de sortie 2048x2048 sera divisée en mosaïques. Supposons que ceux-ci sont 256x256, alors l'image entière est divisée en 64 tuiles. Les objets opérateurs JAI savent comment travailler une tuile sur une tuile. Ainsi, la mise à l'échelle de la section 512x512 de l'image source se produit réellement 64 fois sur des pixels source 64x64 à la fois.
Calculer une tuile à la fois signifie faire une boucle sur les tuiles, ce qui semblerait prendre plus de temps. Cependant, deux choses fonctionnent en votre faveur lors du calcul de tuiles. Tout d'abord, les tuiles peuvent être évaluées simultanément sur plusieurs threads. Deuxièmement, l'utilisation de la mémoire transitoire est beaucoup, beaucoup plus faible que le calcul du mode immédiat.
Tout ce qui est une longue explication pourquoi vous voulez utiliser JAI pour ce type de traitement d'image.
Quelques notes et mises en garde:
- Vous pouvez vaincre le rendu à base de tuiles sans le savoir. Partout où vous avez un BufferedImage dans le flux de travail, il ne peut pas agir comme une source de tuile ou un puits.
- Si vous effectuez un rendu sur disque à l'aide des opérateurs d'E/S d'image JAI ou JAI pour JPEG, vous êtes en bon état. Si vous essayez d'utiliser les classes d'image intégrées du JDK, vous aurez besoin de toute la mémoire. (Fondamentalement, évitez de mélanger les deux types de manipulation d'image.Le mode immédiat et le mode différé ne se mélangent pas bien.)
- Tous les trucs fantaisie avec les ROI, les tuiles et le mode différé sont transparents pour le programme. Vous venez de faire un appel d'API sur la classe JAI. Vous ne traitez avec la machine que si vous avez besoin de plus de contrôle sur des choses comme la taille des tuiles, la mise en cache et la concurrence.