~hjd/ubuntu/wily/xmlgraphics-commons/debian-merged

« back to all changes in this revision

Viewing changes to src/java/org/apache/xmlgraphics/image/writer/imageio/ImageIOImageWriter.java

  • Committer: Hans Joachim Desserud
  • Date: 2015-11-11 18:22:53 UTC
  • mfrom: (9.1.5 sid)
  • Revision ID: hans_joachim_desserud-20151111182253-zwi0frfm97j0wddn
  * Merge from Debian unstable.  Remaining changes:
    - d/control: Drop dependencies required for unit testing as they
      include libmockito-java which would pull maven into main, disable unit
      test execution.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 * limitations under the License.
16
16
 */
17
17
 
18
 
/* $Id: ImageIOImageWriter.java 750418 2009-03-05 11:03:54Z vhennebert $ */
 
18
/* $Id: ImageIOImageWriter.java 1610846 2014-07-15 20:44:18Z vhennebert $ */
19
19
 
20
20
package org.apache.xmlgraphics.image.writer.imageio;
21
21
 
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;
43
45
 
44
46
/**
45
47
 * ImageWriter implementation that uses Image I/O to write images.
46
48
 *
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 $
48
50
 */
49
51
public class ImageIOImageWriter implements ImageWriter, IIOWriteWarningListener {
50
52
 
 
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";
 
56
 
51
57
    private static final String STANDARD_METADATA_FORMAT = "javax_imageio_1.0";
52
58
 
53
59
    private String targetMIME;
60
66
        this.targetMIME = mime;
61
67
    }
62
68
 
63
 
    /**
64
 
     * @see ImageWriter#writeImage(java.awt.image.RenderedImage, java.io.OutputStream)
65
 
     */
 
69
    /** {@inheritDoc} */
66
70
    public void writeImage(RenderedImage image, OutputStream out) throws IOException {
67
71
        writeImage(image, out, null);
68
72
    }
69
73
 
70
 
    /**
71
 
     * @see ImageWriter#writeImage(java.awt.image.RenderedImage, java.io.OutputStream, ImageWriterParams)
72
 
     */
 
74
    /** {@inheritDoc} */
73
75
    public void writeImage(RenderedImage image, OutputStream out,
74
76
            ImageWriterParams params)
75
77
                throws IOException {
81
83
 
82
84
            ImageWriteParam iwParam = getDefaultWriteParam(iiowriter, image, params);
83
85
 
 
86
            IIOMetadata streamMetadata = createStreamMetadata(iiowriter, iwParam, params);
 
87
 
84
88
            ImageTypeSpecifier type;
85
89
            if (iwParam.getDestinationType() != null) {
86
90
                type = iwParam.getDestinationType();
93
97
                    type, iwParam);
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);
97
101
            }
98
102
 
99
103
            //Write image
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);
103
107
 
104
108
        } finally {
105
109
            imgout.close();
107
111
        }
108
112
    }
109
113
 
 
114
    /**
 
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)
 
122
     */
 
123
    protected IIOMetadata createStreamMetadata(javax.imageio.ImageWriter writer,
 
124
            ImageWriteParam writeParam, ImageWriterParams params) {
 
125
        return null; //leave the default
 
126
    }
 
127
 
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();
115
133
        }
116
134
        if (iiowriter == null) {
117
135
            throw new UnsupportedOperationException("No ImageIO codec for writing "
141
159
 
142
160
    /**
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
147
166
     */
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");
155
 
                if (child == null) {
156
 
                    child = new IIOMetadataNode("HorizontalPixelSize");
157
 
                    dim.appendChild(child);
158
 
                }
159
 
                child.setAttribute("value",
160
 
                        Double.toString(params.getResolution().doubleValue() / 25.4));
161
 
                child = getChildNode(dim, "VerticalPixelSize");
162
 
                if (child == null) {
163
 
                    child = new IIOMetadataNode("VerticalPixelSize");
164
 
                    dim.appendChild(child);
165
 
                }
166
 
                child.setAttribute("value",
167
 
                        Double.toString(params.getResolution().doubleValue() / 25.4));
168
 
            }
169
 
            try {
170
 
                meta.mergeTree(STANDARD_METADATA_FORMAT, root);
171
 
            } catch (IIOInvalidTreeException e) {
172
 
                throw new RuntimeException("Cannot update image metadata: "
173
 
                            + e.getMessage());
 
167
    protected IIOMetadata updateMetadata(RenderedImage image, IIOMetadata meta,
 
168
                ImageWriterParams params) {
 
169
        if (meta.isStandardMetadataFormatSupported() && params.getResolution() != null) {
 
170
 
 
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/
 
173
 
 
174
            float multiplier = (ResolutionUnit.CENTIMETER == params.getResolutionUnit()) ? 10f : UnitConv.IN2MM;
 
175
            double pixelWidthInMillimeters = multiplier / params.getXResolution().doubleValue();
 
176
            double pixelHeightInMillimeters = multiplier / params.getYResolution().doubleValue();
 
177
 
 
178
            //Try with the right value as per the ImageIO spec
 
179
            updatePixelSize(meta, pixelWidthInMillimeters, pixelHeightInMillimeters);
 
180
 
 
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);
174
190
            }
175
191
        }
176
192
        return meta;
177
193
    }
