Abend!
Ich möchte BMPs mit ImageIO schreiben. Soweit kein Problem. Allerdings kommt es mir darauf an, die Auflösung festlegen zu können (dpi). Bei JPEG-Grafiken klappt das bereits auch ohne Probleme:
Eine entscheidende Rolle spielt dabei die Klasse IIOMetadata, die quasi alle für ein Grafikformat relevanten Informationen zu einer Grafik enthält - im Fall von BMP und JPEG also auch die Auflösung. Für jedes Grafikformat ist desweiteren eine separate von IIOMetadata abgeleitete Klasse zuständig: bei JPEG-Grafiken ist es z.b. com.sun.imageio.plugins.jpeg.JPEGMetadata. Der Hacken bei der entsprechenden BMP-Klasse com.sun.imageio.plugins.bmp.BMPMetadata ist nun, dass sich die Attribute darin nicht überschreiben lassen. So werfen die Implementierungen der Schnittstellen-Setter z.B. gleich eine Exception ohne wenn und aber.
Kennt also jemand vielleicht einen anderen Weg?
Ich möchte BMPs mit ImageIO schreiben. Soweit kein Problem. Allerdings kommt es mir darauf an, die Auflösung festlegen zu können (dpi). Bei JPEG-Grafiken klappt das bereits auch ohne Probleme:
Code:
// erstelle BufferedImage und zeichne in seinen grafikkontext
BufferedImage bi = new BufferedImage(pxlWidth, pxlHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bi.createGraphics();
// ...
// ... zeichne in den g2d-kontext
// ...
g2d.dispose();
ImageTypeSpecifier its = new ImageTypeSpecifier(bi.getColorModel(), bi.getSampleModel());
Iterator iterator = ImageIO.getImageWritersByFormatName("jpg");
ImageWriter imageWriter = (ImageWriter)iterator.next();
ImageWriteParam param = imageWriter.getDefaultWriteParam();
IIOMetadata iomd = imageWriter.getDefaultImageMetadata(its, param);
initJPGImageMetadata(iomd, resolution); // <<<--------- aufruf der methode s. unten
IIOImage iioImage = new IIOImage(bi, null, iomd);
// schreibe datei
FileImageOutputStream fios = null;
try {
fios = new FileImageOutputStream(file);
imageWriter.setOutput(fios);
imageWriter.write(iioImage);
} catch (Exception e) {
// ...
} finally {
if (fios != null) try { fios.close(); } catch (Exception e) {}
}
Code:
//----
private static void initJPGImageMetadata(IIOMetadata iiomd, int resolution) {
final String resStr = String.valueOf(resolution);
final String formatName = "javax_imageio_jpeg_image_1.0";
final Node node = iiomd.getAsTree(formatName);
final NodeList nodeList = node.getChildNodes();
for (int i=nodeList.getLength()-1; i>=0; i--) {
Node n = nodeList.item(i);
if (n.getNodeName().equals("JPEGvariety")) {
NodeList childNodes = n.getChildNodes();
for (int j=childNodes.getLength()-1; j>=0; j--) {
Node cn = childNodes.item(j);
if (cn.getNodeName().equals("app0JFIF")) {
getAttributeByName(cn, "resUnits").setNodeValue("1"); // "dpi"
getAttributeByName(cn, "Xdensity").setNodeValue(resStr);
getAttributeByName(cn, "Ydensity").setNodeValue(resStr);
}
}
break;
}
}
try { iiomd.setFromTree(formatName, node);
} catch (IIOInvalidTreeException e) { /* kann sich nicht ereignen */ }
}
Code:
//---- hilfsmethode
private static Node getAttributeByName(Node node, String attributeName) {
NamedNodeMap nnm = node.getAttributes();
for (int i=nnm.getLength()-1; i>=0; i--) {
Node n = nnm.item(i);
if (n.getNodeName().equals(attributeName))
return n;
}
return null; // no such attribute was found
}
Eine entscheidende Rolle spielt dabei die Klasse IIOMetadata, die quasi alle für ein Grafikformat relevanten Informationen zu einer Grafik enthält - im Fall von BMP und JPEG also auch die Auflösung. Für jedes Grafikformat ist desweiteren eine separate von IIOMetadata abgeleitete Klasse zuständig: bei JPEG-Grafiken ist es z.b. com.sun.imageio.plugins.jpeg.JPEGMetadata. Der Hacken bei der entsprechenden BMP-Klasse com.sun.imageio.plugins.bmp.BMPMetadata ist nun, dass sich die Attribute darin nicht überschreiben lassen. So werfen die Implementierungen der Schnittstellen-Setter z.B. gleich eine Exception ohne wenn und aber.
Kennt also jemand vielleicht einen anderen Weg?