40
40
import org.apache.xmlgraphics.image.writer.ImageWriter;
41
41
import org.apache.xmlgraphics.image.writer.ImageWriterParams;
42
42
import org.apache.xmlgraphics.image.writer.MultiImageWriter;
43
import org.apache.xmlgraphics.image.writer.ResolutionUnit;
44
import org.apache.xmlgraphics.util.UnitConv;
45
47
* ImageWriter implementation that uses Image I/O to write images.
47
* @version $Id: ImageIOImageWriter.java 750418 2009-03-05 11:03:54Z vhennebert $
49
* @version $Id: ImageIOImageWriter.java 1610846 2014-07-15 20:44:18Z vhennebert $
49
51
public class ImageIOImageWriter implements ImageWriter, IIOWriteWarningListener {
53
private static final String DIMENSION = "Dimension";
54
private static final String VERTICAL_PIXEL_SIZE = "VerticalPixelSize";
55
private static final String HORIZONTAL_PIXEL_SIZE = "HorizontalPixelSize";
51
57
private static final String STANDARD_METADATA_FORMAT = "javax_imageio_1.0";
53
59
private String targetMIME;
94
98
//meta might be null for some JAI codecs as they don't support metadata
95
99
if (params != null && meta != null) {
96
meta = updateMetadata(meta, params);
100
meta = updateMetadata(image, meta, params);
100
104
iiowriter.setOutput(imgout);
101
105
IIOImage iioimg = new IIOImage(image, null, meta);
102
iiowriter.write(null, iioimg, iwParam);
106
iiowriter.write(streamMetadata, iioimg, iwParam);
115
* Creates the stream metadata for image. By default, this method returns null which
116
* causes the default stream metadata to be used. Subclasses can override this to
117
* supply special stream metadata (see TIFF for an example).
118
* @param writer the image write
119
* @param writeParam the ImageIO write parameters
120
* @param params the ImageWriter write parameters
121
* @return the stream metadata (or null if no special metadata needs to be produced)
123
protected IIOMetadata createStreamMetadata(javax.imageio.ImageWriter writer,
124
ImageWriteParam writeParam, ImageWriterParams params) {
125
return null; //leave the default
110
128
private javax.imageio.ImageWriter getIIOImageWriter() {
111
Iterator iter = ImageIO.getImageWritersByMIMEType(getMIMEType());
129
Iterator<javax.imageio.ImageWriter> iter = ImageIO.getImageWritersByMIMEType(getMIMEType());
112
130
javax.imageio.ImageWriter iiowriter = null;
113
131
if (iter.hasNext()) {
114
iiowriter = (javax.imageio.ImageWriter)iter.next();
132
iiowriter = iter.next();
116
134
if (iiowriter == null) {
117
135
throw new UnsupportedOperationException("No ImageIO codec for writing "
143
161
* Updates the metadata information based on the parameters to this writer.
162
* @param image the current image being rendered
144
163
* @param meta the metadata
145
164
* @param params the parameters
146
165
* @return the updated metadata
148
protected IIOMetadata updateMetadata(IIOMetadata meta, ImageWriterParams params) {
149
if (meta.isStandardMetadataFormatSupported()) {
150
IIOMetadataNode root = (IIOMetadataNode)meta.getAsTree(STANDARD_METADATA_FORMAT);
151
IIOMetadataNode dim = getChildNode(root, "Dimension");
152
IIOMetadataNode child;
153
if (params.getResolution() != null) {
154
child = getChildNode(dim, "HorizontalPixelSize");
156
child = new IIOMetadataNode("HorizontalPixelSize");
157
dim.appendChild(child);
159
child.setAttribute("value",
160
Double.toString(params.getResolution().doubleValue() / 25.4));
161
child = getChildNode(dim, "VerticalPixelSize");
163
child = new IIOMetadataNode("VerticalPixelSize");
164
dim.appendChild(child);
166
child.setAttribute("value",
167
Double.toString(params.getResolution().doubleValue() / 25.4));
170
meta.mergeTree(STANDARD_METADATA_FORMAT, root);
171
} catch (IIOInvalidTreeException e) {
172
throw new RuntimeException("Cannot update image metadata: "
167
protected IIOMetadata updateMetadata(RenderedImage image, IIOMetadata meta,
168
ImageWriterParams params) {
169
if (meta.isStandardMetadataFormatSupported() && params.getResolution() != null) {
171
//NOTE: There are several bugs in ImageIO codecs concerning resolution handling
172
//http://www.tracemodeler.com/articles/aging-bugs-and-setting-dpi-with-java-image-io/
174
float multiplier = (ResolutionUnit.CENTIMETER == params.getResolutionUnit()) ? 10f : UnitConv.IN2MM;
175
double pixelWidthInMillimeters = multiplier / params.getXResolution().doubleValue();
176
double pixelHeightInMillimeters = multiplier / params.getYResolution().doubleValue();
178
//Try with the right value as per the ImageIO spec
179
updatePixelSize(meta, pixelWidthInMillimeters, pixelHeightInMillimeters);
181
//Check the merge result
182
double checkMerged = getHorizontalPixelSize(meta);
183
if (!equals(checkMerged, pixelWidthInMillimeters, 0.00001)) {
184
//Merging bug in Sun/Oracle JRE encountered
185
//Try compensation strategy for PNG bug:
186
//http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5106305
187
double horzValue = 1 / pixelWidthInMillimeters;
188
double vertValue = 1 / pixelHeightInMillimeters;
189
updatePixelSize(meta, horzValue, vertValue);
195
private static boolean equals(double d1, double d2, double maxDelta) {
196
return Math.abs(d1 - d2) <= maxDelta;
199
private double getHorizontalPixelSize(IIOMetadata meta) {
201
IIOMetadataNode root = (IIOMetadataNode)meta.getAsTree(STANDARD_METADATA_FORMAT);
202
IIOMetadataNode dim = getChildNode(root, DIMENSION);
204
IIOMetadataNode horz = getChildNode(dim, HORIZONTAL_PIXEL_SIZE);
206
result = Double.parseDouble(horz.getAttribute("value"));
212
private void updatePixelSize(IIOMetadata meta, double horzValue, double vertValue) {
213
IIOMetadataNode root = (IIOMetadataNode)meta.getAsTree(STANDARD_METADATA_FORMAT);
214
IIOMetadataNode dim = getChildNode(root, DIMENSION);
215
IIOMetadataNode child;
217
child = getChildNode(dim, HORIZONTAL_PIXEL_SIZE);
219
child = new IIOMetadataNode(HORIZONTAL_PIXEL_SIZE);
220
dim.appendChild(child);
222
child.setAttribute("value", Double.toString(horzValue));
224
child = getChildNode(dim, VERTICAL_PIXEL_SIZE);
226
child = new IIOMetadataNode(VERTICAL_PIXEL_SIZE);
227
dim.appendChild(child);
229
child.setAttribute("value", Double.toString(vertValue));
231
meta.mergeTree(STANDARD_METADATA_FORMAT, root);
232
} catch (IIOInvalidTreeException e) {
233
throw new RuntimeException("Cannot update image metadata: "
180
239
* Returns a specific metadata child node
181
240
* @param n the base node
196
/** @see ImageWriter#getMIMEType() */
197
256
public String getMIMEType() {
198
257
return this.targetMIME;
201
/** @see org.apache.xmlgraphics.image.writer.ImageWriter#isFunctional() */
202
261
public boolean isFunctional() {
203
Iterator iter = ImageIO.getImageWritersByMIMEType(getMIMEType());
262
Iterator<javax.imageio.ImageWriter> iter = ImageIO.getImageWritersByMIMEType(getMIMEType());
204
263
//Only return true if an IIO ImageWriter is available in the current environment
205
264
return (iter.hasNext());
209
* @see javax.imageio.event.IIOWriteWarningListener#warningOccurred(
210
* javax.imageio.ImageWriter, int, java.lang.String)
212
268
public void warningOccurred(javax.imageio.ImageWriter source,
213
269
int imageIndex, String warning) {
214
270
System.err.println("Problem while writing image using ImageI/O: "
219
* @see org.apache.xmlgraphics.image.writer.ImageWriter#createMultiImageWriter(
220
* java.io.OutputStream)
222
275
public MultiImageWriter createMultiImageWriter(OutputStream out) throws IOException {
223
276
return new IIOMultiImageWriter(out);
226
/** @see org.apache.xmlgraphics.image.writer.ImageWriter#supportsMultiImageWriter() */
227
280
public boolean supportsMultiImageWriter() {
228
281
javax.imageio.ImageWriter iiowriter = getIIOImageWriter();