/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id: ImageIOTIFFImageWriter.java 1833700 2018-06-18 10:08:45Z ssteiner $ */
package org.apache.xmlgraphics.image.writer.imageio;
import java.awt.image.RenderedImage;
import java.util.Arrays;
import java.util.Set;
import javax.imageio.ImageWriteParam;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import org.w3c.dom.Node;
import org.apache.xmlgraphics.image.codec.tiff.TIFFImageDecoder;
import org.apache.xmlgraphics.image.writer.Endianness;
import org.apache.xmlgraphics.image.writer.ImageWriterParams;
import org.apache.xmlgraphics.image.writer.ResolutionUnit;
// CSOFF: MultipleVariableDeclarations
ImageWriter that encodes TIFF images using Image I/O.
Version: $Id: ImageIOTIFFImageWriter.java 1833700 2018-06-18 10:08:45Z ssteiner $
/**
* ImageWriter that encodes TIFF images using Image I/O.
*
* @version $Id: ImageIOTIFFImageWriter.java 1833700 2018-06-18 10:08:45Z ssteiner $
*/
public class ImageIOTIFFImageWriter extends ImageIOImageWriter {
private static final String SUN_TIFF_NATIVE_FORMAT
= "com_sun_media_imageio_plugins_tiff_image_1.0";
private static final String JAVA_TIFF_NATIVE_FORMAT
= "javax_imageio_tiff_image_1.0";
private static final String SUN_TIFF_NATIVE_STREAM_FORMAT
= "com_sun_media_imageio_plugins_tiff_stream_1.0";
private static final String JAVA_TIFF_NATIVE_STREAM_FORMAT
= "javax_imageio_tiff_stream_1.0";
Main constructor.
/**
* Main constructor.
*/
public ImageIOTIFFImageWriter() {
super("image/tiff");
}
{@inheritDoc} /** {@inheritDoc} */
@Override
protected IIOMetadata updateMetadata(RenderedImage image, IIOMetadata meta,
ImageWriterParams params) {
meta = super.updateMetadata(image, meta, params);
//We set the resolution manually using the native format since it appears that
//it doesn't work properly through the standard metadata. Haven't figured out why
//that happens.
if (params.getResolution() != null) {
if (SUN_TIFF_NATIVE_FORMAT.equals(meta.getNativeMetadataFormatName())
|| JAVA_TIFF_NATIVE_FORMAT.equals(meta.getNativeMetadataFormatName())) {
IIOMetadataNode root = new IIOMetadataNode(meta.getNativeMetadataFormatName());
IIOMetadataNode ifd = getChildNode(root, "TIFFIFD");
if (ifd == null) {
ifd = new IIOMetadataNode("TIFFIFD");
root.appendChild(ifd);
}
ifd.appendChild(createResolutionUnitField(params));
ifd.appendChild(createResolutionField(TIFFImageDecoder.TIFF_X_RESOLUTION,
"XResolution", params.getXResolution(), params.getResolutionUnit()));
ifd.appendChild(createResolutionField(TIFFImageDecoder.TIFF_Y_RESOLUTION,
"YResolution", params.getYResolution(), params.getResolutionUnit()));
int rows = params.isSingleStrip() ? image.getHeight() : params.getRowsPerStrip();
ifd.appendChild(createShortMetadataNode(TIFFImageDecoder.TIFF_ROWS_PER_STRIP,
"RowsPerStrip", Integer.toString(rows)));
try {
meta.mergeTree(meta.getNativeMetadataFormatName(), root);
} catch (IIOInvalidTreeException e) {
throw new RuntimeException("Cannot update image metadata: "
+ e.getMessage(), e);
}
}
}
return meta;
}
//number of pixels in 100 Meters
private static final String DENOMINATOR_CENTIMETER = "/" + (100 * 100);
private static final String DENOMINATOR_INCH = "/" + 1;
private IIOMetadataNode createResolutionField(int number, String name,
Integer resolution, ResolutionUnit unit) {
String value;
if (unit == ResolutionUnit.INCH) {
value = resolution + DENOMINATOR_INCH;
} else {
float pixSzMM = 25.4f / resolution.floatValue();
int numPix = (int)(((1000 * 100) / pixSzMM) + 0.5);
value = numPix + DENOMINATOR_CENTIMETER;
}
return createRationalMetadataNode(number, name, value);
}
Generate a TIFFField for resolution unit based on the parameters.
Params: - params –
Returns: the new metadata node
/**
* Generate a TIFFField for resolution unit based on the parameters.
* @param params
* @return the new metadata node
*/
private IIOMetadataNode createResolutionUnitField(ImageWriterParams params) {
return createShortMetadataNode(TIFFImageDecoder.TIFF_RESOLUTION_UNIT, "ResolutionUnit",
Integer.toString(params.getResolutionUnit().getValue()),
params.getResolutionUnit().getDescription());
}
Utility to create a TIFFShort metadata child node of a TIFFShorts node for TIFF metadata.
Params: - number – value of the number attribute of the TIFField
- name – value of the name attribute of the TIFFField
- value – value of the value attribute of the TIFFShort
Returns: the new metadata node
/**
* Utility to create a TIFFShort metadata child node of a TIFFShorts node for TIFF metadata.
*
* @param number value of the number attribute of the TIFField
* @param name value of the name attribute of the TIFFField
* @param value value of the value attribute of the TIFFShort
* @return the new metadata node
*/
public static final IIOMetadataNode createShortMetadataNode(int number,
String name, String value) {
return createShortMetadataNode(number, name, value, null);
}
Utility to create a TIFFShort metadata child node of a TIFFShorts node for TIFF metadata.
Params: - number – value of the number attribute of the TIFField
- name – value of the name attribute of the TIFFField
- value – value of the value attribute of the TIFFShort
- description – value of the description attribute of the TIFFShort, ignored if null
Returns: the new metadata node
/**
* Utility to create a TIFFShort metadata child node of a TIFFShorts node for TIFF metadata.
*
* @param number value of the number attribute of the TIFField
* @param name value of the name attribute of the TIFFField
* @param value value of the value attribute of the TIFFShort
* @param description value of the description attribute of the TIFFShort, ignored if null
* @return the new metadata node
*/
public static final IIOMetadataNode createShortMetadataNode(int number, String name,
String value, String description) {
IIOMetadataNode field = createMetadataField(number, name);
IIOMetadataNode arrayNode;
IIOMetadataNode valueNode;
arrayNode = new IIOMetadataNode("TIFFShorts");
field.appendChild(arrayNode);
valueNode = new IIOMetadataNode("TIFFShort");
valueNode.setAttribute("value", value);
if (description != null) {
valueNode.setAttribute("description", description);
}
arrayNode.appendChild(valueNode);
return field;
}
Utility to create a TIFFRational metadata child node of a TIFFRationals node for
TIFF metadata.
Params: - number – value of the number attribute of the TIFField
- name – value of the name attribute of the TIFFField
- value – value of the value attribute of the TIFFRational
Returns: the new metadata node
/**
* Utility to create a TIFFRational metadata child node of a TIFFRationals node for
* TIFF metadata.
*
* @param number value of the number attribute of the TIFField
* @param name value of the name attribute of the TIFFField
* @param value value of the value attribute of the TIFFRational
* @return the new metadata node
*/
public static final IIOMetadataNode createRationalMetadataNode(int number,
String name, String value) {
IIOMetadataNode field = createMetadataField(number, name);
IIOMetadataNode arrayNode;
IIOMetadataNode valueNode;
arrayNode = new IIOMetadataNode("TIFFRationals");
field.appendChild(arrayNode);
valueNode = new IIOMetadataNode("TIFFRational");
valueNode.setAttribute("value", value);
arrayNode.appendChild(valueNode);
return field;
}
Utility function to create a base TIFFField node for TIFF metadata.
Params: - number – value of the number attribute of the TIFField
- name – value of the name attribute of the TIFFField
Returns: the new metadata node
/**
* Utility function to create a base TIFFField node for TIFF metadata.
*
* @param number value of the number attribute of the TIFField
* @param name value of the name attribute of the TIFFField
* @return the new metadata node
*/
public static final IIOMetadataNode createMetadataField(int number, String name) {
IIOMetadataNode field = new IIOMetadataNode("TIFFField");
field.setAttribute("number", Integer.toString(number));
field.setAttribute("name", name);
return field;
}
{@inheritDoc} /** {@inheritDoc} */
@Override
protected IIOMetadata createStreamMetadata(javax.imageio.ImageWriter writer,
ImageWriteParam writeParam, ImageWriterParams params) {
Endianness endian = (params != null ? params.getEndianness() : Endianness.DEFAULT);
if (endian == Endianness.DEFAULT || endian == null) {
return super.createStreamMetadata(writer, writeParam, params);
}
//Try changing the Byte Order
IIOMetadata streamMetadata = writer.getDefaultStreamMetadata(writeParam);
if (streamMetadata != null) {
Set<String> names = new java.util.HashSet<String>(
Arrays.asList(streamMetadata.getMetadataFormatNames()));
setFromTree(names, streamMetadata, endian, SUN_TIFF_NATIVE_STREAM_FORMAT);
setFromTree(names, streamMetadata, endian, JAVA_TIFF_NATIVE_STREAM_FORMAT);
}
return streamMetadata;
}
private void setFromTree(Set<String> names, IIOMetadata streamMetadata, Endianness endian, String format) {
if (names.contains(format)) {
Node root = streamMetadata.getAsTree(format);
root.getFirstChild().getAttributes().item(0).setNodeValue(endian.toString());
try {
streamMetadata.setFromTree(format, root);
} catch (IIOInvalidTreeException e) {
//This should not happen since we check if the format is supported.
throw new IllegalStateException(
"Could not replace TIFF stream metadata: " + e.getMessage(), e);
}
}
}
}