2 votes

Est-ce que g.drawImage() rend seulement la partie de l'image visible sur un JPanel, ou "garde-t-il en mémoire" le reste de l'image?

Supposons que nous avons le code suivant :

(dans une classe qui étend JPanel) :

public void paintComponent(Graphics g) {
    g.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null);
}

Si dx1 et dy1 sont négatifs ou si dx2 et dy2 sont plus grands que la largeur du JPanel (en d'autres termes, une partie de l'image sera hors de l'écran), est-ce que drawImage() ajuste ce qui est rendu de sorte qu'il ne "tient compte que" de la partie visible sur le JPanel ? Je suis curieux à ce sujet car si je dessine une image très grande sur le JPanel, paintComponent() pourrait devenir lent.

3voto

Mikle Garin Points 5990

Il y a deux côtés du problème ici...

1. Chargement d'images volumineuses

Vous avez déjà une grande image chargée en mémoire dans votre exemple de code (vous la peignez directement sur le composant). Cela signifie que si vous avez une image vraiment grande - vous rencontrerez des problèmes dès que vous commencerez à la charger en mémoire pour la peindre (peu importe comment) - elle consommera beaucoup de mémoire une fois entièrement chargée.

Cela devrait être le principal problème lorsque vous travaillez avec de grandes images car Java standard ne fournit pas beaucoup d'outils. Vous ne pouvez charger l'image complète qu'avec les outils de base.

Vous pourriez envisager d'explorer des façons alternatives de charger une partie de l'image (pas sûr que cela soit toujours possible) ou de diviser une grande image en parties et de charger seulement les parties de l'image affichées. Des bibliothèques tierces comme JAI pourraient aider avec cela.

Quoi qu'il en soit, ce ne sont que des "paroles" - passons au deuxième problème dont vous avez parlé.

2. Peindre une grande image sur le composant

Je parie que vous avez lu quelques tutoriels de Swing et vous devez être conscient du clip. Vous devez également savoir qu'il est généralement défini sur les limites visibles actuelles du composant. Oui, uniquement la partie visible.

Donc si vous avez quelque chose comme un panneau de taille 5000x5000 px avec une image de 5000x5000 px peinte dessus, mais que la partie visible du panneau est seulement de 500x500 px - l'image sera également rognée par les graphiques sous-jacents et seule la partie qui s'adapte au clip sera peinte.

Cette optimisation fonctionne également pour diverses formes de peinture/remplissage et d'autres opérations avec des graphiques. Ce n'est pas une chose évidente mais dans la plupart des cas, il est préférable de peindre la forme/l'image complète et de laisser les graphiques sous-jacents optimiser l'opération de peinture. Dans la plupart des cas, cela sera bien plus rapide que de rogner manuellement la forme/l'image et de peindre le résultat.

Autre chose - dessiner une image sur les graphiques est l'une des opérations les plus rapides en Graphics2D donc je ne me concentrerais pas vraiment là-dessus.

Vous pouvez vérifier cet exemple qui indique clairement les optimisations de peinture fournies par les implémentations internes de Graphics2D :

public class ImageDrawTest
{
    public static void main ( String[] args )
    {    
        final ImageIcon icon = new ImageIcon ( "C:\\large.jpg" );

        JComponent c = new JComponent ()
        {
            protected void paintComponent ( Graphics g )
            {
                super.paintComponent ( g );

                long time = System.nanoTime ();
                g.drawImage ( icon.getImage (), 0, 0, null );
                time = System.nanoTime () - time;
                System.out.println ( time );
            }
        };

        JFrame f = new JFrame ();
        f.getContentPane ().setLayout ( new BorderLayout () );
        f.getContentPane ().add ( c );
        f.setSize ( 200, 100 );
        f.setLocationRelativeTo ( null );
        f.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
        f.setVisible ( true );
    }
}

Au lieu de C:\\large.jpg, utilisez n'importe quel chemin d'accès d'une grande image disponible.

Il suffit d'exécuter cet exemple et de redimensionner la fenêtre pour changer la zone visible du composant afin de voir la sortie. Il affichera le temps de peinture en nanosecondes pour chaque nouvelle peinture - cela variera beaucoup en fonction de la taille de la zone visible.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X