2008-11-05 9 views
8

Estoy tratando de escribir un archivo png de una imagen java.awt.image.BufferedImage. Todo funciona bien, pero el png resultante es un archivo de 32 bits.En java, ¿cómo se escribe java.awt.image.BufferedImage en un archivo png de 8 bits?

¿Hay alguna manera de hacer que el archivo png sea de 8 bits? La imagen es en escala de grises, pero necesito transparencia ya que esta es una imagen superpuesta. Estoy usando java 6, y preferiría devolver un OutputStream para que pueda hacer que la clase que llama trate de escribir el archivo en disk/db.

Aquí es la parte relevante del código:

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

Puede haber más información se puede encontrar ahora en http://stackoverflow.com/questions/665406/make-a-color-transparent-in-bufferedimage-to-be-saved-as-png – VonC

Respuesta

1

Es una pregunta interesante ... Es tarde, voy a experimentar mañana. Primero intentaré usar una imagen Buffered.TYPE_BYTE_INDEXED (quizás después del dibujo) para ver si Java es lo suficientemente inteligente como para generar un archivo PNG de 8 bits.
O tal vez alguna biblioteca de imágenes puede permitir eso.

[EDIT] Algunos años después ... En realidad, hice el código en ese momento, pero olvidé actualizar este hilo ... Usé the code pointed at by Kat, con un pequeño refinamiento en el manejo de la transparencia, y guardando en PNG formato en lugar de formato Gif. Funciona al hacer un archivo PNG de 8 bits con transparencia de todo o nada.

Puede encontrar un archivo de prueba en funcionamiento en http://bazaar.launchpad.net/~philho/+junk/Java/view/head:/Tests/src/org/philhosoft/tests/image/AddTransparency.java usando mi clase ImageUtil.

Como el código no es tan grande, para la posteridad, lo publico aquí, sin JavaDoc para guardar algunas líneas.

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 años después, todavía esperando que esto sea una respuesta en lugar de otra pregunta. – mjaggard

+1

No veo una pregunta sobre mi respuesta, aunque sinceramente tampoco veo una respuesta (hey, era nuevo en SO en ese momento ...). De todos modos, a pesar del tono, gracias por el aviso. – PhiLho

+0

Perdón por el tono, se suponía que no debía sonar agresivo. SO le pide que especifique por qué está bajando la votación, así que solo estaba respondiendo esa pregunta. – mjaggard

4

La acumulación de escritor ImageIO png va a escribir archivos de 32 bits PNG en todas las plataformas que he utilizado en, no importa lo que la imagen de origen es. También debe tener en cuenta que muchas personas se han quejado de que la compresión resultante es mucho menor de lo que es posible con el formato png. Hay varios png libraries independientes disponibles que le permiten especificar el formato exacto, pero en realidad no tengo ninguna experiencia con ninguno de ellos.

0

Gracias por responder, iba a probar un TYPE_BYTE_INDEXED con un IndexColorModel y todavía puede pero si ImageIO escribe 32 bits independientemente de que parezca que pueda estar perdiendo el tiempo allí.

La imagen que intento escribir puede ser muy grande (hasta 8000x4000) pero es simplemente una máscara para la imagen de abajo, por lo que solo tendrá un ~ 30% de gris transparente y un recorte transparente del 100%. Yo usaría un GIF pero parece que IE6 tiene problemas para mostrar uno tan grande.

Solo se genera una vez y en una pantalla de configuración interna, por lo que el rendimiento tampoco es un problema, pero tiene que hacerse dentro del código Java y no con una utilidad fuera de línea.

Las bibliotecas que ha especificado se pueden usar para transformarlo mientras se escribe ... Voy a verificarlo.

Si alguien tiene una mejor manera, ¡por favor hágamelo saber!

Gracias!

1

he encontrado la respuesta en cuanto a cómo convertir a RGBA indexado aquí: http://www.eichberger.de/2007/07/transparent-gifs-in-java.html

Sin embargo, el archivo PNG de 8 bits resultante sólo tiene 100% o 0% de transparencia.Probablemente podría modificar las matrices de IndexColorModel, pero hemos decidido convertir el archivo generado (lo que era una máscara de superposición) en un jpg subyacente y usar lo que era la base estática como superposición transparente.

+1

En lugar de hacer tachuelas en las respuestas a su publicación, puede agregar información a su pregunta original haciendo clic en editar. Los usuarios pueden ver lo que se ha cambiado y no solo sigue agregando a la columna de respuestas. –

Cuestiones relacionadas