
FAQ Java GUIConsultez toutes les FAQ
Nombre d'auteurs : 51, nombre de questions : 152, dernière mise à jour : 21 décembre 2009
Sommaire→Les images- Comment faire une capture d'écran ?
- Comment accéder à une image ?
- Comment enregistrer une image ?
- Comment connaître les types d'images que l'on peut lire ou écrire ?
- Comment mettre une image en fond de JFrame ?
- Comment convertir une image en une instance de BufferedImage ?
- Comment créer un objet de type Image depuis une BufferedImage ?
- Comment convertir une image couleurs en niveaux de gris ?
- Comment rendre floue une image ?
- Comment effectuer des transformations sur une image en mémoire ?
- Comment manipuler directement les pixels de mon image ?
- Qu'est-ce que l'encodage entier RGBA des couleurs d'une image ?
- Comment redimensionner une image ?
- Comment changer l'icone de la fenêtre de mon application ?
- Comment obtenir une Image de mon composant graphique ?
- Comment savoir si une image a des pixels transparents ?
- Comment dessiner et écrire sur une BufferedImage ?
- Comment combiner deux images ?
- Comment utiliser des images compatibles pour améliorer les performances et le rendu ?
La classe java.awt.Robot permet de faire facilement des captures d'écran.
Capture d'une zone :
Robot robot = new Robot();
BufferedImage image = robot.createScreenCapture(new Rectangle( 15, 15, 150, 150));
Capture de tout l'écran :
Robot robot = new Robot();
BufferedImage image = robot.createScreenCapture(
new Rectangle(java.awt.Toolkit.getDefaultToolkit().getScreenSize()) );
Capture d'une fenêtre :
Robot robot = new Robot();
BufferedImage image = robot.createScreenCapture(
new Rectangle( frame.getX(), frame.getY(), frame.getWidth(), frame.getHeight() )
);
Type de fichier supporté :
GIF, JPEG, PNG, BMP et WBMP. Pour lire des images encodées dans d'autres formats, vous devez utiliser une bibliothèque externe.
Dans un applet :
La classe Applet fournit tout le nécessaire pour la lecture d'image :
Image java.applet.Applet.getImage(URL url);
Image java.applet.Applet.getImage(URL url, String name);
Dans une application :
Pour une application (Awt ou Swing), il faut utiliser les méthodes de la classe java.awt.Toolkit
/** Accès au toolkit : */
java.awt.Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit();
/** lecture de l'image : */
Image image = toolkit.getImage("fichier");
Image image = toolkit.getImage(url);
BufferedImage image = ImageIO.read( /* File, URL ou InputStream */ );
A noter qu'avec ImageIO, les images sont complètement chargées lors du retour de la méthode read(), alors que les images renvoyées par le Toolkit sont chargées en arrière plan.
Dans un Jar :
Si l'image se trouve dans une archive, le plus simple est de laisser le ClassLoader trouver le fichier. Cette solution est valable que l'image se trouve ou non dans une archive, il est donc préférable de toujours utiliser le ClassLoader afin de limiter les problèmes lors du déploiement de l'application/applet.
java.net.URL url = getClass().getResource("chemin/nom.gif");
JDK 1.4 :Le JDK1.4 introduit le "imaging I/O framework" qui permet d'écrire des images dans la majorité des formats courants : http://java.sun.com/j2se/1.4/docs/guide/imageio/index.html
JDK antérieur :Java ne permettait pas d'enregistrer une image au format GIF, PNG ou JPEG. Il va falloir faire appel à des classes extérieures permettant le codage de l'image.
- En Java 2, un 'package' est fourni pour enregistrer en JPEG (mais ne fait pas partie des librairies standard) : http://java.sun.com/products/jdk/1.2/docs/guide/2d/api-jpeg/overview-summary.html
- Pour le GIF : http://www.acme.com/java/software/Acme.JPM.Encoders.GifEncoder.html
- Pour le PNG, un encodeur est disponible dans le code source de Batik : http://xml.apache.org/batik
La classe ImageIO du package javax.imageio permet l'accès à ces informations. On peut ainsi connaître les types d'images que l'on peut lire ou écrire en fonction du nom du format, du type MIME ou du suffixe d'un fichier. Voici un exemple :
import javax.imageio.*;
public class FormatsImages{
public static boolean canRead(String format){
boolean type = ImageIO.getImageReadersByFormatName(format).hasNext();
boolean mime = ImageIO.getImageReadersByMIMEType(format).hasNext();
boolean suffixe = ImageIO.getImageReadersBySuffix(format).hasNext();
String infos = "Informations lecture "+format+" : ";
infos+="Format image = "+type+", ";
infos+="MIME = "+mime+", ";
infos+="Suffixe fichier = "+suffixe;
System.out.println(infos);
return type||mime||suffixe;
}
public static boolean canWrite(String format){
boolean type = ImageIO.getImageWritersByFormatName(format).hasNext();
boolean mime = ImageIO.getImageWritersByMIMEType(format).hasNext();
boolean suffixe = ImageIO.getImageWritersBySuffix(format).hasNext();
String infos = "Informations écriture "+format+" : ";
infos+="Format image = "+type+", ";
infos+="MIME = "+mime+", ";
infos+="Suffixe fichier = "+suffixe;
System.out.println(infos);
return type||mime||suffixe;
}
}
Vous pouvez utiliser ces deux méthodes statiques pour vérifier n'importe quel format.
canRead("gif");
canRead("jpg");
canRead("bmp");
canRead("image/jpeg");
//quelques vérifications sur les possibilités de lecture
canWrite("gif");
canWrite("jpg");
canWrite("bmp");
canWrite("image/jpeg");
//quelques vérifications sur les possibilités d'écriture
Vous pouvez avoir accès à tous les types d'images que vous pouvez lire ou écrire grâce aux méthodes getReaderFormatNames et getWriterFormatNames. les mêmes méthodes sont disponibles pour les types MIME.
String[] formatsLecture = ImageIO.getReaderFormatNames();
String[] formatsEcriture = ImageIO.getWriterFormatNames();
//affichage des formats d'images lisibles
System.out.println("Formats d'images disponibles en lecture");
for(int i=0;i<formatsLecture.length;i++){
System.out.println(formatsLecture[i]);
}
System.out.println("Formats d'images disponibles en écriture");
for(int i=0;i<formatsEcriture.length;i++){
System.out.println(formatsEcriture[i]);
}
Lien : Comment accéder à une image ?
Lien : Comment enregistrer une image ?
L'ajout d'image en fond de composant n'est pas possible avec les classes de base de Swing. Heureusement, la réalisation d'une telle classe n'est pas compliquée, il suffit de créer un nouveau composant héritant de JComponent et de surcharger la méthode paintComponent.
La méthode paintComponent(Graphique g) est chargée de dessiner le composant ; les composants fils seront dessinés par dessus plus tard.
Exemple (Swing):
public class MonPanel extends JComponent {
/** variable de classe contenant l'image à afficher en fond */
private Image bg;
/** Surcharge de la fonction paintComponent() pour afficher notre image */
public void paintComponent(Graphics g) {
g.drawImage(bg,0,0,null);
}
}
Exemple (AWT):
public class MonPanel {
/** variable de classe contenant l'image à afficher en fond */
private Image bg;
/** Surcharge de la fonction paint() pour afficher notre image */
public void paint(Graphics g) {
g.drawImage(bg,0,0,null);
}
}
Note :Vous pouvez placer le composant dans la JFrame en utilisant la méthode setContentPane(moncomposant).
Fichier joint :Vous trouvez, dans les liens ci-dessous, un exemple complet d'implémentation d'un tel objet, permettant d'afficher l'image en mosaïque ou centrée.
Téléchargement : Extension de JPanel pour afficher des images en arrière-plan.
Téléchargement : Exemple d'utilisation de la classe.
Beaucoup d'opérations de manipulation d'image ne travaillent que sur des java.awt.image.BufferedImage. La vie étant parfois mal faite, il est courant de trouver dans l'API des méthodes nous retournant des images, mais assez rarement des bufferedImages, il nous faut donc convertir ces images... Voici une méthode qui s'occupe de tout :
BufferedImage toBufferedImage(Image image) {
/** On test si l'image n'est pas déja une instance de BufferedImage */
if( image instanceof BufferedImage ) {
return( (BufferedImage)image );
} else {
/** On s'assure que l'image est complètement chargée */
image = new ImageIcon(image).getImage();
/** On crée la nouvelle image */
BufferedImage bufferedImage = new BufferedImage(
image.getWidth(null),
image.getHeight(null),
BufferedImage.TYPE_INT_RGB );
Graphics g = bufferedImage.createGraphics();
g.drawImage(image,0,0,null);
g.dispose();
return( bufferedImage );
}
}
Cette façon ne préserve pas la transparence de l'image de base.
Comme BufferedImage étend image, on peut tout simplement employer une BufferImage en tant qu'Image.
BufferedImage buf = ...;
Image image = buf;
Les modifications de couleur d'une image sont assurées par la classe java.awt.image.ColorConvertOp qui travaille à partir de java.awt.image.BufferedImage.
ColorConvertOp op = new ColorConvertOp(
ColorSpace.getInstance(ColorSpace.CS_GRAY),
null);
BufferedImage imageGrise = op.filter(bufferedImage,null);
Lien : Comment convertir une image en une instance de BufferedImage ?
L'algorithme permettant de rendre une image floue travaille très simplement : la couleur d'un pixel est calculée en faisant la moyenne pondérée de sa couleur et de celles de ses voisins. Il suffit de modifier les coefficients et le nombre de voisins pour intervenir sur le résultat, plus le poids des voisins est important, plus l'image sera floue. De plus, on peut choisir le poids d'un voisin en fonction de sa position, ce qui permet d'attribuer des poids différents et d'obtenir des résultats surprenants...
float[ ] matrice = {
0.1f, 0.1f, 0.1f,
0.1f, 0.2f, 0.1f,
0.1f, 0.1f, 0.1f
};
BufferedImageOp op = new ConvolveOp(new Kernel(3,3,matrice));
BufferedImage nouvelleImage = op.filter(bufferedImage, null);
Lien : Comment convertir une image en une instance de BufferedImage ?
Il n'est pas possible d'effectuer de transformation directement sur une image mémoire, il faut créer un nouvelle image et dessiner la version transformée dans cette nouvelle image.
/** Création d'une nouvelle image */
BufferedImage nouvelleImage = new BufferedImage(
imageSource.getWidth(),
imageSource.getHeight(),
imageSource.getType());
Graphics2D g2d = nouvelleImage.createGraphics();
/** préparation de la transformation */
AffineTransform at = new AffineTransform();
at.rotate(angle,x,y);
g2d.drawImage(imageSource,at,null);
g2d.dispose();
C'est à mon avis une assez mauvaise idée. Les méthodes de la classe java.awt.Graphics sont généralement des appels directs des fonctions de la carte vidéo ou d'une bibliotheque graphique (DirectX ou autre), bref.
Lecture d'un pixel :
/** Lecture d'un seul pixel : */
int rgb = bufferedImage.getRGB(x,y);
/** Lecture de tous les pixels : */
int w = bufferedImage.getWidth();
int h = bufferedImage.getHeight();
int[] rgbs = new int[w*h]; /** on crée l'espace neccessaire */
bufferedImage.getRGB(0,0,w,h,rgbs,0,w);
Ecriture d'un pixel :
/** Ecriture d'un seul pixel : */
bufferedImage.setRGB(x,y,rgb);
/** Ecriture de tous les pixels : */
int w = bufferedImage.getWidth();
int h = bufferedImage.getHeight();
int[] rgbs = new int[w*h];
bufferedImage.setRGB(0,0,w,h,rgbs,0,w);
Lien : Qu'est-ce que l'encodage entier RGBA des couleurs d'une image ?
Pour des raisons de performance on utilise un seul entier pour coder les trois couleurs primaires (rouge, vert, bleu) et la composante alpha (le niveau de transparence). Chaque composante est codée sur 8 bits (bleu 0-7, vert 8-15, rouge 16-23, alpha 24-31).
/** Lecture manuelle des composantes : */
int rgb = bufferedImage.getRGB(x,y);
int alpha = (rgb >>24 ) & 0xFF;
int rouge = (rgb >>16 ) & 0xFF;
int vert = (rgb >> 8 ) & 0xFF;
int bleu = rgb & 0xFF;
/** Construction d'un pixel : */
int rgb = (alpha<<24)+(rouge<<16)+(vert<<8)+bleu;
/** Les composantes doivent obligatoirement être comprises dans l'intervalle 0-255 */
Lien : Comment manipuler directement les pixels de mon image ?
Redimensionnemant d'une image :
/**
* Redimensionne une image.
*
* @param source Image à redimensionner.
* @param width Largeur de l'image cible.
* @param height Hauteur de l'image cible.
* @return Image redimensionnée.
*/
public static Image scale(Image source, int width, int height) {
/* On crée une nouvelle image aux bonnes dimensions. */
BufferedImage buf = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
/* On dessine sur le Graphics de l'image bufferisée. */
Graphics2D g = buf.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(source, 0, 0, width, height, null);
g.dispose();
/* On retourne l'image bufferisée, qui est une image. */
return buf;
}
Redimensionnemant d'une BufferedImage :
/** Effectue une homothétie de l'image.
*
* @param bi l'image.
* @param scaleValue la valeur de l'homothétie.
* @return une image réduite ou agrandie.
*
*/public static BufferedImage scale(BufferedImage bi, double scaleValue) {
AffineTransform tx = new AffineTransform();
tx.scale(scaleValue, scaleValue);
AffineTransformOp op = new AffineTransformOp(tx,
AffineTransformOp.TYPE_BILINEAR);
BufferedImage biNew = new BufferedImage( (int) (bi.getWidth() * scaleValue),
(int) (bi.getHeight() * scaleValue),
bi.getType());
return op.filter(bi, biNew);
}
Note :Un coefficient supérieur à 1 correspond à un agrandissement, un coefficient inférieur à 1 correspond à une réduction.
L'icone d'une application apparaît à divers endroits en fonction du système d'exploitation. Sous windows, on la retrouve en haut à gauche de la fenêtre, et dans la barre des taches. Par défaut, il s'agit de la tasse de café de Java. Il est très facile de la personnaliser en utilisant la méthode setIconImage(java.awt.Image) des classes javax.swing.JFrame.
Cette méthode n'est pas disponible pour la classe JDialog, les dialogues utilisent automatiquement l'icone de la frame parente.
Image icone = Toolkit.getDefaultToolkit().getImage("./monImage.jpg");
maFenetre.setIconImage(icone);
Si l'image n'apparaît pas, c'est certainement que le paramètre image a une valeur 'null'.
Une autre raison pour laquelle cette image n'apparaitrait serait un problème au niveau de la transparence avec les images PNG qui ne sont pas gérés par tous les OS, certains OS vont l'afficher mais supprimmer la transparence et d'autres ne pas l'afficher.
De plus, certains OS ne supportent simplement pas les images de type PNG, transparence ou non.
La classe Component a la capacité de peindre l'intégralité de son contenu dans un Graphics, grâce à la méthode paintAll.
Voici une méthode permettant de récuperer l'Image d'un Component quelconque :
public Image getImage(Component component){
if(component==null){return null;}
int width = component.getWidth();
int height = component.getHeight();
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
component.paintAll(g);
g.dispose();
return image;
}
Cette information est relativement simple à obtenir si l'on travaille avec une instance de BufferedImage. Si c'est le cas, on peut directement demander au ColorModel de l'image de nous donner l'information. Dans le cas contraire, on est obligé de passer par un PixelGrabber.
Voici une méthode permettant de récuperer cette information quelque soit le type de l'image :
public boolean alphaLayer(Image image){
ColorModel modele = null;
if(image instanceof BufferedImage){
// si on a affaire à une BufferedImage on regarde son ColorModel
BufferedImage bi = (BufferedImage)image;
modele = bi.getColorModel();
}else {
// on traite l'image pixel par pixel afin de récuperer un ColorModel
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
try{
// on découpe donc l'image pixel par pixel
pg.grabPixels();
}catch (InterruptedException e) {
e.printStackTrace();
}
modele = pg.getColorModel();
}
return modele.hasAlpha();
}
// on crée auparavant la BufferedImage avec le nom bi
Graphics2D g2d = bi.createGraphics(); // on récupère le contexte graphique de la BufferedImage
g2d.setColor( Color.red ); // on met l'état de couleur rouge à la BufferedImage
g2d.fillOval( 30, 30, 100, 100 ); // on dessine un cercle de centre x=30 y=30 et de rayon=100
g2d.dispose(); //on libère la mémoire utilisée pour le contexte graphique
Si vous ne faites pas de dispose() sur le contexte graphique et que vous rafraichissiez beaucoup celui-ci durant l'utilisation du programme, votre programme sera de plus en plus gourmant en mémoire.
Pour combiner 2 images, il suffit de dessinner la deuxième image sur la première image. Pour cela, il faut récupérer le Graphics2D de la première image et ensuite configurer l'anti-aliasing et la interpolation sur le Graphics2D. On peut ensuite tout simplement dessinner la deuxième image sur la première à l'endroit voulu.
Voilà donc ce que ça donne :
public static BufferedImage addImage(BufferedImage image1, BufferedImage image2){
Graphics2D g2d = image1.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.drawImage(image2, 0, 0, null);
g2d.dispose();
return image1 ;
}
Lorsque vous utilisez des BufferedImage, il est important d'utiliser ce qu'on nomme des images compatibles.
Qu'est-ce que c'est ?
Ce sont des images qui sont déja dans le bon format pour le périphérique d'affichage. Elles sont de types BufferedImage et ont certains avantages au niveau de la performance.
Qu'est-ce que ça change ?
Ce type d'image étant directement adapté au rendu sur le périphérique d'affichage utilisé, elles nécessitent moins de code Java2D pour être affichées.
Comment les utiliser ?
L'utilisation de telles images est très simples. Il faut passer par la classe GraphicsConfiguration pour en obtenir une. Voici une méthode permettant de créer une nouvelle image compatible vide :
/**
* Create a compatible image.
*
* @param width The width.
* @param height The height.
* @param type The type of the image.
* @return A compatible image.
*/
private static BufferedImage createCompatibleImage(int width, int height, int type) {
GraphicsConfiguration gc = GraphicsEnvironment.
getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
return gc.createCompatibleImage(width, height, type);
}
Et voici une méthode permettant de convertir une image existante en image compatible :
/**
* Create a compatible image from an existing image.
*
* @param image The image to make compatible.
* @return A compatible image filled with the base image.
*/
public static BufferedImage createCompatibleImage(BufferedImage image) {
GraphicsConfiguration gc = GraphicsEnvironment.
getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
if (image.getColorModel().equals(gc.getColorModel())) {
return image;
} else {
BufferedImage compatibleImage = gc.createCompatibleImage(image.getWidth(), image.getHeight(),
image.getTransparency());
Graphics g = compatibleImage.getGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return compatibleImage;
}
}
On commence par tester si le modèle de couleur de l'image n'est pas déja le bon pour ne pas faire de travail dans le vide. Ensuite, on créer une nouvelle image compatible et on dessinne l'ancienne image sur la nouvelle.


















