PNG leer y escribir con Java aumenta el tamaño del archivo

Tengo un problema al leer y escribir un archivo png. Lo leí con ImageIO en una matriz de bytes y luego escribo esta matriz de bytes nuevamente usando ImageIO. Pero el tamaño del archivo aumenta significativamente. ¿Cómo puede suceder esto?

public BufferedImage toBufferedImage(InputStream inputstream) {
    try {
        return ImageIO.read(inputstream);
    } catch (Exception e) {
        throw new IllegalStateException("Can't convert to buffered image", e);
    }
}

public byte[] toByteArray(BufferedImage bufferedImage, String filetype) {
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    try {
        ImageIO.write(bufferedImage, filetype, output);
        return output.toByteArray();
    } catch (Exception e) {
        throw new IllegalStateException(e);
    }
}

Seguimiento: ¿hay alguna biblioteca que admita archivos PNG comprimidos que esté escrito en Java y no necesite ningún código nativo?

preguntado el 22 de mayo de 12 a las 17:05

Me pregunto si está agregando un encabezado adicional de algún tipo al escribir o agregando datos adicionales al encabezado. Una buena manera de verificar si esto es así es abrir ambos archivos en algo como Beyond Compare y ver si todas las diferencias están al principio (donde está el encabezado). De lo contrario, las diferencias pueden estar en todas partes, lo que puede sugerir que está agregando datos en blanco en todo el archivo. Dudo que sea porque ha vuelto a codificar el archivo, pero esa podría ser una posibilidad. -

Me imagino que el escritor no está siendo muy inteligente con la compresión. ¿Quizás hay mejores implementaciones de flujo de salida o escritor que pueden comprimir el formato? El javadoc en el paquete alude a las interfaces con esta función. -

3 Respuestas

Lo más probable es que esto se deba a que el algoritmo de compresión es diferente entre Java y lo que haya creado el PNG original.

contestado el 22 de mayo de 12 a las 17:05

La documentación dice que está decodificando el archivo de entrada, por lo que no se guarda en la memoria como PNG:

Devuelve una imagen almacenada en búfer como resultado de la decodificación de un archivo proporcionado con un ImageReader elegido automáticamente entre los registrados actualmente. El archivo está envuelto en un ImageInputStream. Si ningún ImageReader registrado afirma poder leer el flujo resultante, se devuelve un valor nulo.

Cuando lo vuelve a escribir, tiene que volver a codificar el archivo PNG, y la codificación PNG de Java no parece ser tan eficiente como lo que creó su archivo original.

contestado el 22 de mayo de 12 a las 17:05

finalmente usamos pngj (código.google.com/p/pngj) para escribir que parece funcionar bastante bien para lo que necesitamos. - bertolami

El grabador de PNG suministrado con el JDK no admite la compresión. Puede verificar esto rápidamente con:

w = ImageIO.getImageWritersByFormatName("png").next();
p = w.getDefaultWriteParam();
print("Can compress? "+p.canWriteCompressed());
// Can compress? false

Es posible que imageio-ext o jai-imageio incluyan un escritor png con soporte de compresión: http://java.net/projects/imageio/

contestado el 22 de mayo de 12 a las 17:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.