13

我目前正在使用 javax.imageio.ImageIO 来编写 PNG 文件。我想包含一个文本块(实际上是此处列出的任何块),但看不到这样做的方法。

从 com.sun.imageio.plugins.png.PNGMetadata 看起来应该是可能的。

我应该非常感谢任何线索或答案。

M。

4

6 回答 6

10

经过一些反编译后我想到的解决方案如下......

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 );
于 2009-04-07T07:24:17.837 回答
1

我们在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 块应用相同的想法,但压缩文本部分确实允许相当大的文本部分。

于 2010-09-20T10:48:35.603 回答
1

我意识到这个问题早已得到解答,但如果您想在不深入“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();
于 2011-03-30T12:15:58.233 回答
1

使用 Java 1.6,我将 Mike 的代码编辑为

Node document = domresult.getNode();

而不是他的线

Document document = dom.getResult();

此外,我建议添加一行

writer.dispose()

工作完成后,释放作者持有的任何资源。

于 2011-06-17T14:30:31.653 回答
0

试试 Sixlegs Java PNG 库 ( http://sixlegs.com/software/png/ )。它声称支持所有块类型并进行私有块处理。

于 2009-04-06T15:34:43.610 回答
0

老问题,但是... PNGJ 可以完全控制读取和写入 PNG 块

于 2013-02-17T13:58:20.653 回答