IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

AWT/Swing Java Discussion :

redimensionner une image assez grosse


Sujet :

AWT/Swing Java

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    48
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 48
    Par défaut redimensionner une image assez grosse
    Salut!

    J'ai fait un petit programme dans lequel je dois redimensionner une photo choisie dans le système de fichier. Ma méthode pour redimensionner l'image ressemble à ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public Image redimensionnerImage(Image im){
    		return im.getScaledInstance(80,120,Image.SCALE_DEFAULT);
    	}
    Mais j'ai de très mauvaises performances, en particulier sur les grosses photos (en terme de nombre de pixels plus que de taille sur le disque apparemment), le redimensionnement prend facilement une petite dizaine de secondes sur des photos de coté 500 ou 600 pixels environs, et pour les photos qui vont chercher dans les plus 1000*1000 pixels, ca travaille carrément un moment avant de me sortir cette erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    Exception during event dispatch:
    java.lang.ArrayIndexOutOfBoundsException: 9600
       at gnu.java.awt.peer.gtk.GtkImageConsumer.setPixels(lib-gnu-java-awt-peer-gtk.so.7)
       at java.awt.image.ReplicateScaleFilter.setPixels(libgcj.so.7)
       at java.awt.image.BufferedImage$1.startProduction(libgcj.so.7)
       at java.awt.image.FilteredImageSource.startProduction(libgcj.so.7)
       at gnu.java.awt.peer.gtk.GtkImage.<init>(lib-gnu-java-awt-peer-gtk.so.7)
       at gnu.java.awt.peer.gtk.GtkToolkit.createImage(lib-gnu-java-awt-peer-gtk.so.7)
       at java.awt.Image.getScaledInstance(libgcj.so.7)
       at carteMakerFrame.redimensionnerImage(carteMaker.java:484)
       at carteMakerFrame.actionPerformed(carteMaker.java:310)
       at javax.swing.AbstractButton.fireActionPerformed(libgcj.so.7)
       at javax.swing.AbstractButton$1.actionPerformed(libgcj.so.7)
       at javax.swing.DefaultButtonModel.fireActionPerformed(libgcj.so.7)
       at javax.swing.DefaultButtonModel.setPressed(libgcj.so.7)
       at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(libgcj.so.7)
       at java.awt.Component.processMouseEvent(libgcj.so.7)
       at java.awt.Component.processEvent(libgcj.so.7)
       at java.awt.Container.processEvent(libgcj.so.7)
       at java.awt.Component.dispatchEventImpl(libgcj.so.7)
       at java.awt.Container.dispatchEventImpl(libgcj.so.7)
       at java.awt.Component.dispatchEvent(libgcj.so.7)
       at java.awt.LightweightDispatcher.handleEvent(libgcj.so.7)
       at java.awt.Container.dispatchEventImpl(libgcj.so.7)
       at java.awt.Window.dispatchEventImpl(libgcj.so.7)
       at java.awt.Component.dispatchEvent(libgcj.so.7)
       at java.awt.EventQueue.dispatchEvent(libgcj.so.7)
       at java.awt.EventDispatchThread.run(libgcj.so.7)
    Est-ce que qqn connait une méthode plus légère pour redimensionner les images ?
    Merci...

  2. #2
    Membre chevronné
    Avatar de Orian
    Inscrit en
    Août 2006
    Messages
    372
    Détails du profil
    Informations personnelles :
    Âge : 36

    Informations forums :
    Inscription : Août 2006
    Messages : 372

  3. #3
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Mouaip mieux vaut ne pas uttiliser le getScaledInstance qui est 100% software et bouffe paquet de mémoire

    utilise quelque chose dans ce style plutôt:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    Image imageAReduire = ...;
    // ...
    BufferedImage image = new BufferedImage(BufferedImage.TYPE_INT_ARGB, imageAReduire.getWidth(null), imageAReduire.getHeight(null));
    Graphics2D g2 = image.createGraphics();
    g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    g2.drawImage(imageAReduire, 0, 0, nouvelleLargeur, nouvelleHauteur, null);
    g2.dispose();
    imageAReduire = image;
    Ensuite tu n'utilises pas la JVM standard mais celle de GNU Classpath (GCJ) qui peut causer des problèmes à ce niveau là...

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    48
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 48
    Par défaut
    merci sinok jvais essayer ca jvous redis

    la méthode de la faq avec getScaledInstance prend autant de temps, mais ne fonctionne pas et me donne un joli "Aborted".

  5. #5
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Je répète le post précédent avec un peu plus de précisions: c'est dû au fait que getScaledInstance est très couteux au niveau ressources (il n'utilise pas la carte vidéo pour faire les manips) et que tu utilises une JVM pas fontionnelle à 100% même si elle n'est est pas loin.

    D'ailleurs vu que tu fais du swing tu risques de tomber rapidement sur des problèmes car swing marche realivement mal avec Gcj, même si ça s'est amélioré dernièrement avec la mise en place d'une correspondance en les Graphics/Graphics2D et pango et cairo.

  6. #6
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Citation Envoyé par ratakses
    la méthode de la faq avec getScaledInstance prend autant de temps, mais ne fonctionne pas et me donne un joli "Aborted".
    La méthode de la FAQ est mauvaise, utilise celle de sinok

  7. #7
    Gfx
    Gfx est déconnecté
    Expert confirmé
    Avatar de Gfx
    Inscrit en
    Mai 2005
    Messages
    1 770
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 770
    Par défaut
    Il y a mieux encore. La méthode ci-dessous fournit un résultat plus joli que la méthode simple proposée par sinok. Le temps d'exécution est comparable (sur mon dernier test, cela prenait quelques millisecondes de plus que la méthode simple : 15ms au lieu de ~12/10ms sur une image en 640x480 redimensionnée à 120 pixels de large).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
       public static BufferedImage createThumbnail(BufferedImage image, int requestedThumbSize) {
            float ratio = (float) image.getWidth() / (float) image.getHeight();
            int width = image.getWidth();
            boolean divide = requestedThumbSize < width;
            BufferedImage thumb = image;
     
            do {
                if (divide) {
                    width /= 2;
                    if (width < requestedThumbSize) {
                        width = requestedThumbSize;
                    }
                } else {
                    width *= 2;
                    if (width > requestedThumbSize) {
                        width = requestedThumbSize;
                    }
                }
     
                BufferedImage temp = new BufferedImage(width, (int) (width / ratio),
                                                       image.getType());
                Graphics2D g2 = temp.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                                    RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                g2.drawImage(thumb, 0, 0, temp.getWidth(), temp.getHeight(), null);
                g2.dispose();
     
                thumb = temp;
            } while (width != requestedThumbSize);
     
            return thumb;
        }

  8. #8
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Citation Envoyé par Gfx
    Il y a mieux encore. La méthode ci-dessous fournit un résultat plus joli que la méthode simple proposée par sinok. Le temps d'exécution est comparable (sur mon dernier test, cela prenait quelques millisecondes de plus que la méthode simple : 15ms au lieu de ~12/10ms sur une image en 640x480 redimensionnée à 120 pixels de large).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
       public static BufferedImage createThumbnail(BufferedImage image, int requestedThumbSize) {
            float ratio = (float) image.getWidth() / (float) image.getHeight();
            int width = image.getWidth();
            boolean divide = requestedThumbSize < width;
            BufferedImage thumb = image;
     
            do {
                if (divide) {
                    width /= 2;
                    if (width < requestedThumbSize) {
                        width = requestedThumbSize;
                    }
                } else {
                    width *= 2;
                    if (width > requestedThumbSize) {
                        width = requestedThumbSize;
                    }
                }
     
                BufferedImage temp = new BufferedImage(width, (int) (width / ratio),
                                                       image.getType());
                Graphics2D g2 = temp.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                                    RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                g2.drawImage(thumb, 0, 0, temp.getWidth(), temp.getHeight(), null);
                g2.dispose();
     
                thumb = temp;
            } while (width != requestedThumbSize);
     
            return thumb;
        }
    J'avoue avoir du mal à distinguer la différence entre les 2 méthodes, c'est quoi qui change vraiment?...

  9. #9
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    ça tient dans l'utilisation du redering hintet de la multiplication des étapes, ce rendering hint matrche bien pour des images de destination faisant la moitié de l'image source en taille si je ne m'abuse...

    Par contre cette méthode oblige à travailler avec des tailles de destination paires (je chipote je sais) car la division par deux donnera forcément un nombre pair donc mieux vaudrait un

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    do{
    ...
    }while (width >= requestedThumbSize);

  10. #10
    Gfx
    Gfx est déconnecté
    Expert confirmé
    Avatar de Gfx
    Inscrit en
    Mai 2005
    Messages
    1 770
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 770
    Par défaut
    En divisant la taille par 2 jusqu'à atteindre la taille cible on obtient un résultat plus lissé. Un simple redimensionnement bilinéaire peut donner un résultat presque identique à un pixel resize quand tu pars d'une grande image pour atteindre une petite image. De même pour le bicubique (qui est de toute façon lent). J'ai présenté cette technique à JavaPolis 2005 et chez Sun en décembre 2005 (vidéo ici : http://java.developpez.tv/javadesktop-dec2005/#Part21 -- la manipulation d'images). La vidéo devrait présenter la démo qui montre les différences entre les deux techniques.

    J'ai joint deux image à cette réponse : mipmap.png et nomipmap.png. La première utilise ma technique, la seconde celle présentée par sinok. Tu verras que la version nomipmap présente des effets d'aliasing marqué sur les zones contrastées (par exemple sommet de la colline de la première photo). Idéalement, ma technique devrait être combiné à une opération de sharpening doux pour améliorer la qualité finale.

    @sinok : Tu as mal lu mon code ! Regarde le début de la boucle... tu verras que si la taille cible est dépassée, les valeurs sont ajustés pour que la boucle s'arrête et que l'image ait la bonne taille. J'ai utilisé cette méthode dans plusieurs programmes (dont http://aerith.dev.java.net) qui chargent des images de toutes tailles et tous ratio et cela marche parfaitement :p
    Images attachées Images attachées   

  11. #11
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    oups

  12. #12
    Expert confirmé
    Avatar de le y@m's
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2005
    Messages
    2 636
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Février 2005
    Messages : 2 636
    Par défaut
    Il serait bon de modifier la FAQ .
    Je ne répondrai à aucune question technique par MP.

    Pensez aux Tutoriels et aux FAQs avant de poster ;) (pour le java il y a aussi JavaSearch), n'oubliez pas non plus la fonction Rechercher.
    Enfin, quand une solution a été trouvée à votre problème
    pensez au tag :resolu:

    Cours Dvp : http://ydisanto.developpez.com
    Blog : http://yann-disanto.blogspot.com/
    Page perso : http://yann-disanto.fr

  13. #13
    Membre chevronné
    Avatar de Orian
    Inscrit en
    Août 2006
    Messages
    372
    Détails du profil
    Informations personnelles :
    Âge : 36

    Informations forums :
    Inscription : Août 2006
    Messages : 372
    Par défaut
    ouaip, pour éviter à des gens bien intentionné comme moi d'encoyer des aides qui ne servent à rien

  14. #14
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    48
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 48
    Par défaut
    Merci pour vos réponses!

    Bon d'une part c'est vrai que j'utilisais gcj à la place du jdk sun sans avoir rien remarqué depuis le début que je faisais mon programme (n'est pas très malin qui veut). Sinon j'ai utilisé la méthode de Gfx, qui effectivement fonctionne très bien
    J'ai encore 2-3 petits problèmes (du genre mon image réaffiche à moitié le bouton d'à côté jusqu'à ce que je redimensionne la fenêtre), mais ça c'est plutot dû au fait que je sais pas encore utiliser swing correctement

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [VB.NET] Redimensionner une image dans un PictureBox
    Par Monster77 dans le forum Windows Forms
    Réponses: 6
    Dernier message: 05/04/2007, 18h24
  2. [32 bits] Redimensionner une image JPEG/GIF/PNG...
    Par CR_Gio dans le forum x86 32-bits / 64-bits
    Réponses: 2
    Dernier message: 04/10/2005, 00h57
  3. Redimensionner une image...
    Par RhaZieL dans le forum VB 6 et antérieur
    Réponses: 12
    Dernier message: 22/07/2005, 09h30
  4. [VB.NET] Redimensionner une image proportionnelement
    Par Monster77 dans le forum Windows Forms
    Réponses: 3
    Dernier message: 19/10/2004, 12h10
  5. [MX2004] redimensionner une image lors du chargement
    Par ouinouin dans le forum Flash
    Réponses: 8
    Dernier message: 18/02/2004, 18h32

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo