KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > imageio > IIOParam


1 /*
2  * @(#)IIOParam.java 1.29 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.imageio;
9
10 import java.awt.Point JavaDoc;
11 import java.awt.Rectangle JavaDoc;
12
13 /**
14  * A superclass of all classes describing how streams should be
15  * decoded or encoded. This class contains all the variables and
16  * methods that are shared by <code>ImageReadParam</code> and
17  * <code>ImageWriteParam</code>.
18  *
19  * <p> This class provides mechanisms to specify a source region and a
20  * destination region. When reading, the source is the stream and
21  * the in-memory image is the destination. When writing, these are
22  * reversed. In the case of writing, destination regions may be used
23  * only with a writer that supports pixel replacement.
24  * <p>
25  * Decimation subsampling may be specified for both readers
26  * and writers, using a movable subsampling grid.
27  * <p>
28  * Subsets of the source and destination bands may be selected.
29  *
30  * @version 0.5
31  */

32 public abstract class IIOParam {
33
34     /**
35      * The source region, on <code>null</code> if none is set.
36      */

37     protected Rectangle JavaDoc sourceRegion = null;
38
39     /**
40      * The decimation subsampling to be applied in the horizontal
41      * direction. By default, the value is <code>1</code>.
42      * The value must not be negative or 0.
43      */

44     protected int sourceXSubsampling = 1;
45
46     /**
47      * The decimation subsampling to be applied in the vertical
48      * direction. By default, the value is <code>1</code>.
49      * The value must not be negative or 0.
50      */

51     protected int sourceYSubsampling = 1;
52
53     /**
54      * A horizontal offset to be applied to the subsampling grid before
55      * subsampling. The first pixel to be used will be offset this
56      * amount from the origin of the region, or of the image if no
57      * region is specified.
58      */

59     protected int subsamplingXOffset = 0;
60
61     /**
62      * A vertical offset to be applied to the subsampling grid before
63      * subsampling. The first pixel to be used will be offset this
64      * amount from the origin of the region, or of the image if no
65      * region is specified.
66      */

67     protected int subsamplingYOffset = 0;
68     
69     /**
70      * An array of <code>int</code>s indicating which source bands
71      * will be used, or <code>null</code>. If <code>null</code>, the
72      * set of source bands to be used is as described in the comment
73      * for the <code>setSourceBands</code> method. No value should
74      * be allowed to be negative.
75      */

76     protected int[] sourceBands = null;
77
78     /**
79      * An <code>ImageTypeSpecifier</code> to be used to generate a
80      * destination image when reading, or to set the output color type
81      * when writing. If non has been setm the value will be
82      * <code>null</code>. By default, the value is <code>null</code>.
83      */

84     protected ImageTypeSpecifier JavaDoc destinationType = null;
85
86     /**
87      * The offset in the destination where the upper-left decoded
88      * pixel should be placed. By default, the value is (0, 0).
89      */

90     protected Point JavaDoc destinationOffset = new Point JavaDoc(0, 0);
91
92     /**
93      * The default <code>IIOParamController</code> that will be
94      * used to provide settings for this <code>IIOParam</code>
95      * object when the <code>activateController</code> method
96      * is called. This default should be set by subclasses
97      * that choose to provide their own default controller,
98      * usually a GUI, for setting parameters.
99      *
100      * @see IIOParamController
101      * @see #getDefaultController
102      * @see #activateController
103      */

104     protected IIOParamController JavaDoc defaultController = null;
105
106     /**
107      * The <code>IIOParamController</code> that will be
108      * used to provide settings for this <code>IIOParam</code>
109      * object when the <code>activateController</code> method
110      * is called. This value overrides any default controller,
111      * even when null.
112      *
113      * @see IIOParamController
114      * @see #setController(IIOParamController)
115      * @see #hasController()
116      * @see #activateController()
117      */

118     protected IIOParamController JavaDoc controller = null;
119
120     /**
121      * Protected constructor may be called only by subclasses.
122      */

123     protected IIOParam() {
124         controller = defaultController;
125     }
126
127     /**
128      * Sets the source region of interest. The region of interest is
129      * described as a rectangle, with the upper-left corner of the
130      * source image as pixel (0, 0) and increasing values down and to
131      * the right. The actual number of pixels used will depend on
132      * the subsampling factors set by <code>setSourceSubsampling</code>.
133      * If subsampling has been set such that this number is zero,
134      * an <code>IllegalStateException</code> will be thrown.
135      *
136      * <p> The source region of interest specified by this method will
137      * be clipped as needed to fit within the source bounds, as well
138      * as the destination offsets, width, and height at the time of
139      * actual I/O.
140      *
141      * <p> A value of <code>null</code> for <code>sourceRegion</code>
142      * will remove any region specification, causing the entire image
143      * to be used.
144      *
145      * @param sourceRegion a <code>Rectangle</code> specifying the
146      * source region of interest, or <code>null</code>.
147      *
148      * @exception IllegalArgumentException if
149      * <code>sourceRegion</code> is non-<code>null</code> and either
150      * <code>sourceRegion.x</code> or <code>sourceRegion.y</code> is
151      * negative.
152      * @exception IllegalArgumentException if
153      * <code>sourceRegion</code> is non-<code>null</code> and either
154      * <code>sourceRegion.width</code> or
155      * <code>sourceRegion.height</code> is negative or 0.
156      * @exception IllegalStateException if subsampling is such that
157      * this region will have a subsampled width or height of zero.
158      *
159      * @see #getSourceRegion
160      * @see #setSourceSubsampling
161      * @see ImageReadParam#setDestinationOffset
162      * @see ImageReadParam#getDestinationOffset
163      */

164     public void setSourceRegion(Rectangle JavaDoc sourceRegion) {
165         if (sourceRegion == null) {
166             this.sourceRegion = null;
167             return;
168         }
169
170         if (sourceRegion.x < 0) {
171             throw new IllegalArgumentException JavaDoc("sourceRegion.x < 0!");
172         }
173         if (sourceRegion.y < 0){
174             throw new IllegalArgumentException JavaDoc("sourceRegion.y < 0!");
175         }
176         if (sourceRegion.width <= 0) {
177             throw new IllegalArgumentException JavaDoc("sourceRegion.width <= 0!");
178         }
179         if (sourceRegion.height <= 0) {
180             throw new IllegalArgumentException JavaDoc("sourceRegion.height <= 0!");
181         }
182
183         // Throw an IllegalStateException if region falls between subsamples
184
if (sourceRegion.width <= subsamplingXOffset) {
185             throw new IllegalStateException JavaDoc
186                 ("sourceRegion.width <= subsamplingXOffset!");
187         }
188         if (sourceRegion.height <= subsamplingYOffset) {
189             throw new IllegalStateException JavaDoc
190                 ("sourceRegion.height <= subsamplingYOffset!");
191         }
192
193         this.sourceRegion = (Rectangle JavaDoc)sourceRegion.clone();
194     }
195
196     /**
197      * Returns the source region to be used. The returned value is
198      * that set by the most recent call to
199      * <code>setSourceRegion</code>, and will be <code>null</code> if
200      * there is no region set.
201      *
202      * @return the source region of interest as a
203      * <code>Rectangle</code>, or <code>null</code>.
204      *
205      * @see #setSourceRegion
206      */

207     public Rectangle JavaDoc getSourceRegion() {
208         if (sourceRegion == null) {
209             return null;
210         }
211         return (Rectangle JavaDoc)sourceRegion.clone();
212     }
213
214     /**
215      * Specifies a decimation subsampling to apply on I/O. The
216      * <code>sourceXSubsampling</code> and
217      * <code>sourceYSubsampling</code> parameters specify the
218      * subsampling period (<i>i.e.</i>, the number of rows and columns
219      * to advance after every source pixel). Specifically, a period of
220      * 1 will use every row or column; a period of 2 will use every
221      * other row or column. The <code>subsamplingXOffset</code> and
222      * <code>subsamplingYOffset</code> parameters specify an offset
223      * from the region (or image) origin for the first subsampled pixel.
224      * Adjusting the origin of the subsample grid is useful for avoiding
225      * seams when subsampling a very large source image into destination
226      * regions that will be assembled into a complete subsampled image.
227      * Most users will want to simply leave these parameters at 0.
228      *
229      * <p> The number of pixels and scanlines to be used are calculated
230      * as follows.
231      * <p>
232      * The number of subsampled pixels in a scanline is given by
233      * <p>
234      * <code>truncate[(width - subsamplingXOffset + sourceXSubsampling - 1)
235      * / sourceXSubsampling]</code>.
236      * <p>
237      * If the region is such that this width is zero, an
238      * <code>IllegalStateException</code> is thrown.
239      * <p>
240      * The number of scanlines to be used can be computed similarly.
241      *
242      * <p>The ability to set the subsampling grid to start somewhere
243      * other than the source region origin is useful if the
244      * region is being used to create subsampled tiles of a large image,
245      * where the tile width and height are not multiples of the
246      * subsampling periods. If the subsampling grid does not remain
247      * consistent from tile to tile, there will be artifacts at the tile
248      * boundaries. By adjusting the subsampling grid offset for each
249      * tile to compensate, these artifacts can be avoided. The tradeoff
250      * is that in order to avoid these artifacts, the tiles are not all
251      * the same size. The grid offset to use in this case is given by:
252      * <br>
253      * grid offset = [period - (region offset modulo period)] modulo period)
254      *
255      * <p> If either <code>sourceXSubsampling</code> or
256      * <code>sourceYSubsampling</code> is 0 or negative, an
257      * <code>IllegalArgumentException</code> will be thrown.
258      *
259      * <p> If either <code>subsamplingXOffset</code> or
260      * <code>subsamplingYOffset</code> is negative or greater than or
261      * equal to the corresponding period, an
262      * <code>IllegalArgumentException</code> will be thrown.
263      *
264      * <p> There is no <code>unsetSourceSubsampling</code> method;
265      * simply call <code>setSourceSubsampling(1, 1, 0, 0)</code> to
266      * restore default values.
267      *
268      * @param sourceXSubsampling the number of columns to advance
269      * between pixels.
270      * @param sourceYSubsampling the number of rows to advance between
271      * pixels.
272      * @param subsamplingXOffset the horizontal offset of the first subsample
273      * within the region, or within the image if no region is set.
274      * @param subsamplingYOffset the horizontal offset of the first subsample
275      * within the region, or within the image if no region is set.
276      * @exception IllegalArgumentException if either period is
277      * negative or 0, or if either grid offset is negative or greater than
278      * the corresponding period.
279      * @exception IllegalStateException if the source region is such that
280      * the subsampled output would contain no pixels.
281      */

282     public void setSourceSubsampling(int sourceXSubsampling,
283                                      int sourceYSubsampling,
284                                      int subsamplingXOffset,
285                                      int subsamplingYOffset) {
286         if (sourceXSubsampling <= 0) {
287             throw new IllegalArgumentException JavaDoc("sourceXSubsampling <= 0!");
288         }
289         if (sourceYSubsampling <= 0) {
290             throw new IllegalArgumentException JavaDoc("sourceYSubsampling <= 0!");
291         }
292         if (subsamplingXOffset < 0 ||
293             subsamplingXOffset >= sourceXSubsampling) {
294             throw new IllegalArgumentException JavaDoc
295                 ("subsamplingXOffset out of range!");
296         }
297         if (subsamplingYOffset < 0 ||
298             subsamplingYOffset >= sourceYSubsampling) {
299             throw new IllegalArgumentException JavaDoc
300                 ("subsamplingYOffset out of range!");
301         }
302         
303         // Throw an IllegalStateException if region falls between subsamples
304
if (sourceRegion != null) {
305             if (subsamplingXOffset >= sourceRegion.width ||
306                 subsamplingYOffset >= sourceRegion.height) {
307                 throw new IllegalStateException JavaDoc("region contains no pixels!");
308             }
309         }
310
311         this.sourceXSubsampling = sourceXSubsampling;
312         this.sourceYSubsampling = sourceYSubsampling;
313         this.subsamplingXOffset = subsamplingXOffset;
314         this.subsamplingYOffset = subsamplingYOffset;
315     }
316
317     /**
318      * Returns the number of source columns to advance for each pixel.
319      *
320      * <p>If <code>setSourceSubsampling</code> has not been called, 1
321      * is returned (which is the correct value).
322      *
323      * @return the source subsampling X period.
324      *
325      * @see #setSourceSubsampling
326      * @see #getSourceYSubsampling
327      */

328     public int getSourceXSubsampling() {
329         return sourceXSubsampling;
330     }
331
332     /**
333      * Returns the number of rows to advance for each pixel.
334      *
335      * <p>If <code>setSourceSubsampling</code> has not been called, 1
336      * is returned (which is the correct value).
337      *
338      * @return the source subsampling Y period.
339      *
340      * @see #setSourceSubsampling
341      * @see #getSourceXSubsampling
342      */

343     public int getSourceYSubsampling() {
344         return sourceYSubsampling;
345     }
346
347     /**
348      * Returns the horizontal offset of the subsampling grid.
349      *
350      * <p>If <code>setSourceSubsampling</code> has not been called, 0
351      * is returned (which is the correct value).
352      *
353      * @return the source subsampling grid X offset.
354      *
355      * @see #setSourceSubsampling
356      * @see #getSubsamplingYOffset
357      */

358     public int getSubsamplingXOffset() {
359         return subsamplingXOffset;
360     }
361
362     /**
363      * Returns the vertical offset of the subsampling grid.
364      *
365      * <p>If <code>setSourceSubsampling</code> has not been called, 0
366      * is returned (which is the correct value).
367      *
368      * @return the source subsampling grid Y offset.
369      *
370      * @see #setSourceSubsampling
371      * @see #getSubsamplingXOffset
372      */

373     public int getSubsamplingYOffset() {
374         return subsamplingYOffset;
375     }
376
377     /**
378      * Sets the indices of the source bands to be used. Duplicate
379      * indices are not allowed.
380      *
381      * <p> A <code>null</code> value indicates that all source bands
382      * will be used.
383      *
384      * <p> At the time of reading, an
385      * <code>IllegalArgumentException</code> will be thrown by the
386      * reader or writer if a value larger than the largest available
387      * source band index has been specified or if the number of source
388      * bands and destination bands to be used differ. The
389      * <code>ImageReader.checkReadParamBandSettings</code> method may
390      * be used to automate this test.
391      *
392      * <p> Semantically, a copy is made of the array; changes to the
393      * array contents subsequent to this call have no effect on
394      * this <code>IIOParam</code>.
395      *
396      * @param sourceBands an array of integer band indices to be
397      * used.
398      *
399      * @exception IllegalArgumentException if <code>sourceBands</code>
400      * contains a negative or duplicate value.
401      *
402      * @see #getSourceBands
403      * @see ImageReadParam#setDestinationBands
404      * @see ImageReader#checkReadParamBandSettings
405      */

406     public void setSourceBands(int[] sourceBands) {
407         if (sourceBands == null) {
408             this.sourceBands = null;
409         } else {
410             int numBands = sourceBands.length;
411             for (int i = 0; i < numBands; i++) {
412                 int band = sourceBands[i];
413                 if (band < 0) {
414                     throw new IllegalArgumentException JavaDoc("Band value < 0!");
415                 }
416                 for (int j = i + 1; j < numBands; j++) {
417                     if (band == sourceBands[j]) {
418                         throw new IllegalArgumentException JavaDoc("Duplicate band value!");
419                     }
420                 }
421                 
422             }
423             this.sourceBands = (int[])(sourceBands.clone());
424         }
425     }
426
427     /**
428      * Returns the set of of source bands to be used. The returned
429      * value is that set by the most recent call to
430      * <code>setSourceBands</code>, or <code>null</code> if there have
431      * been no calls to <code>setSourceBands</code>.
432      *
433      * <p> Semantically, the array returned is a copy; changes to
434      * array contents subsequent to this call have no effect on this
435      * <code>IIOParam</code>.
436      *
437      * @return the set of source bands to be used, or
438      * <code>null</code>.
439      *
440      * @see #setSourceBands
441      */

442     public int[] getSourceBands() {
443         if (sourceBands == null) {
444             return null;
445         }
446         return (int[])(sourceBands.clone());
447     }
448
449     /**
450      * Sets the desired image type for the destination image, using an
451      * <code>ImageTypeSpecifier</code>.
452      *
453      * <p> When reading, if the layout of the destination has been set
454      * using this method, each call to an <code>ImageReader</code>
455      * <code>read</code> method will return a new
456      * <code>BufferedImage</code> using the format specified by the
457      * supplied type specifier. As a side effect, any destination
458      * <code>BufferedImage</code> set by
459      * <code>ImageReadParam.setDestination(BufferedImage)</code> will
460      * no longer be set as the destination. In other words, this
461      * method may be thought of as calling
462      * <code>setDestination((BufferedImage)null)</code>.
463      *
464      * <p> When writing, the destination type maybe used to determine
465      * the color type of the image. The <code>SampleModel</code>
466      * information will be ignored, and may be <code>null</code>. For
467      * example, a 4-banded image could represent either CMYK or RGBA
468      * data. If a destination type is set, its
469      * <code>ColorModel</code> will override any
470      * <code>ColorModel</code> on the image itself. This is crucial
471      * when <code>setSourceBands</code> is used since the image's
472      * <code>ColorModel</code> will refer to the entire image rather
473      * than to the subset of bands being written.
474      *
475      * @param destinationType the <code>ImageTypeSpecifier</code> to
476      * be used to determine the destination layout and color type.
477      *
478      * @see #getDestinationType
479      */

480     public void setDestinationType(ImageTypeSpecifier JavaDoc destinationType) {
481         this.destinationType = destinationType;
482     }
483
484     /**
485      * Returns the type of image to be returned by the read, if one
486      * was set by a call to
487      * <code>setDestination(ImageTypeSpecifier)</code>, as an
488      * <code>ImageTypeSpecifier</code>. If none was set,
489      * <code>null</code> is returned.
490      *
491      * @return an <code>ImageTypeSpecifier</code> describing the
492      * destination type, or <code>null</code>.
493      *
494      * @see #setDestinationType
495      */

496     public ImageTypeSpecifier JavaDoc getDestinationType() {
497         return destinationType;
498     }
499
500     /**
501      * Specifies the offset in the destination image at which future
502      * decoded pixels are to be placed, when reading, or where a
503      * region will be written, when writing.
504      *
505      * <p> When reading, the region to be written within the
506      * destination <code>BufferedImage</code> will start at this
507      * offset and have a width and height determined by the source
508      * region of interest, the subsampling parameters, and the
509      * destination bounds.
510      *
511      * <p> Normal writes are not affected by this method, only writes
512      * performed using <code>ImageWriter.replacePixels</code>. For
513      * such writes, the offset specified is within the output stream
514      * image whose pixels are being modified.
515      *
516      * <p> There is no <code>unsetDestinationOffset</code> method;
517      * simply call <code>setDestinationOffset(new Point(0, 0))</code> to
518      * restore default values.
519      *
520      * @param destinationOffset the offset in the destination, as a
521      * <code>Point</code>.
522      *
523      * @exception IllegalArgumentException if
524      * <code>destinationOffset</code> is <code>null</code>.
525      *
526      * @see #getDestinationOffset
527      * @see ImageWriter#replacePixels
528      */

529     public void setDestinationOffset(Point JavaDoc destinationOffset) {
530         if (destinationOffset == null) {
531             throw new IllegalArgumentException JavaDoc("destinationOffset == null!");
532         }
533         this.destinationOffset = (Point JavaDoc)destinationOffset.clone();
534     }
535
536     /**
537      * Returns the offset in the destination image at which pixels are
538      * to be placed.
539      *
540      * <p> If <code>setDestinationOffsets</code> has not been called,
541      * a <code>Point</code> with zero X and Y values is returned
542      * (which is the correct value).
543      *
544      * @return the destination offset as a <code>Point</code>.
545      *
546      * @see #setDestinationOffset
547      */

548     public Point JavaDoc getDestinationOffset() {
549         return (Point JavaDoc)destinationOffset.clone();
550     }
551
552     /**
553      * Sets the <code>IIOParamController</code> to be used
554      * to provide settings for this <code>IIOParam</code>
555      * object when the <code>activateController</code> method
556      * is called, overriding any default controller. If the
557      * argument is <code>null</code>, no controller will be
558      * used, including any default. To restore the default, use
559      * <code>setController(getDefaultController())</code>.
560      *
561      * @param controller An appropriate
562      * <code>IIOParamController</code>, or <code>null</code>.
563      *
564      * @see IIOParamController
565      * @see #getController
566      * @see #getDefaultController
567      * @see #hasController
568      * @see #activateController()
569      */

570     public void setController(IIOParamController JavaDoc controller) {
571         this.controller = controller;
572     }
573
574     /**
575      * Returns whatever <code>IIOParamController</code> is currently
576      * installed. This could be the default if there is one,
577      * <code>null</code>, or the argument of the most recent call
578      * to <code>setController</code>.
579      *
580      * @return the currently installed
581      * <code>IIOParamController</code>, or <code>null</code>.
582      *
583      * @see IIOParamController
584      * @see #setController
585      * @see #getDefaultController
586      * @see #hasController
587      * @see #activateController()
588      */

589     public IIOParamController JavaDoc getController() {
590         return controller;
591     }
592
593     /**
594      * Returns the default <code>IIOParamController</code>, if there
595      * is one, regardless of the currently installed controller. If
596      * there is no default controller, returns <code>null</code>.
597      *
598      * @return the default <code>IIOParamController</code>, or
599      * <code>null</code>.
600      *
601      * @see IIOParamController
602      * @see #setController(IIOParamController)
603      * @see #getController
604      * @see #hasController
605      * @see #activateController()
606      */

607     public IIOParamController JavaDoc getDefaultController() {
608         return defaultController;
609     }
610
611     /**
612      * Returns <code>true</code> if there is a controller installed
613      * for this <code>IIOParam</code> object. This will return
614      * <code>true</code> if <code>getController</code> would not
615      * return <code>null</code>.
616      *
617      * @return <code>true</code> if a controller is installed.
618      *
619      * @see IIOParamController
620      * @see #setController(IIOParamController)
621      * @see #getController
622      * @see #getDefaultController
623      * @see #activateController()
624      */

625     public boolean hasController() {
626         return (controller != null);
627     }
628
629     /**
630      * Activates the installed <code>IIOParamController</code> for
631      * this <code>IIOParam</code> object and returns the resulting
632      * value. When this method returns <code>true</code>, all values
633      * for this <code>IIOParam</code> object will be ready for the
634      * next read or write operation. If <code>false</code> is
635      * returned, no settings in this object will have been disturbed
636      * (<i>i.e.</i>, the user canceled the operation).
637      *
638      * <p> Ordinarily, the controller will be a GUI providing a user
639      * interface for a subclass of <code>IIOParam</code> for a
640      * particular plug-in. Controllers need not be GUIs, however.
641      *
642      * @return <code>true</code> if the controller completed normally.
643      *
644      * @exception IllegalStateException if there is no controller
645      * currently installed.
646      *
647      * @see IIOParamController
648      * @see #setController(IIOParamController)
649      * @see #getController
650      * @see #getDefaultController
651      * @see #hasController
652      */

653     public boolean activateController() {
654         if (!hasController()) {
655             throw new IllegalStateException JavaDoc("hasController() == false!");
656         }
657         return getController().activate(this);
658     }
659 }
660
Popular Tags