Java2D
Java2D est une bibliothèque graphique de bas niveau pour Java, faisant partie à la fois de JFC et de Java Media. Cette bibliothèque est le fruit d’une collaboration entre Sun Microsystems et Adobe Systems pour pallier les manques et déficiences de l'AWT. Tant la pile d’exécution de Java2D que ses commandes offrent d’ailleurs une grande similarité avec le langage de rendu PostScript.
Java2D permet de tracer toutes sortes de figures géométriques en 2 dimensions. En effet chaque opération Java2D peut se résumer en un remplissage d'une forme avec une peinture suivi de sa composition sur l’écran (voir le chapitre Destination).
Concepts de base
Ces objets sont les composants de base de presque toutes les opérations Java2D.
Formes (Shape)
Une forme en Java2D peut être interprétée comme étant une frontière infiniment fine définissant un dehors et un dedans. Les pixels dans la forme sont affectés par les opérations de rendu alors que ceux situés à l'extérieur ne le sont pas.
Remplir un segment infiniment fin donnerait un résultat où aucun pixel n'est modifié étant donné que l'on peut considérer qu'une telle forme ne contient aucun pixel. De ce fait, un rectangle de faible épaisseur doit être utilisé pour que la forme puisse contenir des pixels.
Peinture (Paint)
Une peinture génère les couleurs qui doivent être utilisées pour chaque pixel lors des opérations de remplissage (ou fill). La peinture la plus simple est définie par la classe java.awt.Color, qui génère la même couleur pour tous les pixels. Des peintures plus complexes peuvent produire des gradients, des images ou n'importe quelle autre combinaison de couleurs. Remplir une forme circulaire en utilisant la couleur opaque jaune produira un cercle opaque jaune ; tandis que le fait de remplir cette même forme avec peinture générant une image produira un découpage circulaire de cette même image.
Compositions (Composites)
Pour chaque opération de dessin, on peut identifier une source (les pixels qui sont produits par la peinture) et une destination (les pixels déjà présents sur l’écran). En temps normal les pixels sources recouvrent tout simplement les pixels destination ; cependant certaines composites permettent de changer ce comportement.
Une composite, étant donné les pixels sources et destination, produit un résultat qui sera contenu sur l’écran. La composite la plus couramment utilisée est définie par la classe java.awt.AlphaComposite, qui permet de traiter le dessin de pixels partiellement transparents, ce qui permet de voir les pixels de la destination plus ou moins à travers les pixels sources. Cette composite implémente les règles de Porter et Duff.
Remplissage (Filling)
Pour remplir une forme, la première étape est d'identifier quels pixels sont à l'intérieur de cette forme. Ces pixels seront ceux affectés par l'opération de remplissage. Les pixels qui sont partiellement à l’extérieur ou partiellement à l’intérieur seront également affectés selon que l’anticrénelage est activé ou pas.
La peinture doit alors générer la couleur de chacun des pixels devant être peints. Dans le cas courant de l’utilisation d’une couleur opaque, chaque pixel sera mis à la même couleur.
La composition prend alors les pixels générés par la peinture et les combine avec ceux déjà présents sur l’écran pour créer le résultat final.
Objets avancés
Ces objets ainsi que leur comportement peuvent être décomposés en objets simples comme ceux décrits dans le paragraphe précédents.
Transformations (Transform)
Chaque opération Java2D peut être l’objet d’une transformation, faisant que les formes peuvent être translatées, tournées, inclinées voir agrandies ou rétrécies au moment de leur rendu. La transformation la plus courante est la transformation identitaire ou identité qui ne fait rien.
Effectuer un remplissage avec une transformation peut être simplement vu comme la création d’une nouvelle forme transformée et le remplissage de cette même forme.
Tracé (Stroke)
En plus des opérations de remplissage, Java2D permet de faire des opérations de tracé. Alors que le remplissage dessine l’intérieur d’une forme, le tracé en dessine le contour. Ce contour peut simplement apparaitre comme une ligne fine voire sous des formes plus complexes telles qu’une succession de tirets de bouts arrondis.
L’objet responsable de la création de la bordure est un trait ou Stroke. À partir d'une forme source donnée, le trait produira une nouvelle forme représentant le contour de la première. Par exemple une ligne infiniment fine peut donner comme contour un rectangle d’une épaisseur de un pixel.
Un tracé peut donc être décrit comme la création d’une nouvelle forme suivie de son remplissage.
Techniquement parlant, la seule chose dont on requiert d’un tracé, c’est d’accepter une forme en entrée et d’en produire une autre en retour. L’implémentation d’un trait fournie avec Java2D (java.awt.BasicStroke) suit la règle précédemment décrite ; cependant un trait personnalisé pourrait, en théorie, produire n’importe quel type de forme suivant les besoins.
Optimisations
Conceptuellement, dessiner un segment noir en Java2D reviendrai à créer un segment, le transformer suivant la transformation courante, générer son tracé ce qui a pour effet de créer un rectangle de fine épaisseur, identifier sur cette forme les pixels affectés par le remplissage puis les générer avec la couleur java.awt.Color.BLACK et enfin composer le résultat sur l’écran.
Cependant effectuer toute cette séquence d'étapes pour chaque opération de dessin est totalement inefficace. Java2D se permet donc d’optimiser certaines opérations basiques de dessin de manière à sauter ou éviter certaines étapes. Si le dessin utilise une couleur opaque, il n’est pas alors nécessaire de créer une liste complète des couleurs à produire. De même si une composite sans support de la transparence est utilisée, demander le calcul du résultat de cette composition est futile et serait une dépense inutile de temps processeur.
Java 2D fait donc dans tous les cas la somme minimale de travail nécessaire pour achever un résultat similaire à un traitement complet ; ceci lui permet d’avoir à la fois une grande flexibilité et de bonnes performances.
Destination
Pour simplifier l’exposé, cet article a présumé que le rendu était destiné à être produit sur un écran. Cependant la surface de rendu finale peut être de toute autre nature comme, par exemple, une imprimante, une image en mémoire ou même n’importe quel objet qui accepterait des commandes Java2D et les traduirait en commandes pour générer un format quelconque d'image vectorielle.