2008-11-05 8 views
8

J'essaie d'écrire un fichier png à partir d'une image java.awt.image.BufferedImage. Tout fonctionne bien, mais le png qui en résulte est un fichier 32 bits.En Java, comment écrire une image java.awt.image.BufferedImage dans un fichier png 8 bits?

Y at-il un moyen de rendre le fichier png 8 bits? L'image est en niveaux de gris, mais j'ai besoin de transparence car il s'agit d'une image superposée. J'utilise java 6, et je préférerais retourner un OutputStream pour que la classe appelante puisse écrire le fichier sur disk/db.

Voici la partie pertinente du code:

public static ByteArrayOutputStream createImage(InputStream originalStream) 
      throws IOException { 

     ByteArrayOutputStream oStream = null; 

     java.awt.Image newImg = javax.imageio.ImageIO.read(originalStream); 
     int imgWidth = newImg.getWidth(null); 
     int imgHeight = newImg.getHeight(null); 
     java.awt.image.BufferedImage bim = new java.awt.image.BufferedImage(imgWidth, 
       imgHeight, java.awt.image.BufferedImage.TYPE_INT_ARGB); 

     Color bckgrndColor = new Color(0x80, 0x80, 0x80); 

     Graphics2D gf = (Graphics2D)bim.getGraphics(); 

     // set transparency for fill image 
     gf.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f)); 
     gf.setColor(bckgrndColor); 
     gf.fillRect(0, 0, imgWidth, imgHeight); 

     oStream = new ByteArrayOutputStream(); 
     javax.imageio.ImageIO.write(bim, "png", oStream); 
     oStream.close(); 

     return oStream; 
    } 
+0

Peut être plus d'informations peuvent être trouvés maintenant à http://stackoverflow.com/questions/665406/make-a-color-transparent-in-bufferedimage-to-be-saved-as-png – VonC

Répondre

1

Il est une question intéressante ... Il est tard, je vais essayer demain. J'essaierai d'abord d'utiliser BufferedImage.TYPE_BYTE_INDEXED (peut-être après avoir dessiné) pour voir si Java est suffisamment intelligent pour générer un PNG 8 bits.
Ou peut-être une bibliothèque d'images peut le permettre.

[EDIT] Quelques années plus tard ... En fait, j'ai fait le code à ce moment, mais j'ai oublié de mettre à jour ce fil ... J'ai utilisé the code pointed at by Kat, avec un peu de raffinement sur la gestion de la transparence format au lieu du format Gif. Cela fonctionne dans la fabrication d'un fichier PNG de 8 bits avec transparence tout ou rien.

Vous pouvez trouver un fichier de test fonctionnel au http://bazaar.launchpad.net/~philho/+junk/Java/view/head:/Tests/src/org/philhosoft/tests/image/AddTransparency.java en utilisant ma classe ImageUtil.

Comme le code n'est pas très gros, par souci de postérité, je le poste ici, sans le JavaDoc pour sauvegarder quelques lignes.

public class ImageUtil 
{ 
    public static int ALPHA_BIT_MASK = 0xFF000000; 

    public static BufferedImage imageToBufferedImage(Image image, int width, int height) 
    { 
    return imageToBufferedImage(image, width, height, BufferedImage.TYPE_INT_ARGB); 
    } 

    public static BufferedImage imageToBufferedImage(Image image, int width, int height, int type) 
    { 
    BufferedImage dest = new BufferedImage(width, height, type); 
    Graphics2D g2 = dest.createGraphics(); 
    g2.drawImage(image, 0, 0, null); 
    g2.dispose(); 
    return dest; 
    } 

    public static BufferedImage convertRGBAToIndexed(BufferedImage srcImage) 
    { 
    // Create a non-transparent palletized image 
    Image flattenedImage = transformTransparencyToMagenta(srcImage); 
    BufferedImage flatImage = imageToBufferedImage(flattenedImage, 
     srcImage.getWidth(), srcImage.getHeight(), BufferedImage.TYPE_BYTE_INDEXED); 
    BufferedImage destImage = makeColorTransparent(flatImage, 0, 0); 
    return destImage; 
    } 

