Как я могу сохранить PNG с фрагментом tEXt или iTXt из Java? - PullRequest
11 голосов
/ 06 апреля 2009

В настоящее время я использую javax.imageio.ImageIO для записи файла PNG. Я хотел бы включить блок TEXt (и любой из перечисленных здесь блоков ), но не вижу средств для этого.

Судя по всему com.sun.imageio.plugins.png.PNGMetadata это возможно.

Я был бы очень благодарен за любые подсказки или ответы.

М.

Ответы [ 6 ]

10 голосов
/ 07 апреля 2009

Решение, с которым я столкнулся после некоторой декомпиляции, выглядит следующим образом ...

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 );
1 голос
/ 17 июня 2011

Используя Java 1.6, я отредактировал код Майка до

Node document = domresult.getNode();

вместо своей линии

Document document = dom.getResult();

Более того, я бы предложил добавить строку

writer.dispose()

после выполнения задания, чтобы освободить все ресурсы, которыми владеет писатель.

0 голосов
/ 17 февраля 2013

Старый вопрос, но ... PNGJ дает полный контроль над чтением и записью фрагментов PNG

0 голосов
/ 30 марта 2011

Я понимаю, что на этот вопрос уже давно дан ответ, но если вы хотите сделать это, не углубляясь в иерархию "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();
0 голосов
/ 20 сентября 2010

Мы делаем это в проекте JGraphX ​​. Скачайте исходный код и посмотрите в пакет com.mxgraph.util.png, там вы найдете три класса для кодирования, которые мы скопировали из исходников Apache Batik. Пример использования находится в com.mxgraph.examples.swing.editor.EditorActions в методе saveXmlPng. Слегка отредактированный код выглядит так:

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 - это BufferedImage, который будет формировать .PNG, а xml - это строка, которую мы хотим разместить в разделе iTxt. «mxGraphModel» является ключом для этой строки XML (раздел содержит некоторое количество пар ключ / значение), очевидно, вы заменяете его своим ключом.

Также в com.mxgraph.util.png мы написали действительно простой класс, который извлекает iTxt без обработки всего изображения. Вы можете применить ту же идею для блока tEXt, используя mxPngEncodeParam.setText вместо setCompressedText (), но секция сжатого текста допускает значительно большие текстовые секции.

0 голосов
/ 06 апреля 2009

Попробуйте библиотеку Sixlegs Java PNG (http://sixlegs.com/software/png/). Он утверждает, что поддерживает все типы чанков и выполняет приватную обработку чанков.

...