web-dev-qa-db-fra.com

Java: remplissage d'une BufferedImage avec des pixels transparents

J'ai un BufferedImage hors écran, construit avec le type BufferedImage.TYPE_INT_ARGB. Il peut contenir n'importe quoi et je cherche un moyen (assez efficace) d'écraser complètement l'image avec des pixels transparents, ce qui donne une image "invisible".

En utilisant quelque chose comme ceci:

    (bufimg.getGraphics()).setColor(new Color(10, 10, 100, 0));   
    (bufimg.getGraphics()).fillRect (0, 0, x, y);

N'a aucun effet. Une méthode possible pourrait simplement consister à écrire sur chaque pixel de BufferedImage, mais je ne suis pas sûr que ce soit la meilleure solution. Comment le ferais-tu?

[modifier]
La documentation de Graphics déconseille l'utilisation de clearRect pour les images hors écran, mais je l'ai essayé avec les mêmes résultats que ci-dessus.

[edit2]
Après avoir essayé le code de MeBigFatGuy (merci!), Une image est effacée. Mais cela empêche également de continuer à peindre cette image (ou semble l’être). Ce code par exemple:

    BufferedImage img = new BufferedImage (600, 600, BufferedImage.TYPE_INT_ARGB);
    Graphics g = img.createGraphics ()    
    g.drawLine (100, 100, 500, 500);
    AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f);
    g.setComposite(composite);
    g.setColor(new Color(0, 0, 0, 0));
    g.fillRect(0, 0, 600, 600);
    graphicsAI.setColor(new Color (10, 10, 10, 255));
    graphicsAI.drawLine (100, 100, 500, 500);

Résultats sans aucune image sur l'image (je dessine l'image sur un JPanel). Est-ce que cela a quelque chose à voir avec l'ajout de valeurs alpha?

19
JBenson

Vous pouvez obtenir le tableau int[] sous-jacent de votre BufferedImage (assurez-vous d'utiliser un format compatible: c'est-à-dire, un format supporté par un int[]).

Puis remplissez le int[] avec des entiers dont la valeur alpha est 0 (0 fera;)

Un System.arraycopy sera très rapide.

Vous devez savoir que l'écriture directe dans le int[] est un lot plus rapide que l'utilisation de setRGB .

Maintenant, BufferedImage sont un peu un art noir en Java: selon ce que vous faites et sur quelle plate-forme/JVM vous le faites, vous pouvez perd de l’accélération matérielle (qui n’a peut-être jamais été de toute façon). En plus de cela, vous pouvez très bien ne pas vous soucier de l'accélération matérielle de toute façon car vous ne pouvez pas travailler, par exemple, sur un jeu nécessitant plus de 60 FPS pour être jouable, etc.

Il s’agit d’un sujet très complexe et il existe plus d’une façon de traiter l’enjeu BufferedImage cat. En ce qui me concerne, je travaille directement dans le int[] lorsque je dois bousiller au niveau des pixels car je pense que cela a beaucoup plus de sens que d'essayer d'utiliser des primitives de dessin de niveau supérieur et que je le fais vraiment ne s'inquiète pas de la perte potentielle d'accélération matérielle.

9
SyntaxT3rr0r

Après avoir effacé l'arrière-plan avec le composite CLEAR, vous devez le redéfinir sur SRC_OVER pour que le dessin redevienne normalement. ex:

//clear
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
g2.fillRect(0,0,256,256);

//reset composite
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
//draw
g2.setPaint(Color.RED);
g2.fillOval(50,50,100,100);
24
Josh Marinacci

Si vous convertissez l'objet Graphics en objet Graphics2D, vous pouvez définir un objet Composite via

AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setComposite(composite);
g2d.setColor(new Color(0, 0, 0, 0));
g2d.fillRect(0, 0, 10, 10);
5
MeBigFatGuy

Définir l'arrière-plan de l'objet graphique semble faire l'affaire:

g.setBackground(new Color(0, 0, 0, 0));

(au moins lorsque vous dessinez des images à des fins de mise à l'échelle)

0
Brad Mace

Bien que vous disiez que cela ne fonctionne pas, j'ai utilisé clearRect plutôt bien. 

Efface le rectangle spécifié en le remplissant avec la couleur d'arrière-plan De la surface de dessin actuelle. Cette opération n'utilise pas le mode de peinture actuel .

À partir de Java 1.1, la couleur d'arrière-plan des images hors écran peut Dépendre du système. Les applications doivent utiliser setColor suivi de FillRect pour s’assurer que l’image hors écran est effacée pour obtenir une couleur spécifique.


Remplit le rectangle spécifié. Les bords gauche et droit du rectangle Sont situés à x et x + largeur - 1. Les bords supérieur et inférieur se situent à Y et y + hauteur - 1. Le rectangle résultant couvre une largeur de surface pixels de largeur par hauteur pixels de hauteur. Le rectangle est rempli en utilisant la couleur actuelle du contexte graphique .

Il n’est pas clairement indiqué ici que l’un va définir le rectangle à la couleur de fond, tandis que l’autre (Peindre} _ avec la couleur de premier plan au-dessus des couleurs actuelles, faire.

Ceci est une pure spéculation, mais je pense que la note sur les images hors écran concerne des objets Graphics obtenus à partir de composants AWT hors écran, car ils sont natifs. Je peux difficilement imaginer comment la couleur d'arrière-plan d'une BufferedImage pourrait dépendre du système. Comme la documentation de l'API concerne Graphics, il pourrait s'agir d'une généralisation ne s'appliquant pas au cas BufferedImage.

Mon code de test:

JFrame jf = new JFrame();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

BufferedImage img = new BufferedImage(200, 300, BufferedImage.TYPE_INT_ARGB);

Graphics2D g = img.createGraphics();

//fill right half with opaque white
g.setColor(Color.WHITE);
g.fillRect(100, 0, 100, 300);

//leave top third as it is

//fill middle third with transparent color
g.setColor(new Color(0, true));
g.fillRect(0, 100, 200, 100);

//clear bottom third with transparent color
g.setBackground(new Color(0, true));
g.clearRect(0, 200, 200, 100);

g.dispose();

jf.add(new JLabel(new ImageIcon(img)));

jf.pack();
jf.setVisible(true);

le résultat est deux carrés blancs, en haut à droite. Lorsque aucun blanc n'a été peint ou que clearRect a été utilisé pour remplacer le blanc, le résultat est un gris clair, la couleur d'arrière-plan par défaut du cadre.

En termes de performances, c'est un dessin régulier. arraycopy pourrait bien être plus rapide, je ne sais pas, mais au moins c'est probablement une accélération matérielle accélérée, comme toute autre opération de dessin.

Un point positif par rapport à la solution de matrice est a) pas de mémoire supplémentaire et b) indépendance du modèle de couleur; cela devrait fonctionner quelle que soit la configuration de l'image.

Un point négatif par rapport à la solution composite est qu’elle ne permet que l’effacement des rectangles; régler le composite vous permet d'effacer tout type de forme.

0
Silly Freak

Malgré le fait qu’il souhaite définir le pixel de premier plan sur transparent, votre réponse est définitivement la réponse correcte.

private Color transparent = new Couleur (0, vrai);

((Graphics2D) g) .setBackground (transparent);

g.clearRect (0, 0, w, h);

définit l'arrière-plan sur transparent. 

BTW: Les autres réponses sont la plupart du temps des ordures ou simplement FUD. N'acceptez pas les réponses qui parlent d'une "image protégée comme étant de l'art noir" dans un forum technique. 

0
user1135940