    private static Image transformTransparencyToMagenta(BufferedImage image) 
    { 
    ImageFilter filter = new RGBImageFilter() 
    { 
     @Override 
     public final int filterRGB(int x, int y, int rgb) 
     { 
     int pixelValue = 0; 
     int opacity = (rgb & ALPHA_BIT_MASK) >>> 24; 
     if (opacity < 128) 
     { 
      // Quite transparent: replace color with transparent magenta 
      // (traditional color for binary transparency) 
      pixelValue = 0x00FF00FF; 
     } 
     else 
     { 
      // Quite opaque: get pure color 
      pixelValue = (rgb & 0xFFFFFF) | ALPHA_BIT_MASK; 
     } 
     return pixelValue; 
     } 
    }; 

    ImageProducer ip = new FilteredImageSource(image.getSource(), filter); 
     return Toolkit.getDefaultToolkit().createImage(ip); 
    } 

    public static BufferedImage makeColorTransparent(BufferedImage image, int x, int y) 
    { 
    ColorModel cm = image.getColorModel(); 
    if (!(cm instanceof IndexColorModel)) 
     return image; // No transparency added as we don't have an indexed image 

    IndexColorModel originalICM = (IndexColorModel) cm; 
    WritableRaster raster = image.getRaster(); 
    int colorIndex = raster.getSample(x, y, 0); // colorIndex is an offset in the palette of the ICM' 
    // Number of indexed colors 
    int size = originalICM.getMapSize(); 
    byte[] reds = new byte[size]; 
    byte[] greens = new byte[size]; 
    byte[] blues = new byte[size]; 
    originalICM.getReds(reds); 
    originalICM.getGreens(greens); 
    originalICM.getBlues(blues); 
    IndexColorModel newICM = new IndexColorModel(8, size, reds, greens, blues, colorIndex); 
    return new BufferedImage(newICM, raster, image.isAlphaPremultiplied(), null); 
    } 
} 
+0

4 ans plus tard, toujours attendre que ce soit une réponse plutôt qu'une autre question. – mjaggard

+1

Je ne vois pas de question sur ma réponse, même si honnêtement je ne vois pas non plus de réponse (hé, j'étais nouveau sur SO à l'époque ...). Quoi qu'il en soit, malgré le ton, merci pour les heads-up. – PhiLho

+0

Désolé pour le ton, il n'était pas supposé paraître agressif. SO vous demande de préciser pourquoi vous votez à la baisse, alors je répondais à cette question. – mjaggard

4

La construction de l'écrivain ImageIO va écrire les fichiers de 32 bits sur toutes les plates-formes que je l'ai utilisé sur, peu importe ce que l'image source est. Vous devez également être conscient que beaucoup de gens se sont plaints que la compression résultante est beaucoup plus faible que ce qui est possible avec le format png. Il y a plusieurs png libraries disponibles qui vous permettent de spécifier le format exact, mais je n'ai aucune expérience avec eux.

0

Merci d'avoir répondu, j'allais essayer un TYPE_BYTE_INDEXED avec un IndexColorModel et peut encore, mais si ImageIO écrit en 32 bits, même s'il semble que je puisse perdre mon temps là-bas. L'image que j'essaie d'écrire peut être très grande (jusqu'à 8000x4000) mais n'est qu'un simple masque pour l'image ci-dessous, elle aura donc seulement ~ 30% de gris transparent et une découpe 100% transparente. J'utiliserais un GIF mais IE6 semble avoir du mal à en afficher un aussi grand. Il n'est généré qu'une seule fois et dans un écran de type configuration interne, donc la performance n'est pas un problème non plus, mais cela doit être fait dans le code java et non par un utilitaire hors ligne.

Les bibliothèques que vous avez spécifiées pourraient être utilisées pour le transformer en écrivant ... Je vais vérifier cela.

Si quelqu'un a un meilleur moyen, s'il vous plaît faites le moi savoir !!

Merci!

1

J'ai trouvé la réponse à la façon de convertir RGBA à Indexé ici: http://www.eichberger.de/2007/07/transparent-gifs-in-java.html

Cependant, le fichier .png 8 bits résultant a seulement 100% ou 0% de transparence.Vous pouvez probablement ajuster les tableaux IndexColorModel, mais nous avons décidé de transformer le fichier généré (ce qui était un masque de superposition) en jpg de sous-couche et d'utiliser la base statique comme couche transparente.

+1

Au lieu de virer sur les réponses à votre message, vous pouvez réellement ajouter des informations à votre question originale en cliquant sur modifier. Les utilisateurs peuvent voir ce qui a été modifié et ne pas continuer à ajouter dans la colonne des réponses. –

Questions connexes