1 /*
2  * $RCSfile: ImageLayout.java,v $
3  *
4  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
5  *
6  * Use is subject to license terms.
7  *
8  * $Revision: 1.1 $
9  * $Date: 2005/02/11 04:57:09 $
10  * $State: Exp $
11  */
12 package com.lightcrafts.mediax.jai;
13 import java.awt.image.ColorModel;
14 import java.awt.image.RenderedImage;
15 import java.awt.image.SampleModel;
16 import java.io.IOException;
17 import java.io.ObjectInputStream;
18 import java.io.ObjectOutputStream;
19 import java.io.Serializable;
20 import com.lightcrafts.mediax.jai.remote.SerializableState;
21 import com.lightcrafts.mediax.jai.remote.SerializerFactory;
22 
23 /**
24  * A class describing the desired layout of an <code>OpImage</code>.
25  *
26  * <p> The <code>ImageLayout</code> class encapsulates three types of information about
27  * an image:
28  *
29  * <ul>
30  * <li> The image bounds, comprising the min X and Y coordinates,
31  *      image width, and image height;
32  * <li> The tile grid layout, comprising the tile grid X and Y offsets,
33  *      the tile width, and the tile height; and
34  * <li> The <code>SampleModel</code> and <code>ColorModel</code> of the image.
35  * </ul>
36  *
37  * <p> Each of these parameters may be set individually, or left unset.
38  * An unset parameter will cause the corresponding value of a given
39  * <code>RenderedImage</code> to be used.  For example, the code:
40  *
41  * <pre>
42  * ImageLayout layout;
43  * RenderedImage im;
44  *
45  * int width = layout.getTileWidth(im);
46  * </pre>
47  *
48  * will return the tile width of the <code>ImageLayout</code> if it is set,
49  * or the tile width of the image <code>im</code> if it is not.
50  *
51  * <p> <code>ImageLayout</code> objects are primarily intended to be passed as part
52  * of the <code>renderingHints</code> argument of the <code>create()</code> method of
53  * <code>RenderedImageFactory</code>.  The <code>create()</code> method may remove parameter
54  * settings that it cannot deal with, prior to passing the
55  * <code>ImageLayout</code> to any <code>OpImage</code> constructors.  New <code>OpImage</code> subclasses
56  * are not required to accept an <code>ImageLayout</code> parameter, but most will
57  * at least need to synthesize one to be passed up the constructor
58  * chain.
59  *
60  * <p> Methods that modify the state of an <code>ImageLayout</code> return a reference
61  * to 'this' following the change.  This allows multiple modifications to
62  * be made in a single expression.  This provides a way of modifying an
63  * <code>ImageLayout</code> within a superclass constructor call.
64  *
65  */
66 public class ImageLayout extends Object implements Cloneable, Serializable {
67     /** A bitmask to specify the validity of <code>minX</code>. */
68     public static final int MIN_X_MASK = 0x1;
69     /** A bitmask to specify the validity of <code>minY</code>. */
70     public static final int MIN_Y_MASK = 0x2;
71     /** A bitmask to specify the validity of <code>width</code>. */
72     public static final int WIDTH_MASK = 0x4;
73     /** A bitmask to specify the validity of <code>height</code>. */
74     public static final int HEIGHT_MASK = 0x8;
75 
76     /** A bitmask to specify the validity of <code>tileGridXOffset</code>. */
77     public static final int TILE_GRID_X_OFFSET_MASK = 0x10;
78     /** A bitmask to specify the validity of <code>tileGridYOffset</code>. */
79     public static final int TILE_GRID_Y_OFFSET_MASK = 0x20;
80     /** A bitmask to specify the validity of <code>tileWidth</code>. */
81     public static final int TILE_WIDTH_MASK = 0x40;
82     /** A bitmask to specify the validity of <code>tileHeight</code>. */
83     public static final int TILE_HEIGHT_MASK = 0x80;
84 
85     /** A bitmask to specify the validity of <code>sampleModel</code>. */
86     public static final int SAMPLE_MODEL_MASK = 0x100;
87 
88     /** A bitmask to specify the validity of <code>colorModel</code>. */
89     public static final int COLOR_MODEL_MASK = 0x200;
90 
91     /** The image's minimum X coordinate. */
92     int minX = 0;
93 
94     /** The image's minimum Y coordinate. */
95     int minY = 0;
96 
97     /** The image's <code>width</code>. */
98     int width = 0;
99 
100     /** The image's height. */
101     int height = 0;
102 
103     /** The X coordinate of tile (0, 0). */
104     int tileGridXOffset = 0;
105 
106     /** The Y coordinate of tile (0, 0). */
107     int tileGridYOffset = 0;
108 
109     /** The width of a tile. */
110     int tileWidth = 0;
111 
112     /** The height of a tile. */
113     int tileHeight = 0;
114 
115     /** The image's <code>SampleModel</code>. */
116     transient SampleModel sampleModel = null;
117 
118     /** The image's <code>ColorModel</code>. */
119     transient ColorModel colorModel = null;
120 
121     /** The 'or'-ed together valid bitmasks. */
122     protected int validMask = 0;
123 
124     /** Constructs an <code>ImageLayout</code> with no parameters set. */
ImageLayout()125     public ImageLayout() {}
126 
127     /**
128      * Constructs an <code>ImageLayout</code> with all its parameters set.
129      * The <code>sampleModel</code> and <code>colorModel</code> parameters are ignored if null.
130      *
131      * @param minX the image's minimum X coordinate.
132      * @param minY the image's minimum Y coordinate.
133      * @param width the image's width.
134      * @param height the image's height.
135      * @param tileGridXOffset the X coordinate of tile (0, 0).
136      * @param tileGridYOffset the Y coordinate of tile (0, 0).
137      * @param tileWidth the width of a tile.
138      * @param tileHeight the height of a tile.
139      * @param sampleModel the image's <code>SampleModel</code>.
140      * @param colorModel the image's <code>ColorModel</code>.
141      */
ImageLayout(int minX, int minY, int width, int height, int tileGridXOffset, int tileGridYOffset, int tileWidth, int tileHeight, SampleModel sampleModel, ColorModel colorModel)142     public ImageLayout(int minX,
143                        int minY,
144                        int width,
145                        int height,
146                        int tileGridXOffset,
147                        int tileGridYOffset,
148                        int tileWidth,
149                        int tileHeight,
150                        SampleModel sampleModel,
151                        ColorModel colorModel) {
152         setMinX(minX);
153         setMinY(minY);
154         setWidth(width);
155         setHeight(height);
156         setTileGridXOffset(tileGridXOffset);
157         setTileGridYOffset(tileGridYOffset);
158         setTileWidth(tileWidth);
159         setTileHeight(tileHeight);
160         if (sampleModel != null) {
161             setSampleModel(sampleModel);
162         }
163         if (colorModel != null) {
164             setColorModel(colorModel);
165         }
166     }
167 
168 
169     /**
170      * Constructs an <code>ImageLayout</code> with only the image dimension
171      * parameters set.
172      *
173      * @param minX the image's minimum X coordinate.
174      * @param minY the image's minimum Y coordinate.
175      * @param width the image's width.
176      * @param height the image's height.
177      */
ImageLayout(int minX, int minY, int width, int height)178     public ImageLayout(int minX,
179                        int minY,
180                        int width,
181                        int height) {
182         setMinX(minX);
183         setMinY(minY);
184         setWidth(width);
185         setHeight(height);
186     }
187 
188     /**
189      * Constructs an <code>ImageLayout</code> with its tile grid layout,
190      * <code>SampleModel</code>, and <code>ColorModel</code> parameters set.
191      * The <code>sampleModel</code> and <code>colorModel</code> parameters are ignored if null.
192      *
193      * @param tileGridXOffset the X coordinate of tile (0, 0).
194      * @param tileGridYOffset the Y coordinate of tile (0, 0).
195      * @param tileWidth the width of a tile.
196      * @param tileHeight the height of a tile.
197      * @param sampleModel the image's <code>SampleModel</code>.
198      * @param colorModel the image's <code>ColorModel</code>.
199      */
ImageLayout(int tileGridXOffset, int tileGridYOffset, int tileWidth, int tileHeight, SampleModel sampleModel, ColorModel colorModel)200     public ImageLayout(int tileGridXOffset,
201                        int tileGridYOffset,
202                        int tileWidth,
203                        int tileHeight,
204                        SampleModel sampleModel,
205                        ColorModel colorModel) {
206         setTileGridXOffset(tileGridXOffset);
207         setTileGridYOffset(tileGridYOffset);
208         setTileWidth(tileWidth);
209         setTileHeight(tileHeight);
210         if (sampleModel != null) {
211             setSampleModel(sampleModel);
212         }
213         if (colorModel != null) {
214             setColorModel(colorModel);
215         }
216     }
217 
218     /**
219      * Constructs an <code>ImageLayout</code> with all its parameters set
220      * to equal those of a given <code>RenderedImage</code>.
221      *
222      * @param im a <code>RenderedImage</code> whose layout will be copied.
223      */
ImageLayout(RenderedImage im)224     public ImageLayout(RenderedImage im) {
225         this(im.getMinX(),
226              im.getMinY(),
227              im.getWidth(),
228              im.getHeight(),
229              im.getTileGridXOffset(),
230              im.getTileGridYOffset(),
231              im.getTileWidth(),
232              im.getTileHeight(),
233              im.getSampleModel(),
234              im.getColorModel());
235     }
236 
237     /**
238      * Returns the 'or'-ed together bitmask indicating parameter validity.
239      * To determine the validity of a particular parameter, say tile width,
240      * test <code>getValidMask() & ImageLayout.TILE_WIDTH_MASK</code>
241      * against <code>0</code>.
242      *
243      * <p> To test a single mask value or set of mask values, the
244      * convenience method isValid() may be used.
245      *
246      * @return an int that is the logical 'or' of the valid mask values,
247      *         with a '1' bit representing the setting of a value.
248      */
getValidMask()249     public int getValidMask() {
250         return validMask;
251     }
252 
253     /**
254      * Returns <code>true</code> if all the parameters specified by the argument are set.
255      *
256      * @param mask a bitmask.
257      * @return a boolean truth value.
258      */
isValid(int mask)259     public final boolean isValid(int mask) {
260         return (validMask & mask) == mask;
261     }
262 
263     /**
264      * Sets selected bits of the valid bitmask.  The valid bitmask is
265      * set to the logical 'or' of its prior value and a new value.
266      *
267      * @param mask the new mask value to be 'or'-ed with the prior value.
268      * @return a reference to this <code>ImageLayout</code> following the change.
269      */
setValid(int mask)270     public ImageLayout setValid(int mask) {
271         validMask |= mask;
272         return this;
273     }
274 
275     /**
276      * Clears selected bits of the valid bitmask.  The valid bitmask
277      * is set to the logical 'and' of its prior value and the negation
278      * of the new mask value.  This effectively subtracts from the set of
279      * valid parameters.
280      *
281      * @param mask the new mask value to be negated and 'and'-ed with
282      *        the prior value.
283      * @return a reference to this <code>ImageLayout</code> following the change.
284      */
unsetValid(int mask)285     public ImageLayout unsetValid(int mask) {
286         validMask &= ~mask;
287         return this;
288     }
289 
290     /**
291      * Marks the parameters dealing with the image bounds
292      * (minX, minY, width, and height) as being invalid.
293      *
294      * @return a reference to this <code>ImageLayout</code> following the change.
295      */
unsetImageBounds()296     public ImageLayout unsetImageBounds() {
297         unsetValid(MIN_X_MASK |
298                    MIN_Y_MASK |
299                    WIDTH_MASK |
300                    HEIGHT_MASK);
301         return this;
302     }
303 
304     /**
305      * Marks the parameters dealing with the tile layout (tileGridXOffset,
306      * tileGridYOffset, tileWidth, and tileHeight) as being invalid.
307      *
308      * @return a reference to this <code>ImageLayout</code> following the change.
309      */
unsetTileLayout()310     public ImageLayout unsetTileLayout() {
311         unsetValid(TILE_GRID_X_OFFSET_MASK |
312                    TILE_GRID_Y_OFFSET_MASK |
313                    TILE_WIDTH_MASK |
314                    TILE_HEIGHT_MASK);
315         return this;
316     }
317 
318     /**
319      * Returns the value of <code>minX</code> if it is valid, and
320      * otherwise returns the value from the supplied <code>RenderedImage</code>.
321      * If <code>minX</code> is not valid and fallback is null, 0 is returned.
322      *
323      * @param fallback the <code>RenderedImage</code> fallback.
324      * @return the appropriate value of minX.
325      */
getMinX(RenderedImage fallback)326     public int getMinX(RenderedImage fallback) {
327         if (isValid(MIN_X_MASK)) {
328             return minX;
329         } else {
330             if (fallback == null) {
331                 return 0;
332             } else {
333                 return fallback.getMinX();
334             }
335         }
336     }
337 
338     /**
339      * Sets <code>minX</code> to the supplied value and marks it as valid.
340      *
341      * @param minX the minimum X coordinate of the image, as an int.
342      * @return a reference to this <code>ImageLayout</code> following the change.
343      */
setMinX(int minX)344     public ImageLayout setMinX(int minX) {
345         this.minX = minX;
346         setValid(MIN_X_MASK);
347         return this;
348     }
349 
350     /**
351      * Returns the value of <code>minY</code> if it is valid, and
352      * otherwise returns the value from the supplied <code>RenderedImage</code>.
353      * If <code>minY</code> is not valid and fallback is null, 0 is returned.
354      *
355      * @param fallback the <code>RenderedImage</code> fallback.
356      * @return the appropriate value of minY.
357      */
getMinY(RenderedImage fallback)358     public int getMinY(RenderedImage fallback) {
359         if (isValid(MIN_Y_MASK)) {
360             return minY;
361         } else {
362             if (fallback == null) {
363                 return 0;
364             } else {
365                 return fallback.getMinY();
366             }
367         }
368     }
369 
370     /**
371      * Sets <code>minY</code> to the supplied value and marks it as valid.
372      *
373      * @param minY the minimum Y coordinate of the image, as an int.
374      * @return a reference to this <code>ImageLayout</code> following the change.
375      */
setMinY(int minY)376     public ImageLayout setMinY(int minY) {
377         this.minY = minY;
378         setValid(MIN_Y_MASK);
379         return this;
380     }
381 
382     /**
383      * Returns the value of <code>width</code> if it is valid, and
384      * otherwise returns the value from the supplied <code>RenderedImage</code>.
385      * If <code>width</code> is not valid and fallback is null, 0 is returned.
386      *
387      * @param fallback the <code>RenderedImage</code> fallback.
388      * @return the appropriate value of width.
389      */
getWidth(RenderedImage fallback)390     public int getWidth(RenderedImage fallback) {
391         if (isValid(WIDTH_MASK)) {
392             return width;
393         } else {
394             if (fallback == null) {
395                 return 0;
396             } else {
397                 return fallback.getWidth();
398             }
399         }
400     }
401 
402     /**
403      * Sets <code>width</code> to the supplied value and marks it as valid.
404      *
405      * @param width the width of the image, as an int.
406      * @return a reference to this <code>ImageLayout</code> following the change.
407      * @throws IllegalArgumentException if <code>width</code> is non-positive.
408      */
setWidth(int width)409    public ImageLayout setWidth(int width) {
410        if(width <= 0) {
411            throw new IllegalArgumentException(JaiI18N.getString("ImageLayout0"));
412        }
413        this.width = width;
414        setValid(WIDTH_MASK);
415        return this;
416     }
417 
418     /**
419      * Returns the value of height if it is valid, and
420      * otherwise returns the value from the supplied <code>RenderedImage</code>.
421      * If height is not valid and fallback is null, 0 is returned.
422      *
423      * @param fallback the <code>RenderedImage</code> fallback.
424      * @return the appropriate value of height.
425      */
getHeight(RenderedImage fallback)426     public int getHeight(RenderedImage fallback) {
427         if (isValid(HEIGHT_MASK)) {
428             return height;
429         } else {
430             if (fallback == null) {
431                 return 0;
432             } else {
433                 return fallback.getHeight();
434             }
435         }
436     }
437 
438     /**
439      * Sets height to the supplied value and marks it as valid.
440      *
441      * @param height the height of the image, as an int.
442      * @return a reference to this <code>ImageLayout</code> following the change.
443      * @throws IllegalArgumentException if <code>height</code> is non-positive.
444      */
setHeight(int height)445     public ImageLayout setHeight(int height) {
446        if(height <= 0) {
447            throw new IllegalArgumentException(JaiI18N.getString("ImageLayout0"));
448        }
449        this.height = height;
450        setValid(HEIGHT_MASK);
451        return this;
452     }
453 
454     /**
455      * Returns the value of <code>tileGridXOffset</code> if it is valid, and
456      * otherwise returns the value from the supplied <code>RenderedImage</code>.
457      * If <code>tileGridXOffset</code> is not valid and fallback is null, 0 is returned.
458      *
459      * @param fallback the <code>RenderedImage</code> fallback.
460      * @return the appropriate value of tileGridXOffset.
461      */
getTileGridXOffset(RenderedImage fallback)462     public int getTileGridXOffset(RenderedImage fallback) {
463         if (isValid(TILE_GRID_X_OFFSET_MASK)) {
464             return tileGridXOffset;
465         } else {
466             if (fallback == null) {
467                 return 0;
468             } else {
469                 return fallback.getTileGridXOffset();
470             }
471         }
472     }
473 
474     /**
475      * Sets <code>tileGridXOffset</code> to the supplied value and marks it as valid.
476      *
477      * @param tileGridXOffset the X coordinate of tile (0, 0), as an int.
478      * @return a reference to this <code>ImageLayout</code> following the change.
479      */
setTileGridXOffset(int tileGridXOffset)480     public ImageLayout setTileGridXOffset(int tileGridXOffset) {
481         this.tileGridXOffset = tileGridXOffset;
482         setValid(TILE_GRID_X_OFFSET_MASK);
483         return this;
484     }
485 
486     /**
487      * Returns the value of <code>tileGridYOffset</code> if it is valid, and
488      * otherwise returns the value from the supplied <code>RenderedImage</code>.
489      * If <code>tileGridYOffset</code> is not valid and fallback is null, 0 is returned.
490      *
491      * @param fallback the <code>RenderedImage</code> fallback.
492      * @return the appropriate value of tileGridYOffset.
493      */
getTileGridYOffset(RenderedImage fallback)494     public int getTileGridYOffset(RenderedImage fallback) {
495         if (isValid(TILE_GRID_Y_OFFSET_MASK)) {
496             return tileGridYOffset;
497         } else {
498             if (fallback == null) {
499                 return 0;
500             } else {
501                 return fallback.getTileGridYOffset();
502             }
503         }
504     }
505 
506     /**
507      * Sets <code>tileGridYOffset</code> to the supplied value and marks it as valid.
508      *
509      * @param tileGridYOffset the Y coordinate of tile (0, 0), as an int.
510      * @return a reference to this <code>ImageLayout</code> following the change.
511      */
setTileGridYOffset(int tileGridYOffset)512     public ImageLayout setTileGridYOffset(int tileGridYOffset) {
513         this.tileGridYOffset = tileGridYOffset;
514         setValid(TILE_GRID_Y_OFFSET_MASK);
515         return this;
516     }
517 
518     /**
519      * Returns the value of <code>tileWidth</code> if it is valid, and
520      * otherwise returns the value from the supplied <code>RenderedImage</code>.
521      * If <code>tileWidth</code> is not valid and fallback is null, 0 is returned.
522      *
523      * @param fallback the <code>RenderedImage</code> fallback.
524      * @return the appropriate value of tileWidth.
525      */
getTileWidth(RenderedImage fallback)526     public int getTileWidth(RenderedImage fallback) {
527         if (isValid(TILE_WIDTH_MASK)) {
528             return tileWidth;
529         } else {
530             if (fallback == null) {
531                 return 0;
532             } else {
533                 return fallback.getTileWidth();
534             }
535         }
536     }
537 
538     /**
539      * Sets <code>tileWidth</code> to the supplied value and marks it as valid.
540      *
541      * @param tileWidth the width of a tile, as an int.
542      * @return a reference to this <code>ImageLayout</code> following the change.
543      * @throws IllegalArgumentException if <code>tileWidth</code> is
544      *                                  non-positive.
545      */
setTileWidth(int tileWidth)546     public ImageLayout setTileWidth(int tileWidth) {
547        if(tileWidth <= 0) {
548            throw new IllegalArgumentException(JaiI18N.getString("ImageLayout0"));
549        }
550        this.tileWidth = tileWidth;
551        setValid(TILE_WIDTH_MASK);
552        return this;
553     }
554 
555     /**
556      * Returns the value of tileHeight if it is valid, and
557      * otherwise returns the value from the supplied <code>RenderedImage</code>.
558      * If tileHeight is not valid and fallback is null, 0 is returned.
559      *
560      * @param fallback the <code>RenderedImage</code> fallback.
561      * @return the appropriate value of tileHeight.
562      */
getTileHeight(RenderedImage fallback)563     public int getTileHeight(RenderedImage fallback) {
564         if (isValid(TILE_HEIGHT_MASK)) {
565             return tileHeight;
566         } else {
567             if (fallback == null) {
568                 return 0;
569             } else {
570                 return fallback.getTileHeight();
571             }
572         }
573     }
574 
575     /**
576      * Sets tileHeight to the supplied value and marks it as valid.
577      *
578      * @param tileHeight the height of a tile, as an int.
579      * @return a reference to this <code>ImageLayout</code> following the change.
580      * @throws IllegalArgumentException if <code>tileHeight</code> is
581      *                                  non-positive.
582      */
setTileHeight(int tileHeight)583     public ImageLayout setTileHeight(int tileHeight) {
584        if(tileHeight <= 0) {
585            throw new IllegalArgumentException(JaiI18N.getString("ImageLayout0"));
586        }
587        this.tileHeight = tileHeight;
588        setValid(TILE_HEIGHT_MASK);
589        return this;
590     }
591 
592     /**
593      * Returns the value of <code>sampleModel</code> if it is valid, and
594      * otherwise returns the value from the supplied <code>RenderedImage</code>.
595      * If <code>sampleModel</code> is not valid and fallback is null, null is returned.
596      *
597      * @param fallback the <code>RenderedImage</code> fallback.
598      * @return the appropriate value of <code>sampleModel</code>.
599      */
getSampleModel(RenderedImage fallback)600     public SampleModel getSampleModel(RenderedImage fallback) {
601         if (isValid(SAMPLE_MODEL_MASK)) {
602             return sampleModel;
603         } else {
604             if (fallback == null) {
605                 return null;
606             } else {
607                 return fallback.getSampleModel();
608             }
609         }
610     }
611 
612     /**
613      * Sets <code>sampleModel</code> to the supplied value and marks it as valid.
614      *
615      * @param sampleModel the new <code>SampleModel</code>.
616      * @return a reference to this <code>ImageLayout</code> following the change.
617      */
setSampleModel(SampleModel sampleModel)618     public ImageLayout setSampleModel(SampleModel sampleModel) {
619         this.sampleModel = sampleModel;
620         setValid(SAMPLE_MODEL_MASK);
621         return this;
622     }
623 
624     /**
625      * Returns the value of <code>colorModel</code> if it is valid, and
626      * otherwise returns the value from the supplied <code>RenderedImage</code>.
627      * If <code>colorModel</code> is not valid and fallback is null, null is returned.
628      *
629      * @param fallback the <code>RenderedImage</code> fallback.
630      * @return the appropriate value of <code>colorModel</code>.
631      */
getColorModel(RenderedImage fallback)632     public ColorModel getColorModel(RenderedImage fallback) {
633         if (isValid(COLOR_MODEL_MASK)) {
634             return colorModel;
635         } else {
636             if (fallback == null) {
637                 return null;
638             } else {
639                 return fallback.getColorModel();
640             }
641         }
642     }
643 
644     /**
645      * Sets <code>colorModel</code> to the supplied value and marks it as valid.
646      *
647      * @param colorModel the new <code>ColorModel</code>.
648      * @return a reference to this <code>ImageLayout</code> following the change.
649      */
setColorModel(ColorModel colorModel)650     public ImageLayout setColorModel(ColorModel colorModel) {
651         this.colorModel = colorModel;
652         setValid(COLOR_MODEL_MASK);
653         return this;
654     }
655 
656     /** Returns a String containing the values of all valid fields. */
toString()657     public String toString() {
658         String s = "ImageLayout[";
659         boolean first = true;
660 
661         if (isValid(MIN_X_MASK)) {
662             s += "MIN_X=" + minX;
663             first = false;
664         }
665 
666         if (isValid(MIN_Y_MASK)) {
667             if (!first) {
668                 s += ", ";
669             }
670             s += "MIN_Y=" + minY;
671             first = false;
672         }
673 
674         if (isValid(WIDTH_MASK)) {
675             if (!first) {
676                 s += ", ";
677             }
678             s += "WIDTH=" + width;
679             first = false;
680         }
681 
682         if (isValid(HEIGHT_MASK)) {
683             if (!first) {
684                 s += ", ";
685             }
686             s += "HEIGHT=" + height;
687             first = false;
688         }
689 
690         if (isValid(TILE_GRID_X_OFFSET_MASK)) {
691             if (!first) {
692                 s += ", ";
693             }
694             s += "TILE_GRID_X_OFFSET=" + tileGridXOffset;
695             first = false;
696         }
697 
698         if (isValid(TILE_GRID_Y_OFFSET_MASK)) {
699             if (!first) {
700                 s += ", ";
701             }
702             s += "TILE_GRID_Y_OFFSET=" + tileGridYOffset;
703             first = false;
704         }
705 
706         if (isValid(TILE_WIDTH_MASK)) {
707             if (!first) {
708                 s += ", ";
709             }
710             s += "TILE_WIDTH=" + tileWidth;
711             first = false;
712         }
713 
714         if (isValid(TILE_HEIGHT_MASK)) {
715             if (!first) {
716                 s += ", ";
717             }
718             s += "TILE_HEIGHT=" + tileHeight;
719             first = false;
720         }
721 
722         if (isValid(SAMPLE_MODEL_MASK)) {
723             if (!first) {
724                 s += ", ";
725             }
726             s += "SAMPLE_MODEL=" + sampleModel;
727             first = false;
728         }
729 
730         if (isValid(COLOR_MODEL_MASK)) {
731             if (!first) {
732                 s += ", ";
733             }
734             s += "COLOR_MODEL=" + colorModel;
735         }
736 
737         s += "]";
738         return s;
739     }
740 
741     /**
742      * Returns a clone of the <code>ImageLayout</code> as an Object.
743      */
clone()744     public Object clone() {
745         try {
746             return super.clone();
747         } catch (CloneNotSupportedException e) {
748             return null;
749         }
750     }
751 
752     /**
753      * Serialize the <code>ImageLayout</code>.
754      * @throws IOException
755      */
writeObject(ObjectOutputStream out)756     private void writeObject(ObjectOutputStream out) throws IOException {
757         // Write the non-static and non-transient fields.
758         out.defaultWriteObject();
759 
760         // Create and write a serializable SampleModel.
761         if(isValid(SAMPLE_MODEL_MASK)) {
762             out.writeObject(SerializerFactory.getState(sampleModel, null));
763         }
764 
765         // Create and write a serializable ColorModel.
766         if(isValid(COLOR_MODEL_MASK)) {
767             out.writeObject(SerializerFactory.getState(colorModel, null));
768         }
769     }
770 
771     /**
772      * Deserialize the <code>ImageLayout</code>.
773      * @throws IOException
774      */
readObject(ObjectInputStream in)775     private void readObject(ObjectInputStream in)
776         throws IOException, ClassNotFoundException {
777         // Read the non-static and non-transient fields.
778         in.defaultReadObject();
779 
780         // Read the serializable form of the SampleModel.
781         if(isValid(SAMPLE_MODEL_MASK)) {
782             Object object = in.readObject();
783             if (!(object instanceof SerializableState))
784                 sampleModel = null;
785 
786             SerializableState ss = (SerializableState)object;
787             Class c = ss.getObjectClass();
788             if (SampleModel.class.isAssignableFrom(c))
789                 sampleModel = (SampleModel)ss.getObject();
790             else
791                 sampleModel = null;
792         }
793 
794         // Read the serializable form of the ColorModel.
795         if(isValid(COLOR_MODEL_MASK)) {
796             Object object = in.readObject();
797             if (!(object instanceof SerializableState))
798                 colorModel = null;
799 
800             SerializableState ss = (SerializableState)object;
801             Class c = ss.getObjectClass();
802             if (ColorModel.class.isAssignableFrom(c))
803                 colorModel = (ColorModel)ss.getObject();
804             else
805                 colorModel = null;
806         }
807     }
808 
809     /**
810      * Tests if the specified <code>Object</code> equals this
811      * <code>ImageLayout</code>.
812      *
813      * @param obj the <code>Object</code> to test for equality
814      *
815      * @return <code>true</code> if the specified <code>Object</code>
816      * is an instance of <code>ImageLayout</code> and equals this
817      * <code>ImageLayout</code>; <code>false</code> otherwise.
818      *
819      * @since JAI 1.1
820      */
equals(Object obj)821     public boolean equals(Object obj) {
822 
823 	if (this == obj)
824 	    return true;
825 
826 	if (!(obj instanceof ImageLayout))
827 	    return false;
828 
829 	ImageLayout il = (ImageLayout)obj;
830 
831 	return (validMask       == il.validMask      ) &&
832 	       (width           == il.width          ) &&
833 	       (height          == il.height         ) &&
834 	       (minX            == il.minX           ) &&
835 	       (minY            == il.minY           ) &&
836 	       (tileHeight      == il.tileHeight     ) &&
837 	       (tileWidth       == il.tileWidth      ) &&
838 	       (tileGridXOffset == il.tileGridXOffset) &&
839 	       (tileGridYOffset == il.tileGridYOffset) &&
840 	       (sampleModel.equals(il.sampleModel   )) &&
841 	       (colorModel.equals(il.colorModel));
842     }
843 
844     /**
845      * Returns the hash code for this <code>ImageLayout</code>.
846      *
847      * @return a hash code for this <code>ImageLayout</code>.
848      *
849      * @since JAI 1.1
850      */
hashCode()851     public int hashCode() {
852 
853 	int code = 0, i = 1;
854 
855 	// This implementation is quite arbitrary.
856 	// hashCode's NEED not be uniqe for two "different" objects
857 	code += (width           * i++);
858 	code += (height          * i++);
859 	code += (minX            * i++);
860 	code += (minY            * i++);
861 	code += (tileHeight      * i++);
862 	code += (tileWidth       * i++);
863 	code += (tileGridXOffset * i++);
864 	code += (tileGridYOffset * i++);
865 
866 	code ^= sampleModel.hashCode();
867 	code ^= validMask;
868 	code ^= colorModel.hashCode();
869 
870 	return code;
871     }
872 }
873