1/*
2 * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.imageio;
27
28import java.awt.Point;
29import java.awt.Rectangle;
30
31/**
32 * A superclass of all classes describing how streams should be
33 * decoded or encoded.  This class contains all the variables and
34 * methods that are shared by {@code ImageReadParam} and
35 * {@code ImageWriteParam}.
36 *
37 * <p> This class provides mechanisms to specify a source region and a
38 * destination region.  When reading, the source is the stream and
39 * the in-memory image is the destination.  When writing, these are
40 * reversed.  In the case of writing, destination regions may be used
41 * only with a writer that supports pixel replacement.
42 * <p>
43 * Decimation subsampling may be specified for both readers
44 * and writers, using a movable subsampling grid.
45 * <p>
46 * Subsets of the source and destination bands may be selected.
47 *
48 */
49public abstract class IIOParam {
50
51    /**
52     * The source region, on {@code null} if none is set.
53     */
54    protected Rectangle sourceRegion = null;
55
56    /**
57     * The decimation subsampling to be applied in the horizontal
58     * direction.  By default, the value is {@code 1}.
59     * The value must not be negative or 0.
60     */
61    protected int sourceXSubsampling = 1;
62
63    /**
64     * The decimation subsampling to be applied in the vertical
65     * direction.  By default, the value is {@code 1}.
66     * The value must not be negative or 0.
67     */
68    protected int sourceYSubsampling = 1;
69
70    /**
71     * A horizontal offset to be applied to the subsampling grid before
72     * subsampling.  The first pixel to be used will be offset this
73     * amount from the origin of the region, or of the image if no
74     * region is specified.
75     */
76    protected int subsamplingXOffset = 0;
77
78    /**
79     * A vertical offset to be applied to the subsampling grid before
80     * subsampling.  The first pixel to be used will be offset this
81     * amount from the origin of the region, or of the image if no
82     * region is specified.
83     */
84    protected int subsamplingYOffset = 0;
85
86    /**
87     * An array of {@code int}s indicating which source bands
88     * will be used, or {@code null}.  If {@code null}, the
89     * set of source bands to be used is as described in the comment
90     * for the {@code setSourceBands} method.  No value should
91     * be allowed to be negative.
92     */
93    protected int[] sourceBands = null;
94
95    /**
96     * An {@code ImageTypeSpecifier} to be used to generate a
97     * destination image when reading, or to set the output color type
98     * when writing.  If non has been set the value will be
99     * {@code null}.  By default, the value is {@code null}.
100     */
101    protected ImageTypeSpecifier destinationType = null;
102
103    /**
104     * The offset in the destination where the upper-left decoded
105     * pixel should be placed.  By default, the value is (0, 0).
106     */
107    protected Point destinationOffset = new Point(0, 0);
108
109    /**
110     * The default {@code IIOParamController} that will be
111     * used to provide settings for this {@code IIOParam}
112     * object when the {@code activateController} method
113     * is called.  This default should be set by subclasses
114     * that choose to provide their own default controller,
115     * usually a GUI, for setting parameters.
116     *
117     * @see IIOParamController
118     * @see #getDefaultController
119     * @see #activateController
120     */
121    protected IIOParamController defaultController = null;
122
123    /**
124     * The {@code IIOParamController} that will be
125     * used to provide settings for this {@code IIOParam}
126     * object when the {@code activateController} method
127     * is called.  This value overrides any default controller,
128     * even when null.
129     *
130     * @see IIOParamController
131     * @see #setController(IIOParamController)
132     * @see #hasController()
133     * @see #activateController()
134     */
135    protected IIOParamController controller = null;
136
137    /**
138     * Protected constructor may be called only by subclasses.
139     */
140    protected IIOParam() {
141        controller = defaultController;
142    }
143
144    /**
145     * Sets the source region of interest.  The region of interest is
146     * described as a rectangle, with the upper-left corner of the
147     * source image as pixel (0, 0) and increasing values down and to
148     * the right.  The actual number of pixels used will depend on
149     * the subsampling factors set by {@code setSourceSubsampling}.
150     * If subsampling has been set such that this number is zero,
151     * an {@code IllegalStateException} will be thrown.
152     *
153     * <p> The source region of interest specified by this method will
154     * be clipped as needed to fit within the source bounds, as well
155     * as the destination offsets, width, and height at the time of
156     * actual I/O.
157     *
158     * <p> A value of {@code null} for {@code sourceRegion}
159     * will remove any region specification, causing the entire image
160     * to be used.
161     *
162     * @param sourceRegion a {@code Rectangle} specifying the
163     * source region of interest, or {@code null}.
164     *
165     * @exception IllegalArgumentException if
166     * {@code sourceRegion} is non-{@code null} and either
167     * {@code sourceRegion.x} or {@code sourceRegion.y} is
168     * negative.
169     * @exception IllegalArgumentException if
170     * {@code sourceRegion} is non-{@code null} and either
171     * {@code sourceRegion.width} or
172     * {@code sourceRegion.height} is negative or 0.
173     * @exception IllegalStateException if subsampling is such that
174     * this region will have a subsampled width or height of zero.
175     *
176     * @see #getSourceRegion
177     * @see #setSourceSubsampling
178     * @see ImageReadParam#setDestinationOffset
179     * @see ImageReadParam#getDestinationOffset
180     */
181    public void setSourceRegion(Rectangle sourceRegion) {
182        if (sourceRegion == null) {
183            this.sourceRegion = null;
184            return;
185        }
186
187        if (sourceRegion.x < 0) {
188            throw new IllegalArgumentException("sourceRegion.x < 0!");
189        }
190        if (sourceRegion.y < 0){
191            throw new IllegalArgumentException("sourceRegion.y < 0!");
192        }
193        if (sourceRegion.width <= 0) {
194            throw new IllegalArgumentException("sourceRegion.width <= 0!");
195        }
196        if (sourceRegion.height <= 0) {
197            throw new IllegalArgumentException("sourceRegion.height <= 0!");
198        }
199
200        // Throw an IllegalStateException if region falls between subsamples
201        if (sourceRegion.width <= subsamplingXOffset) {
202            throw new IllegalStateException
203                ("sourceRegion.width <= subsamplingXOffset!");
204        }
205        if (sourceRegion.height <= subsamplingYOffset) {
206            throw new IllegalStateException
207                ("sourceRegion.height <= subsamplingYOffset!");
208        }
209
210        this.sourceRegion = (Rectangle)sourceRegion.clone();
211    }
212
213    /**
214     * Returns the source region to be used.  The returned value is
215     * that set by the most recent call to
216     * {@code setSourceRegion}, and will be {@code null} if
217     * there is no region set.
218     *
219     * @return the source region of interest as a
220     * {@code Rectangle}, or {@code null}.
221     *
222     * @see #setSourceRegion
223     */
224    public Rectangle getSourceRegion() {
225        if (sourceRegion == null) {
226            return null;
227        }
228        return (Rectangle)sourceRegion.clone();
229    }
230
231    /**
232     * Specifies a decimation subsampling to apply on I/O.  The
233     * {@code sourceXSubsampling} and
234     * {@code sourceYSubsampling} parameters specify the
235     * subsampling period (<i>i.e.</i>, the number of rows and columns
236     * to advance after every source pixel).  Specifically, a period of
237     * 1 will use every row or column; a period of 2 will use every
238     * other row or column.  The {@code subsamplingXOffset} and
239     * {@code subsamplingYOffset} parameters specify an offset
240     * from the region (or image) origin for the first subsampled pixel.
241     * Adjusting the origin of the subsample grid is useful for avoiding
242     * seams when subsampling a very large source image into destination
243     * regions that will be assembled into a complete subsampled image.
244     * Most users will want to simply leave these parameters at 0.
245     *
246     * <p> The number of pixels and scanlines to be used are calculated
247     * as follows.
248     * <p>
249     * The number of subsampled pixels in a scanline is given by
250     * <p>
251     * {@code truncate[(width - subsamplingXOffset + sourceXSubsampling - 1)
252     * / sourceXSubsampling]}.
253     * <p>
254     * If the region is such that this width is zero, an
255     * {@code IllegalStateException} is thrown.
256     * <p>
257     * The number of scanlines to be used can be computed similarly.
258     *
259     * <p>The ability to set the subsampling grid to start somewhere
260     * other than the source region origin is useful if the
261     * region is being used to create subsampled tiles of a large image,
262     * where the tile width and height are not multiples of the
263     * subsampling periods.  If the subsampling grid does not remain
264     * consistent from tile to tile, there will be artifacts at the tile
265     * boundaries.  By adjusting the subsampling grid offset for each
266     * tile to compensate, these artifacts can be avoided.  The tradeoff
267     * is that in order to avoid these artifacts, the tiles are not all
268     * the same size.  The grid offset to use in this case is given by:
269     * <br>
270     * grid offset = [period - (region offset modulo period)] modulo period)
271     *
272     * <p> If either {@code sourceXSubsampling} or
273     * {@code sourceYSubsampling} is 0 or negative, an
274     * {@code IllegalArgumentException} will be thrown.
275     *
276     * <p> If either {@code subsamplingXOffset} or
277     * {@code subsamplingYOffset} is negative or greater than or
278     * equal to the corresponding period, an
279     * {@code IllegalArgumentException} will be thrown.
280     *
281     * <p> There is no {@code unsetSourceSubsampling} method;
282     * simply call {@code setSourceSubsampling(1, 1, 0, 0)} to
283     * restore default values.
284     *
285     * @param sourceXSubsampling the number of columns to advance
286     * between pixels.
287     * @param sourceYSubsampling the number of rows to advance between
288     * pixels.
289     * @param subsamplingXOffset the horizontal offset of the first subsample
290     * within the region, or within the image if no region is set.
291     * @param subsamplingYOffset the horizontal offset of the first subsample
292     * within the region, or within the image if no region is set.
293     * @exception IllegalArgumentException if either period is
294     * negative or 0, or if either grid offset is negative or greater than
295     * the corresponding period.
296     * @exception IllegalStateException if the source region is such that
297     * the subsampled output would contain no pixels.
298     */
299    public void setSourceSubsampling(int sourceXSubsampling,
300                                     int sourceYSubsampling,
301                                     int subsamplingXOffset,
302                                     int subsamplingYOffset) {
303        if (sourceXSubsampling <= 0) {
304            throw new IllegalArgumentException("sourceXSubsampling <= 0!");
305        }
306        if (sourceYSubsampling <= 0) {
307            throw new IllegalArgumentException("sourceYSubsampling <= 0!");
308        }
309        if (subsamplingXOffset < 0 ||
310            subsamplingXOffset >= sourceXSubsampling) {
311            throw new IllegalArgumentException
312                ("subsamplingXOffset out of range!");
313        }
314        if (subsamplingYOffset < 0 ||
315            subsamplingYOffset >= sourceYSubsampling) {
316            throw new IllegalArgumentException
317                ("subsamplingYOffset out of range!");
318        }
319
320        // Throw an IllegalStateException if region falls between subsamples
321        if (sourceRegion != null) {
322            if (subsamplingXOffset >= sourceRegion.width ||
323                subsamplingYOffset >= sourceRegion.height) {
324                throw new IllegalStateException("region contains no pixels!");
325            }
326        }
327
328        this.sourceXSubsampling = sourceXSubsampling;
329        this.sourceYSubsampling = sourceYSubsampling;
330        this.subsamplingXOffset = subsamplingXOffset;
331        this.subsamplingYOffset = subsamplingYOffset;
332    }
333
334    /**
335     * Returns the number of source columns to advance for each pixel.
336     *
337     * <p>If {@code setSourceSubsampling} has not been called, 1
338     * is returned (which is the correct value).
339     *
340     * @return the source subsampling X period.
341     *
342     * @see #setSourceSubsampling
343     * @see #getSourceYSubsampling
344     */
345    public int getSourceXSubsampling() {
346        return sourceXSubsampling;
347    }
348
349    /**
350     * Returns the number of rows to advance for each pixel.
351     *
352     * <p>If {@code setSourceSubsampling} has not been called, 1
353     * is returned (which is the correct value).
354     *
355     * @return the source subsampling Y period.
356     *
357     * @see #setSourceSubsampling
358     * @see #getSourceXSubsampling
359     */
360    public int getSourceYSubsampling() {
361        return sourceYSubsampling;
362    }
363
364    /**
365     * Returns the horizontal offset of the subsampling grid.
366     *
367     * <p>If {@code setSourceSubsampling} has not been called, 0
368     * is returned (which is the correct value).
369     *
370     * @return the source subsampling grid X offset.
371     *
372     * @see #setSourceSubsampling
373     * @see #getSubsamplingYOffset
374     */
375    public int getSubsamplingXOffset() {
376        return subsamplingXOffset;
377    }
378
379    /**
380     * Returns the vertical offset of the subsampling grid.
381     *
382     * <p>If {@code setSourceSubsampling} has not been called, 0
383     * is returned (which is the correct value).
384     *
385     * @return the source subsampling grid Y offset.
386     *
387     * @see #setSourceSubsampling
388     * @see #getSubsamplingXOffset
389     */
390    public int getSubsamplingYOffset() {
391        return subsamplingYOffset;
392    }
393
394    /**
395     * Sets the indices of the source bands to be used.  Duplicate
396     * indices are not allowed.
397     *
398     * <p> A {@code null} value indicates that all source bands
399     * will be used.
400     *
401     * <p> At the time of reading, an
402     * {@code IllegalArgumentException} will be thrown by the
403     * reader or writer if a value larger than the largest available
404     * source band index has been specified or if the number of source
405     * bands and destination bands to be used differ.  The
406     * {@code ImageReader.checkReadParamBandSettings} method may
407     * be used to automate this test.
408     *
409     * <p> Semantically, a copy is made of the array; changes to the
410     * array contents subsequent to this call have no effect on
411     * this {@code IIOParam}.
412     *
413     * @param sourceBands an array of integer band indices to be
414     * used.
415     *
416     * @exception IllegalArgumentException if {@code sourceBands}
417     * contains a negative or duplicate value.
418     *
419     * @see #getSourceBands
420     * @see ImageReadParam#setDestinationBands
421     * @see ImageReader#checkReadParamBandSettings
422     */
423    public void setSourceBands(int[] sourceBands) {
424        if (sourceBands == null) {
425            this.sourceBands = null;
426        } else {
427            int numBands = sourceBands.length;
428            for (int i = 0; i < numBands; i++) {
429                int band = sourceBands[i];
430                if (band < 0) {
431                    throw new IllegalArgumentException("Band value < 0!");
432                }
433                for (int j = i + 1; j < numBands; j++) {
434                    if (band == sourceBands[j]) {
435                        throw new IllegalArgumentException("Duplicate band value!");
436                    }
437                }
438
439            }
440            this.sourceBands = (sourceBands.clone());
441        }
442    }
443
444    /**
445     * Returns the set of source bands to be used. The returned
446     * value is that set by the most recent call to
447     * {@code setSourceBands}, or {@code null} if there have
448     * been no calls to {@code setSourceBands}.
449     *
450     * <p> Semantically, the array returned is a copy; changes to
451     * array contents subsequent to this call have no effect on this
452     * {@code IIOParam}.
453     *
454     * @return the set of source bands to be used, or
455     * {@code null}.
456     *
457     * @see #setSourceBands
458     */
459    public int[] getSourceBands() {
460        if (sourceBands == null) {
461            return null;
462        }
463        return (sourceBands.clone());
464    }
465
466    /**
467     * Sets the desired image type for the destination image, using an
468     * {@code ImageTypeSpecifier}.
469     *
470     * <p> When reading, if the layout of the destination has been set
471     * using this method, each call to an {@code ImageReader}
472     * {@code read} method will return a new
473     * {@code BufferedImage} using the format specified by the
474     * supplied type specifier.  As a side effect, any destination
475     * {@code BufferedImage} set by
476     * {@code ImageReadParam.setDestination(BufferedImage)} will
477     * no longer be set as the destination.  In other words, this
478     * method may be thought of as calling
479     * {@code setDestination((BufferedImage)null)}.
480     *
481     * <p> When writing, the destination type maybe used to determine
482     * the color type of the image.  The {@code SampleModel}
483     * information will be ignored, and may be {@code null}.  For
484     * example, a 4-banded image could represent either CMYK or RGBA
485     * data.  If a destination type is set, its
486     * {@code ColorModel} will override any
487     * {@code ColorModel} on the image itself.  This is crucial
488     * when {@code setSourceBands} is used since the image's
489     * {@code ColorModel} will refer to the entire image rather
490     * than to the subset of bands being written.
491     *
492     * @param destinationType the {@code ImageTypeSpecifier} to
493     * be used to determine the destination layout and color type.
494     *
495     * @see #getDestinationType
496     */
497    public void setDestinationType(ImageTypeSpecifier destinationType) {
498        this.destinationType = destinationType;
499    }
500
501    /**
502     * Returns the type of image to be returned by the read, if one
503     * was set by a call to
504     * {@code setDestination(ImageTypeSpecifier)}, as an
505     * {@code ImageTypeSpecifier}.  If none was set,
506     * {@code null} is returned.
507     *
508     * @return an {@code ImageTypeSpecifier} describing the
509     * destination type, or {@code null}.
510     *
511     * @see #setDestinationType
512     */
513    public ImageTypeSpecifier getDestinationType() {
514        return destinationType;
515    }
516
517    /**
518     * Specifies the offset in the destination image at which future
519     * decoded pixels are to be placed, when reading, or where a
520     * region will be written, when writing.
521     *
522     * <p> When reading, the region to be written within the
523     * destination {@code BufferedImage} will start at this
524     * offset and have a width and height determined by the source
525     * region of interest, the subsampling parameters, and the
526     * destination bounds.
527     *
528     * <p> Normal writes are not affected by this method, only writes
529     * performed using {@code ImageWriter.replacePixels}.  For
530     * such writes, the offset specified is within the output stream
531     * image whose pixels are being modified.
532     *
533     * <p> There is no {@code unsetDestinationOffset} method;
534     * simply call {@code setDestinationOffset(new Point(0, 0))} to
535     * restore default values.
536     *
537     * @param destinationOffset the offset in the destination, as a
538     * {@code Point}.
539     *
540     * @exception IllegalArgumentException if
541     * {@code destinationOffset} is {@code null}.
542     *
543     * @see #getDestinationOffset
544     * @see ImageWriter#replacePixels
545     */
546    public void setDestinationOffset(Point destinationOffset) {
547        if (destinationOffset == null) {
548            throw new IllegalArgumentException("destinationOffset == null!");
549        }
550        this.destinationOffset = (Point)destinationOffset.clone();
551    }
552
553    /**
554     * Returns the offset in the destination image at which pixels are
555     * to be placed.
556     *
557     * <p> If {@code setDestinationOffsets} has not been called,
558     * a {@code Point} with zero X and Y values is returned
559     * (which is the correct value).
560     *
561     * @return the destination offset as a {@code Point}.
562     *
563     * @see #setDestinationOffset
564     */
565    public Point getDestinationOffset() {
566        return (Point)destinationOffset.clone();
567    }
568
569    /**
570     * Sets the {@code IIOParamController} to be used
571     * to provide settings for this {@code IIOParam}
572     * object when the {@code activateController} method
573     * is called, overriding any default controller.  If the
574     * argument is {@code null}, no controller will be
575     * used, including any default.  To restore the default, use
576     * {@code setController(getDefaultController())}.
577     *
578     * @param controller An appropriate
579     * {@code IIOParamController}, or {@code null}.
580     *
581     * @see IIOParamController
582     * @see #getController
583     * @see #getDefaultController
584     * @see #hasController
585     * @see #activateController()
586     */
587    public void setController(IIOParamController controller) {
588        this.controller = controller;
589    }
590
591    /**
592     * Returns whatever {@code IIOParamController} is currently
593     * installed.  This could be the default if there is one,
594     * {@code null}, or the argument of the most recent call
595     * to {@code setController}.
596     *
597     * @return the currently installed
598     * {@code IIOParamController}, or {@code null}.
599     *
600     * @see IIOParamController
601     * @see #setController
602     * @see #getDefaultController
603     * @see #hasController
604     * @see #activateController()
605     */
606    public IIOParamController getController() {
607        return controller;
608    }
609
610    /**
611     * Returns the default {@code IIOParamController}, if there
612     * is one, regardless of the currently installed controller.  If
613     * there is no default controller, returns {@code null}.
614     *
615     * @return the default {@code IIOParamController}, or
616     * {@code null}.
617     *
618     * @see IIOParamController
619     * @see #setController(IIOParamController)
620     * @see #getController
621     * @see #hasController
622     * @see #activateController()
623     */
624    public IIOParamController getDefaultController() {
625        return defaultController;
626    }
627
628    /**
629     * Returns {@code true} if there is a controller installed
630     * for this {@code IIOParam} object.  This will return
631     * {@code true} if {@code getController} would not
632     * return {@code null}.
633     *
634     * @return {@code true} if a controller is installed.
635     *
636     * @see IIOParamController
637     * @see #setController(IIOParamController)
638     * @see #getController
639     * @see #getDefaultController
640     * @see #activateController()
641     */
642    public boolean hasController() {
643        return (controller != null);
644    }
645
646    /**
647     * Activates the installed {@code IIOParamController} for
648     * this {@code IIOParam} object and returns the resulting
649     * value.  When this method returns {@code true}, all values
650     * for this {@code IIOParam} object will be ready for the
651     * next read or write operation.  If {@code false} is
652     * returned, no settings in this object will have been disturbed
653     * (<i>i.e.</i>, the user canceled the operation).
654     *
655     * <p> Ordinarily, the controller will be a GUI providing a user
656     * interface for a subclass of {@code IIOParam} for a
657     * particular plug-in.  Controllers need not be GUIs, however.
658     *
659     * @return {@code true} if the controller completed normally.
660     *
661     * @exception IllegalStateException if there is no controller
662     * currently installed.
663     *
664     * @see IIOParamController
665     * @see #setController(IIOParamController)
666     * @see #getController
667     * @see #getDefaultController
668     * @see #hasController
669     */
670    public boolean activateController() {
671        if (!hasController()) {
672            throw new IllegalStateException("hasController() == false!");
673        }
674        return getController().activate(this);
675    }
676}
677