178
194
 
 
195
    private static boolean equals(double d1, double d2, double maxDelta) {
 
196
        return Math.abs(d1 - d2) <= maxDelta;
 
197
    }
 
198
 
 
199
    private double getHorizontalPixelSize(IIOMetadata meta) {
 
200
        double result = 0;
 
201
        IIOMetadataNode root = (IIOMetadataNode)meta.getAsTree(STANDARD_METADATA_FORMAT);
 
202
        IIOMetadataNode dim = getChildNode(root, DIMENSION);
 
203
        if (dim != null) {
 
204
            IIOMetadataNode horz = getChildNode(dim, HORIZONTAL_PIXEL_SIZE);
 
205
            if (horz != null) {
 
206
                result = Double.parseDouble(horz.getAttribute("value"));
 
207
            }
 
208
        }
 
209
        return result;
 
210
    }
 
211
 
 
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;
 
216
 
 
217
        child = getChildNode(dim, HORIZONTAL_PIXEL_SIZE);
 
218
        if (child == null) {
 
219
            child = new IIOMetadataNode(HORIZONTAL_PIXEL_SIZE);
 
220
            dim.appendChild(child);
 
221
        }
 
222
        child.setAttribute("value", Double.toString(horzValue));
 
223
 
 
224
        child = getChildNode(dim, VERTICAL_PIXEL_SIZE);
 
225
        if (child == null) {
 
226
            child = new IIOMetadataNode(VERTICAL_PIXEL_SIZE);
 
227
            dim.appendChild(child);
 
228
        }
 
229
        child.setAttribute("value", Double.toString(vertValue));
 
230
        try {
 
231
            meta.mergeTree(STANDARD_METADATA_FORMAT, root);
 
232
        } catch (IIOInvalidTreeException e) {
 
233
            throw new RuntimeException("Cannot update image metadata: "
 
234
                        + e.getMessage());
 
235
        }
 
236
    }
 
237
 
179
238
    /**
180
239
     * Returns a specific metadata child node
181
240
     * @param n the base node
193
252
        return null;
194
253
    }
195
254
 
196
 
    /** @see ImageWriter#getMIMEType() */
 
255
    /** {@inheritDoc} */
197
256
    public String getMIMEType() {
198
257
        return this.targetMIME;
199
258
    }
200
259
 
201
 
    /** @see org.apache.xmlgraphics.image.writer.ImageWriter#isFunctional() */
 
260
    /** {@inheritDoc} */
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());
206
265
    }
207
266
 
208
 
    /**
209
 
     * @see javax.imageio.event.IIOWriteWarningListener#warningOccurred(
210
 
     *          javax.imageio.ImageWriter, int, java.lang.String)
211
 
     */
 
267
    /** {@inheritDoc} */
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: "
215
271
                + warning);
216
272
    }
217
273
 
218
 
    /**
219
 
     * @see org.apache.xmlgraphics.image.writer.ImageWriter#createMultiImageWriter(
220
 
     *          java.io.OutputStream)
221
 
     */
 
274
    /** {@inheritDoc} */
222
275
    public MultiImageWriter createMultiImageWriter(OutputStream out) throws IOException {
223
276
        return new IIOMultiImageWriter(out);
224
277
    }
225
278
 
226
 
    /** @see org.apache.xmlgraphics.image.writer.ImageWriter#supportsMultiImageWriter() */
 
279
    /** {@inheritDoc} */
227
280
    public boolean supportsMultiImageWriter() {
228
281
        javax.imageio.ImageWriter iiowriter = getIIOImageWriter();
229
282
        try {
237
290
 
238
291
        private javax.imageio.ImageWriter iiowriter;
239
292
        private ImageOutputStream imageStream;
 
293
        private boolean prepared;
240
294
 
241
295
        public IIOMultiImageWriter(OutputStream out) throws IOException {
242
296
            this.iiowriter = getIIOImageWriter();
248
302
 
249
303
            imageStream = ImageIO.createImageOutputStream(out);
250
304
            iiowriter.setOutput(imageStream);
251
 
            iiowriter.prepareWriteSequence(null);
 
305
 
252
306
        }
253
307
 
254
308
        public void writeImage(RenderedImage image, ImageWriterParams params) throws IOException {
257
311
            }
258
312
            ImageWriteParam iwParam = getDefaultWriteParam(iiowriter, image, params);
259
313
 
 
314
            if (!prepared) {
 
315
                //Only prepare once
 
316
                IIOMetadata streamMetadata = createStreamMetadata(iiowriter, iwParam, params);
 
317
                iiowriter.prepareWriteSequence(streamMetadata);
 
318
                prepared = true;
 
319
            }
 
320
 
260
321
            ImageTypeSpecifier type;
261
322
            if (iwParam.getDestinationType() != null) {
262
323
                type = iwParam.getDestinationType();
269
330
                    type, iwParam);
270
331
            //meta might be null for some JAI codecs as they don't support metadata
271
332
            if (params != null && meta != null) {
272
 
                meta = updateMetadata(meta, params);
 
333
                meta = updateMetadata(image, meta, params);
273
334
            }
274
335
 
275
336
            //Write image