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 :

Chargement d'images -> Performances


Sujet :

AWT/Swing Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2005
    Messages
    277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39

    Informations forums :
    Inscription : Avril 2005
    Messages : 277
    Par défaut Chargement d'images -> Performances
    Bonjour,

    Je suis confronté à un problème de performances ... J'explique le cas ...

    Dans mon application, je suis ammené a travailler sur pas mal d'images, notament pour ce qui est des boutons, etc ... J'ai donc ces images en plusieures tailles, et parfois avec un effet de survol pour faire plus beau ...

    Ainsi vous comprendrez que pour 1 image de base, j'en ai vite 6 (1 image * 3 tailles * 2 effets) ...

    Voici comment je les charge a l'heure actuelle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public ImageIcon charger_image(String fichier) {
        ImageIcon retour = null;
        try{
          retour = new ImageIcon(this.getClass().getClassLoader().getResource(fichier));
        }catch (Exception e){}
        return retour;
      }
    J'ai voulu optimiser la chose en divisant donc mon nombre d'images par 6 ... A savoir :
    -> 1 seule image en taille la plus grande
    -> 1 image pour mon effet de survol, en PNG avec transparence ...

    Et lors du chargement je lui donne l'image, la taille, et l'effet que je veux ... Ainsi j'ai rajouté du FLOU, du niveau de gris, etc ...

    Voila ma méthode :
    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    public ImageIcon sp_charger_image(String image,int taille, int effet) {
     
        BufferedImage img = new BufferedImage(taille,taille,BufferedImage.TYPE_INT_ARGB);
     
        try {
          ImageIcon img_ico = sp_charger_image( sp_image );
          Graphics2D g2d = img.createGraphics();
     
          g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                               RenderingHints.VALUE_INTERPOLATION_BICUBIC);
     
          if(img_ico.getIconWidth() != taille) {
            Double rapport = new Double(taille) / new Double(img_ico.getIconWidth());
            g2d.scale( rapport, rapport );
          }
     
          g2d.drawImage( img_ico.getImage(), 0, 0, null );
     
          switch (effet) {
            case ROLLOVER:
              g2d.drawImage( sp_charger_image( "RollOver.png" ).getImage(), 0, 0, null );
              break;
            case GRIS:
              img = new ColorConvertOp( ColorSpace.getInstance(ColorSpace.CS_GRAY), null).filter(img,null);
              break;
            case LOU:
              float[] flou = { 0.1f, 0.1f, 0.1f, 0.1f, 0.2f, 0.1f, 0.1f, 0.1f, 0.1f };
              img = new ConvolveOp(new Kernel(3,3,flou )).filter(img, null);
              break;
            case CLAIR:
              float[] clair = { 0f, 0f, 0f, 0f, 1.2f, 0f, 0f, 0f, 0f };
              img = new ConvolveOp(new Kernel(3,3,clair )).filter(img, null);
              break;
            case SOMBRE:
              float[] sombre = { 0f, 0f, 0f, 0f, 0.8f, 0f, 0f, 0f, 0f };
              img = new ConvolveOp(new Kernel(3,3,sombre )).filter(img, null);
              break;
            default:
              break;
          }
     
          g2d.dispose();
     
        }catch(Exception e) {e.printStackTrace();}
     
        return new ImageIcon(img);
      }
    Mais apres quelques tests de performance, ma seconde méthode est moins éfficace ...

    Est-il possible de l'améliorer afin qu'elle soit plus éfficace ??? Si oui comment ?

    Je pensait peut être charger les images 1 fois, puis les mettre dans une hashtable et ne pas les recharger completement à la seconde utilisation, mais juste les prendre dans la hashtable ... Ca serait mieux ?

    Merci à vous ...

    Des que je peux je met a dispo une archive qui fonctionnera avec code + images pour tester !

    MErci à vous !!!

    PS : En pièce jointe un ZIP qui peut être renommé en JAR ! Et qui contient les sources !

  2. #2
    Membre Expert
    Avatar de gifffftane
    Profil pro
    Inscrit en
    Février 2007
    Messages
    2 354
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Février 2007
    Messages : 2 354
    Par défaut
    Je ne peux pas te répondre de façon précise, juste te donner une piste : regarde la page de Chris Campbell, qui donne plein de conseils sur les effets d'image, particulièrement The Perils of Image.getScaledInstance(), où il fait des comparatifs de vitesse entre différentes solutions.

  3. #3
    Membre émérite
    Profil pro
    Inscrit en
    Février 2007
    Messages
    572
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Février 2007
    Messages : 572
    Par défaut
    Il est effectivement normal que ca prenne plus de temps dans le cas ou tu construis tes images, mais la mesure n'est pas tres representative.

    Dans le premier cas, les images seront chargées une seule fois. Tu crees plusieurs ImageIcon, mais elles vont referencer les memes images. En gros tu ne construis que les 6 images de bases.

    Dans le deuxieme cas, tu recrees une image a chaque appel (et evidemment un ImageIcon). En bref tu crees 48x60 images.

    Il faut comme tu l'as suggeré utiliser une Hashtable pour stocker les images déjà produites.

    Qqs autres petites remarques :
    - pour la mesure du temps pour les perfs, utilises plutot System.currentTimeMillis()
    - pour le chargement d'un image, regardes javax.imageio.ImageIO.read()
    - pour calculer le facteur d'echelle, ecris plutot double factor = (double) taille/ (double) image.getWith(), au lieu de passer par des objets Double.

  4. #4
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2005
    Messages
    277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39

    Informations forums :
    Inscription : Avril 2005
    Messages : 277
    Par défaut
    Ok, merci beaucoup ...

    Après des tests, modifs, etc ...

    J'ai du mieux, mais pas encore du TOP ...

    J'ai réussi, grâce a
    --> mettre en BILINEAR au lieu de BICUBIC l'interpolation
    --> faire une HashMap avec les imagesIcon utilisées pour pas les charegr plusieures fois

    D'avoir un gain de performances d'environs 25% ...

    Mais ce gain est pour les 2 méthodes ... Ainsi la méthode 2, donc celle qui charge TOUTES les images reste plus rapide et je ne comprends pas !!!

    Methode 1 : environs 1000 ms de durée d'éxécution et 38Mo en mémoire
    Methode 2 : environs 400 ms de durée d'éxécution et 26Mo en mémoire

    Je ne comprends PAS !!! Ca devrait être l'inverse !!!

    J'ai essayé le ImageIO.read() ... en remplacant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public ImageIcon charger_image(String nomfic) {
        ImageIcon retour = list_img.get( nomfic );
        if(retour == null) {
          try {
            retour = new ImageIcon( this.getClass().getClassLoader().getResource( "img/" + nomfic ) );
            list_img.put( nomfic, retour );
          }catch (Exception e) {
            e.printStackTrace();
          }
        } 
        return retour;
      }
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public BufferedImage charger_buffimage(String nomfic) {
        BufferedImage retour = list_buffimg.get( nomfic );
        if(retour == null) {
          try {
            retour = ImageIO.read( new File("img/"+nomfic) );
            list_buffimg.put( nomfic, retour );
          }catch (Exception e) {
            e.printStackTrace();
          }
        } 
        return retour;
      }
    Mais c'est encore pire coté performances ...

    Je dois passer à coté d'un truc, mais lequel ?

    Je redonne les sources modifiées au cas ou quelqu'un puisse aider ^^
    Fichiers attachés Fichiers attachés

  5. #5
    Membre émérite
    Profil pro
    Inscrit en
    Février 2007
    Messages
    572
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Février 2007
    Messages : 572
    Par défaut
    Il faut comprendre que lorsque tu fais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    ImageIcon icon1 = new ImageIcon("image.png");
    ImageIcon icon2 = new ImageIcon("image.png");
    L'image "image.png" n'est decompressée qu'une seule fois. En fait swing (ou a mon avis awt) conserve dans une table la liste des images.
    Donc il faut un peu de temps pour decompresser l'image lors de la creation de icon1, mais rien (ou presque) pour la creaiton de icon2.
    C'est ce qui se passe dans ta methode 2. Il n'y a en fait que 6 decompressions, et donc 6 images differentes. Tout le reste, c'est de la simple creation d'objet (des ImageIcon), qui ont une reference vers ces images.

    Dans la methode 1, tu crees des BufferedImage a chaque fois. Forcement, ca coute un peu de temps. Et tu fais les transformations systematiquement.
    En fait, ce qu'il faut que tu utilises comme clé dans ta Hashtable, c'est une combinaison entre le nom de l'image d'origne, la taille, et l'effet.
    Quelque chose du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String key = filename+"_"+taille+"_"+effet;
    L'idee, c'est que tu ne feras qu'une seule fois la transformation, ce qui est alors comparable a ce qui est fait dans la methode 2.

  6. #6
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Avril 2005
    Messages
    277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39

    Informations forums :
    Inscription : Avril 2005
    Messages : 277
    Par défaut
    Yesssssssssssssssss

    TROP BIEN JOUE !!!!

    MErci ca roule bien maintenant ... Même ressources mémoire et aussi même temps d'exécution ^^

    YOUPIIIIIIIIIIIIIIIIIIIIII

    Encore quelques conseils SVP :

    Est-il possible d'optimiser mon code, peut êtres petites choses que je vois pas, cette méthode sera peut être la plus utilisée de ma librairie donc faut qu'elle soit nickel ! lol

    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    public ImageIcon charger_image(String nomfic) {
        ImageIcon retour = list_img.get( nomfic );
        if(retour == null) {
          try {
            retour = new ImageIcon( this.getClass().getClassLoader().getResource( "img/" + nomfic ) );
            list_img.put( nomfic, retour );
          }catch (Exception e) {
            e.printStackTrace();
          }
        } 
        return retour;
      }
     
      public ImageIcon charger_image(String image, int taille, int effet) {
        String w_key = taille + "_" + SP_EFFETS[effet] + "_" + image;
        BufferedImage img = list_buffimg.get( w_key );
     
        if(img == null) {
     
          img = new BufferedImage( taille, taille, BufferedImage.TYPE_INT_ARGB );
          ImageIcon img_ico = null;
          Graphics2D g2d    = null;
     
          try {
            img_ico = charger_image( image );
            g2d = img.createGraphics();
     
            g2d.setRenderingHint( RenderingHints.KEY_INTERPOLATION,
                                  RenderingHints.VALUE_INTERPOLATION_BILINEAR );
     
            if (img_ico.getIconWidth() != taille) {
              Double w_rapport = (double) taille / (double) img_ico.getIconWidth();
              g2d.scale( w_rapport, w_rapport ); 
            }
     
            g2d.drawImage( img_ico.getImage(), 0, 0, null );
     
            switch (effet) {
              case SP_ROLLOVER:
                g2d.drawImage( charger_image( "32_RO2.png" ).getImage(), 0, 0, null );
                break;
              case SP_GRIS:
                img = new ColorConvertOp( ColorSpace.getInstance( ColorSpace.CS_GRAY ), null ).filter( img,null );
                break;
              case SP_FLOU:
                float[] flou = { 0.1f, 0.1f, 0.1f, 0.1f, 0.2f, 0.1f, 0.1f, 0.1f, 0.1f };
                img = new ConvolveOp( new Kernel( 3, 3, flou ) ).filter( img, null );
                break;
              case SP_CLAIR:
                float[] clair = { 0f, 0f, 0f, 0f, 1.2f, 0f, 0f, 0f, 0f };
                img = new ConvolveOp( new Kernel( 3, 3, clair ) ).filter( img, null );
                break;
              case SP_SOMBRE:
                float[] sombre = { 0f, 0f, 0f, 0f, 0.8f, 0f, 0f, 0f, 0f };
                img = new ConvolveOp( new Kernel( 3, 3, sombre ) ).filter( img, null );
                break;
              default:
                break;
            }
            list_buffimg.put( w_key, img );
            g2d.dispose();
          } catch (Exception e) {
            e.printStackTrace();
          } finally {
            g2d     = null;
            img_ico = null;
          }
        }
        return new ImageIcon( img );
      }
    Et la je suis pas sur de mon coup ... TOUTES les ressources sont bien libèrées quand je fait ca ?

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

Discussions similaires

  1. thumbnail et chargement d'image
    Par nabil dans le forum VB 6 et antérieur
    Réponses: 1
    Dernier message: 02/01/2006, 13h27
  2. [xhtml][css] chargement d'image sur IE
    Par killgors dans le forum Mise en page CSS
    Réponses: 4
    Dernier message: 23/08/2005, 20h37
  3. chargement d'image
    Par bakonu dans le forum AWT/Swing
    Réponses: 2
    Dernier message: 20/06/2005, 22h40
  4. [JLabel] Chargement d'image dans une JFrame
    Par mr.t dans le forum Composants
    Réponses: 10
    Dernier message: 27/01/2005, 18h32
  5. Réponses: 21
    Dernier message: 29/04/2004, 15h45

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