我目前正在使用 javax.imageio.ImageIO 来编写 PNG 文件。我想包含一个文本块(实际上是此处列出的任何块),但看不到这样做的方法。
从 com.sun.imageio.plugins.png.PNGMetadata 看起来应该是可能的。
我应该非常感谢任何线索或答案。
M。
我目前正在使用 javax.imageio.ImageIO 来编写 PNG 文件。我想包含一个文本块(实际上是此处列出的任何块),但看不到这样做的方法。
从 com.sun.imageio.plugins.png.PNGMetadata 看起来应该是可能的。
我应该非常感谢任何线索或答案。
M。
经过一些反编译后我想到的解决方案如下......
RenderedImage image = getMyImage();
Iterator<ImageWriter> iterator = ImageIO.getImageWritersBySuffix( "png" );
if(!iterator.hasNext()) throw new Error( "No image writer for PNG" );
ImageWriter imagewriter = iterator.next();
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
imagewriter.setOutput( ImageIO.createImageOutputStream( bytes ) );
// Create & populate metadata
PNGMetadata metadata = new PNGMetadata();
// see http://www.w3.org/TR/PNG-Chunks.html#C.tEXt for standardized keywords
metadata.tEXt_keyword.add( "Title" );
metadata.tEXt_text.add( "Mandelbrot" );
metadata.tEXt_keyword.add( "Comment" );
metadata.tEXt_text.add( "..." );
metadata.tEXt_keyword.add( "MandelbrotCoords" ); // custom keyword
metadata.tEXt_text.add( fractal.getCoords().toString() );
// Render the PNG to memory
IIOImage iioImage = new IIOImage( image, null, null );
iioImage.setMetadata( metadata ); // Attach the metadata
imagewriter.write( null, iioImage, null );
我们在JGraphX项目中执行此操作。下载源代码并查看 com.mxgraph.util.png 包,您会在其中找到我们从 Apache Batik 源复制的三个用于编码的类。一个使用示例是在 saveXmlPng 方法中的 com.mxgraph.examples.swing.editor.EditorActions 中。稍微编辑一下代码如下:
mxPngEncodeParam param = mxPngEncodeParam
.getDefaultEncodeParam(image);
param.setCompressedText(new String[] { "mxGraphModel", xml });
// Saves as a PNG file
FileOutputStream outputStream = new FileOutputStream(new File(
filename));
try
{
mxPngImageEncoder encoder = new mxPngImageEncoder(outputStream,
param);
if (image != null)
{
encoder.encode(image);
}
}
finally
{
outputStream.close();
}
其中 image 是将形成 .PNG 的 BufferedImage 和 xml 是我们希望放置在 iTxt 部分中的字符串。“mxGraphModel”是该 xml 字符串的键(该部分包含一些键/值对),显然您将其替换为您的键。
同样在 com.mxgraph.util.png 下,我们编写了一个非常简单的类,它可以在不处理整个图像的情况下提取 iTxt。您可以使用 mxPngEncodeParam.setText 而不是 setCompressedText() 对 tEXt 块应用相同的想法,但压缩文本部分确实允许相当大的文本部分。
我意识到这个问题早已得到解答,但如果您想在不深入“com.sun”层次结构的情况下这样做,这里有一个快速且非常丑陋的示例,因为我在其他任何地方都找不到此文档。
BufferedImage img = new BufferedImage(300, 300, BufferedImage.TYPE_INT_ARGB);
// Create a DOM Document describing the metadata;
// I've gone the quick and dirty route. The description for PNG is at
// [http://download.oracle.com/javase/1.4.2/docs/api/javax/imageio/metadata/doc-files/png_metadata.html][1]
Calendar c = Calendar.getInstance();
String xml = "<?xml version='1.0'?><javax_imageio_png_1.0><tIME year='"+c.get(c.YEAR)+"' month='"+(c.get(c.MONTH)+1)+"' day='"+c.get(c.DAY_OF_MONTH)+"' hour='"+c.get(c.HOUR_OF_DAY)+"' minute='"+c.get(c.MINUTE)+"' second='"+c.get(c.SECOND)+"'/><pHYs pixelsPerUnitXAxis='"+11811+"' pixelsPerUnitYAxis='"+11811+"' unitSpecifier='meter'/></javax_imageio_png_1.0>";
DOMResult domresult = new DOMResult();
TransformerFactory.newInstance().newTransformer().transform(new StreamSource(new StringReader(xml)), domresult);
Document document = dom.getResult();
// Apply the metadata to the image
ImageWriter writer = (ImageWriter)ImageIO.getImageWritersBySuffix("png").next();
IIOMetadata meta = writer.getDefaultImageMetadata(new ImageTypeSpecifier(img), null);
meta.setFromTree(meta.getMetadataFormatNames()[0], document.getFirstChild());
FileOutputStream out = new FileOutputStream("out.png");
writer.setOutput(ImageIO.createImageOutputStream(out));
writer.write(new IIOImage(img, null, meta));
out.close();
使用 Java 1.6,我将 Mike 的代码编辑为
Node document = domresult.getNode();
而不是他的线
Document document = dom.getResult();
此外,我建议添加一行
writer.dispose()
工作完成后,释放作者持有的任何资源。
试试 Sixlegs Java PNG 库 ( http://sixlegs.com/software/png/ )。它声称支持所有块类型并进行私有块处理。
老问题,但是... PNGJ 可以完全控制读取和写入 PNG 块