write read imageio iioexception formatname example java image io awt

read - java imageio write formatname



En java, ¿cómo se escribe java.awt.image.BufferedImage en un archivo png de 8 bits? (4)

Encontré la respuesta sobre cómo convertir RGBA a indexado aquí: http://www.eichberger.de/2007/07/transparent-gifs-in-java.html

Sin embargo, el archivo png de 8 bits resultante solo tiene una transparencia del 100% o 0%. 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.

Estoy tratando de escribir un archivo png de una java.awt.image.BufferedImage. Todo funciona bien, pero el png resultante es un archivo de 32 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í está 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; }


Gracias por responder, iba a probar un TYPE_BYTE_INDEXED con un IndexColorModel y aún así, pero si ImageIO escribe en 32 bits, a pesar de todo parece que podría estar perdiendo el tiempo allí.

La imagen que intento escribir puede ser muy grande (hasta 8000x4000), pero es solo una máscara simple para la imagen que está debajo, 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 tipo 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 especificó podrían usarse para transformarlo mientras se escribe ... Voy a verificarlo.

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

¡Gracias!


La construcción en imageio png writer escribirá archivos png de 32 bits en todas las plataformas en las que lo he usado, sin importar cuál sea la imagen fuente. 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 varias bibliotecas png independientes disponibles que le permiten especificar el formato exacto, pero en realidad no tengo ninguna experiencia con ninguna de ellas.


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.

[EDITAR] Algunos años después ... En realidad, hice el código en ese momento, pero olvidé actualizar este hilo ... Utilicé el código apuntado por Kat , con un pequeño refinamiento en el manejo de la transparencia y el ahorro en Formato PNG 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 utilizando mi clase ImageUtil .

Dado que el código no es tan grande, para la posteridad, lo publico aquí, sin el 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); } }