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

2D Java Discussion :

Graphics2D : antialiasing avec alpha


Sujet :

2D Java

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 23
    Points : 17
    Points
    17
    Par défaut Graphics2D : antialiasing avec alpha
    Bonjour !

    J'essaye depuis quelques jours de créer ma propre implémentation d'un TextDrawer afin de lui rajouter quelques outils bien pratique. Mais je me suis aperçu que lorsque je met l'antialiasing sur mon texte, une bordure noire apparait.

    Le texte est censé s'afficher sur une image. Pour simplifier le code, je commence par nettoyer l'écran avec une couleur de fondpuis je nettoie le quad qui va servir à plaquer ma texture où le texte apparaît. Cette couleur correspond à 0x00000000, où l'alpha est activé. Je vois donc bien mon background entre les caractères. Tout va bien sauf quand pour améliorer le rendu je rajoute :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    g.setRenderingHint(
    RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    Là, une bordure grise apparaît. Après avoir fait quelques tests, il s'avère qu'il s'agit de la couleur avec laquelle je nettoie mon quad (le fameux 0x00000000). Un patch pourrait être fait en nettoyant le quad avec la couleur de ma font, mais la classe gère aussi une ombre dont la couleur est déterminable séparément de la couleur du texte.

    Donc je cherche une formule pour avoir un rendu correct face à ce problème, tout en gardant l'antialiasing. Une idée ?

    Merci d'avance

  2. #2
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 23
    Points : 17
    Points
    17
    Par défaut
    J'essaye de reformuler mon problème :

    J'essaye d'écrire un texte sur un quad transparent.
    Ce quad sera posé utilisé dans un monde 3D.

    L'antialiasing que j'utilise sur le texte mélange la couleur du texte avec la couleur transparente, donc si mon texte est rose, les bordures virent vers le gris avec un alpha qui diminue.
    Je ne peux pas changer la couleur transparente. (voir le poste précédent pour les raisons)

    J'aimerais que l'antialiasing n'utilise pas cette couleur noire transparente, mais ne fasse que jouer sur l'alpha afin que la composition avec les couleurs derrière le texte (dans le monde 3D) soit correctes.

  3. #3
    Membre averti
    Avatar de Chatanga
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    211
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 211
    Points : 346
    Points
    346
    Par défaut
    Je n'ai quasiment rien compris . Ne dessiner que le texte avec l'anticrénelage pourrait peut-être suffire ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    Mais peut-être pas.

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 23
    Points : 17
    Points
    17
    Par défaut
    Merci pour ta réponse, j'ai déjà essayé, et ça ne résout pas mon problème.

    Donc c'est reparti pour une explication.

    Soit 2 couleurs, la couleur de fond 0x00000000 (noir transparent) et la couleur du texte 0xffff0000 (rouge)
    Quand j'utilise l'antialiasing sur le texte, j'ai une "bordure grise", car je pense que l'antialiasing mélange le noir et le rouge.
    Or ce que je veux, c'est un antialiasing qui sur les bordures joue simplement avec l'alpha sans changer la couleur des pixels, pour ne plus avoir cette bordure grise.

    Et je ne veux pas changer ces 2 couleurs. (pour faire simple)

    Un avis ? Une idée ? Merci !

  5. #5
    Membre averti
    Avatar de Chatanga
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    211
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 211
    Points : 346
    Points
    346
    Par défaut
    Je vois un peu mieux le problème. Une solution consisterait à effectuer le rendu du texte dans une image temporaire avec un fond de couleur valant couleur_du_texte & 0x00ffffff, puis à recopier cette image sur l'image originale. Une autre solution serait de jouer sur le mode de blending via Graphics2D.setComposite(AlphaComposite.SRC), mais ça reste à vérifier.

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 23
    Points : 17
    Points
    17
    Par défaut
    Je suis aller chercher du côté des "Composite" sur : http://download.oracle.com/javase/tu...mpositing.html
    Ce que j'en comprend, c'est ce que l'on peut jouer sur le style de composition.
    Or dans mon exemple, le texte est opaque, et seul ses bords diminue en opacité. Du coup, je ne sais pas trop comment m'en servir...

    Donc j'suis parti sur du refactoring qui au final était plus simple que de trouver une solution toute faite. J'ai donc 2 rendus, un pour le texte, et un pour l'ombre (par exemple) qui peuvent avoir 2 couleurs différentes, donc avec 2 couleurs de fond différentes.
    Tout fonctionne ... mais quand je met au moins 0.5/255 pour l'alpha pour ces couleurs de fonds. Si je met simplement 0, ou même 0.4999/255 pour l'alpha, je me retrouve avec ces foutues bordures sombres

    Quelqu'un sait d'où sort ce 0.5 ? Parce que même si ça n'a l'air de rien, avec ça j'impose une teinte à l'image final de 1/255 suivant la couleur du texte. Soit un texte rouge pur, la zone proche du texte gagnera 1 point sur sa composante rouge... et ça c'est pas cool, surtout si je me retrouve avec plusieurs textes assez proche, ça va finir par se voir



    On voit bien sur l'image la différence avec en haut la bordure grise mais un blanc vraiment blanc entre les caractères, et en dessous, plus de bordure grise mais un blanc #010000 entre les caractères ...

  7. #7
    Expert confirmé
    Avatar de slim_java
    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2008
    Messages
    2 272
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2008
    Messages : 2 272
    Points : 4 539
    Points
    4 539
    Par défaut
    Salut,

    essayer d'appliquer ce lissage :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Graphics2D g2d = ...;
    /** Lissage du texte uniquement : */
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
     
    /** Lissage du texte et des dessins */
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

  8. #8
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Est-il possible d'avoir un code un peu plus détaillé de ta méthode de rendu ? De même que la platforme d'exécution (JVM, OS, carte graphique, rendu Java2D soft, accéléré OpenGL ou DirectX ?)

    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
     
    public class Main {
     
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
     
                public void run() {
                    JFrame frame = new JFrame("Test");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new TextRenderingPane(), BorderLayout.CENTER);
                    frame.setSize(1000, 800);
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    }
    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
    public class TextRenderingPane extends JComponent {
     
        private BufferedImage offscreenImage;
        private Paint textPaint = Color.RED;
        private Font textFont = new Font("Dialog", Font.BOLD, 300);
        private String text = "The crazy fox jumps over the lazy dog.";
     
        public TextRenderingPane() {
            addComponentListener(new ComponentAdapter() {
     
                /**
                 * {@inheritDoc}
                 */
                @Override
                public void componentResized(ComponentEvent evt) {
                    offscreenImage = null;
                    repaint();
                }
            });
        }
     
        /**
         * {@inheritDoc}
         */
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Insets insets = getInsets();
            Dimension size = getSize();
            int width = size.width - (insets.left + insets.right);
            int height = size.height - (insets.top + insets.bottom);
            if (width <= 0 || height <= 0) {
                return;
            }
            if (offscreenImage == null) {
                GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
                offscreenImage = gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
                Graphics2D g2d = offscreenImage.createGraphics();
                try {
                    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                    g2d.setPaint(textPaint);
                    g2d.setFont(textFont);
                    LineMetrics ln = textFont.getLineMetrics(text, g2d.getFontRenderContext());
                    g2d.drawString(text, 10, 10 + ln.getAscent());
                } finally {
                    g2d.dispose();
                }
            }
            Graphics2D g2d = (Graphics2D) g.create(insets.left, insets.top, width, height);
            try {
                g.drawImage(offscreenImage, 0, 0, null);
                g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
                g2d.setPaint(textPaint);
                g2d.setFont(textFont);
                LineMetrics ln = textFont.getLineMetrics(text, g2d.getFontRenderContext());
                g2d.drawString(text, 10, 2 * (10 + ln.getAscent()));
            } finally {
                g2d.dispose();
            }
        }
    }
    Car j'ai beau écarquiller les yeux je ne vois rien.
    Après si tu dessines directement sur le Graphics de l'écran il faut bien se souvenir que ce dernier n'est jamais transparent, il est tout le temps opaque.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 23
    Points : 17
    Points
    17
    Par défaut SOLUTION
    Merci beaucoup pour vos réponses qui m'ont fait beaucoup réfléchir. Au final, l'erreur venait d'une optimisation de Java2D.

    Cette optimisation permet de ne pas prendre en compte les couleurs dont l'alpha est égale à 0. Le problème est que si vous nettoyer un quad avec une couleur du genre 0x00FF0000, vous vous attendez à ce que le graphics soit remplis de ces valeurs... mais l'optimisation consiste à sauter cette étape et à mettre simplement 0x00000000.

    Et alors où est le problème ?

    Et bien tout simplement, quand vous utilisez un filtrage bilinéaire par exemple, vous allez piochez dans les pixels voisins pour améliorer le rendu. Le filtrage ayant lieu ici sur le quad 0x00000000 et le texte 0xFFFF0000, on créer des couleurs de gris qui n'aurait pas lieu d'être (0x55550000). Et une fois que l'on fait la composition de l'image avec du blanc, ben ça fait moche comme le montre les screens plus haut.

    Ok, mais alors on fait comment ?

    Il existe peut-être une meilleure technique, et si oui, n'hésitez pas à la rajouter, mais en voici une qui a le mérite de marcher.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    g.setBackground(0xFFFF0000);
    g.clearRect(0, 0, w, h);
    WritableRaster r = b.getRaster();
    for (int x = 0; x < w; x++) {
    	for (int y = 0; y < h; y++) {
    		r.setSample(x, y, 3, 0x00);
    	}
    }
    Ce qui donne une fois traduit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Je met la couleur du texte dans ma couleur de fond.
    Je clean le fond (w*h) avec la couleur de fond.
    J écris pour chaque pixel : alpha=0
    3 correspondant à la "band" de l'alpha dans mon cas (BufferedImage.TYPE_4BYTE_ABGR). Vous adviendrez que cela nécessite de passer 2 fois l'image ... Donc je suis preneur de toutes optimisations

    Et au cas où ma config :
    Jdk 1.6.22
    Windows Seven
    NVidia GeForce GTS 240
    OpenGL

    Merci à tout le monde

  10. #10
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Ca javais bien compris, mais je ne vois toujours pas pourquoi utiliser g.getBackground() chose qui n'a jamais correctement fonctionné pour moi. Ca date du temps d'avant le support complet de la transparence, d'avant Java2D.

    Pour nettoyer une zone avec de la couleur transparence, utiliser AlphaComposite.SrcIn devrait être suffisant, un truc du genre :

    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
    Graphics2D g2d = (Graphics2D)g.create();
    try {
      g2d.setColor(Color.BLACK);
      g2d.fillRect(boundingBoxDeLaZoneARepeindre);
      g2d.setComposite(AlphaComposite.SrcIn);
      g2d.setColor(la bonne couleur transparente);
      g2d.fillRect(boundingBoxDeLaZoneARepeindre);
    } finally {
      g2d.dispose();
    }
     
    ...
     
    for (...) {
      if (boundingBoxDeLaZoneARepeindre.intersects(objet)) {
        //repeindre objet.
      }
    }

    Evidement ca ne fonctionnera pas (ou mal) en général sur le graphics de l'écran mais cela fonctionne très bien sur les graphics d'image offscreen.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  11. #11
    Membre à l'essai
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 23
    Points : 17
    Points
    17
    Par défaut
    Merci Bouye pour ce complément d'information, tu as probablement raison... mais avec ce code, les bordures grises sont revenus, donc je ne pense pas que cette technique résolve mon problème plus facilement que celle que j'avais trouvé précédemment.

    De plus, je n'aime pas trop les "trucs" qui fonctionnent pas ou mal, en général. C'est pas assez précis pour moi ^^. Comme le fait que getBackground ne fonctionne pas pour toi...

    Dans tout les cas, merci à tous de votre intérêt pour le sujet, et en espérant que ce topic servent à d'autres...

Discussions similaires

  1. accumulateWeighted mais avec alpha
    Par Garra dans le forum OpenCV
    Réponses: 0
    Dernier message: 12/10/2013, 19h39
  2. masking avec alpha
    Par venomelektro dans le forum OpenGL
    Réponses: 9
    Dernier message: 10/04/2009, 10h17
  3. Problème avec alpha dans un clip
    Par Buuhh dans le forum ActionScript 3
    Réponses: 1
    Dernier message: 08/01/2009, 22h00
  4. Réponses: 0
    Dernier message: 11/05/2008, 22h09
  5. [FLASH 8] Faire disparaitre du texte avec alpha
    Par steeves5 dans le forum Flash
    Réponses: 6
    Dernier message: 08/06/2006, 15h47

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