KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > MultipleGradientPaintContext


1 /*
2  * @(#)MultipleGradientPaintContext.java 1.2 06/04/24
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.awt;
9
10 import java.awt.MultipleGradientPaint.CycleMethod JavaDoc;
11 import java.awt.MultipleGradientPaint.ColorSpaceType JavaDoc;
12 import java.awt.color.ColorSpace JavaDoc;
13 import java.awt.geom.AffineTransform JavaDoc;
14 import java.awt.geom.NoninvertibleTransformException JavaDoc;
15 import java.awt.geom.Rectangle2D JavaDoc;
16 import java.awt.image.ColorModel JavaDoc;
17 import java.awt.image.DataBuffer JavaDoc;
18 import java.awt.image.DataBufferInt JavaDoc;
19 import java.awt.image.DirectColorModel JavaDoc;
20 import java.awt.image.Raster JavaDoc;
21 import java.awt.image.SinglePixelPackedSampleModel JavaDoc;
22 import java.awt.image.WritableRaster JavaDoc;
23 import java.lang.ref.SoftReference JavaDoc;
24 import java.lang.ref.WeakReference JavaDoc;
25 import java.util.Arrays JavaDoc;
26
27 /**
28  * This is the superclass for all PaintContexts which use a multiple color
29  * gradient to fill in their raster. It provides the actual color
30  * interpolation functionality. Subclasses only have to deal with using
31  * the gradient to fill pixels in a raster.
32  *
33  * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
34  */

35 abstract class MultipleGradientPaintContext implements PaintContext JavaDoc {
36     
37     /**
38      * The PaintContext's ColorModel. This is ARGB if colors are not all
39      * opaque, otherwise it is RGB.
40      */

41     protected ColorModel JavaDoc model;
42     
43     /** Color model used if gradient colors are all opaque. */
44     private static ColorModel JavaDoc xrgbmodel =
45         new DirectColorModel JavaDoc(24, 0x00ff0000, 0x0000ff00, 0x000000ff);
46
47     /** The cached ColorModel. */
48     protected static ColorModel JavaDoc cachedModel;
49
50     /** The cached raster, which is reusable among instances. */
51     protected static WeakReference JavaDoc<Raster JavaDoc> cached;
52     
53     /** Raster is reused whenever possible. */
54     protected Raster JavaDoc saved;
55
56     /** The method to use when painting out of the gradient bounds. */
57     protected CycleMethod cycleMethod;
58     
59     /** The ColorSpace in which to perform the interpolation */
60     protected ColorSpaceType colorSpace;
61
62     /** Elements of the inverse transform matrix. */
63     protected float a00, a01, a10, a11, a02, a12;
64     
65     /**
66      * This boolean specifies wether we are in simple lookup mode, where an
67      * input value between 0 and 1 may be used to directly index into a single
68      * array of gradient colors. If this boolean value is false, then we have
69      * to use a 2-step process where we have to determine which gradient array
70      * we fall into, then determine the index into that array.
71      */

72     protected boolean isSimpleLookup;
73     
74     /**
75      * Size of gradients array for scaling the 0-1 index when looking up
76      * colors the fast way.
77      */

78     protected int fastGradientArraySize;
79     
80     /**
81      * Array which contains the interpolated color values for each interval,
82      * used by calculateSingleArrayGradient(). It is protected for possible
83      * direct access by subclasses.
84      */

85     protected int[] gradient;
86     
87     /**
88      * Array of gradient arrays, one array for each interval. Used by
89      * calculateMultipleArrayGradient().
90      */

91     private int[][] gradients;
92
93     /** Normalized intervals array. */
94     private float[] normalizedIntervals;
95     
96     /** Fractions array. */
97     private float[] fractions;
98     
99     /** Used to determine if gradient colors are all opaque. */
100     private int transparencyTest;
101
102     /** Color space conversion lookup tables. */
103     private static final int SRGBtoLinearRGB[] = new int[256];
104     private static final int LinearRGBtoSRGB[] = new int[256];
105
106     static {
107         // build the tables
108
for (int k = 0; k < 256; k++) {
109             SRGBtoLinearRGB[k] = convertSRGBtoLinearRGB(k);
110             LinearRGBtoSRGB[k] = convertLinearRGBtoSRGB(k);
111         }
112     }
113
114     /**
115      * Constant number of max colors between any 2 arbitrary colors.
116      * Used for creating and indexing gradients arrays.
117      */

118     protected static final int GRADIENT_SIZE = 256;
119     protected static final int GRADIENT_SIZE_INDEX = GRADIENT_SIZE -1;
120
121     /**
122      * Maximum length of the fast single-array. If the estimated array size
123      * is greater than this, switch over to the slow lookup method.
124      * No particular reason for choosing this number, but it seems to provide
125      * satisfactory performance for the common case (fast lookup).
126      */

127     private static final int MAX_GRADIENT_ARRAY_SIZE = 5000;
128
129     /**
130      * Constructor for MultipleGradientPaintContext superclass.
131      */

132     protected MultipleGradientPaintContext(MultipleGradientPaint JavaDoc mgp,
133                                            ColorModel JavaDoc cm,
134                                            Rectangle JavaDoc deviceBounds,
135                                            Rectangle2D JavaDoc userBounds,
136                                            AffineTransform JavaDoc t,
137                                            RenderingHints JavaDoc hints,
138                                            float[] fractions,
139                                            Color JavaDoc[] colors,
140                                            CycleMethod cycleMethod,
141                                            ColorSpaceType colorSpace)
142     {
143         if (deviceBounds == null) {
144             throw new NullPointerException JavaDoc("Device bounds cannot be null");
145         }
146
147         if (userBounds == null) {
148             throw new NullPointerException JavaDoc("User bounds cannot be null");
149         }
150
151         if (t == null) {
152             throw new NullPointerException JavaDoc("Transform cannot be null");
153         }
154
155         if (hints == null) {
156             throw new NullPointerException JavaDoc("RenderingHints cannot be null");
157         }
158
159         // The inverse transform is needed to go from device to user space.
160
// Get all the components of the inverse transform matrix.
161
AffineTransform JavaDoc tInv;
162         try {
163             // the following assumes that the caller has copied the incoming
164
// transform and is not concerned about it being modified
165
t.invert();
166             tInv = t;
167         } catch (NoninvertibleTransformException JavaDoc e) {
168             // just use identity transform in this case; better to show
169
// (incorrect) results than to throw an exception and/or no-op
170
tInv = new AffineTransform JavaDoc();
171         }
172         double m[] = new double[6];
173         tInv.getMatrix(m);
174         a00 = (float)m[0];
175         a10 = (float)m[1];
176         a01 = (float)m[2];
177         a11 = (float)m[3];
178         a02 = (float)m[4];
179         a12 = (float)m[5];
180         
181         // copy some flags
182
this.cycleMethod = cycleMethod;
183         this.colorSpace = colorSpace;
184
185         // we can avoid copying this array since we do not modify its values
186
this.fractions = fractions;
187
188         // note that only one of these values can ever be non-null (we either
189
// store the fast gradient array or the slow one, but never both
190
// at the same time)
191
int[] gradient =
192             (mgp.gradient != null) ? mgp.gradient.get() : null;
193         int[][] gradients =
194             (mgp.gradients != null) ? mgp.gradients.get() : null;
195
196         if (gradient == null && gradients == null) {
197             // we need to (re)create the appropriate values
198
calculateLookupData(colors);
199
200             // now cache the calculated values in the
201
// MultipleGradientPaint instance for future use
202
mgp.model = this.model;
203             mgp.normalizedIntervals = this.normalizedIntervals;
204             mgp.isSimpleLookup = this.isSimpleLookup;
205             if (isSimpleLookup) {
206                 // only cache the fast array
207
mgp.fastGradientArraySize = this.fastGradientArraySize;
208                 mgp.gradient = new SoftReference JavaDoc<int[]>(this.gradient);
209             } else {
210                 // only cache the slow array
211
mgp.gradients = new SoftReference JavaDoc<int[][]>(this.gradients);
212             }
213         } else {
214             // use the values cached in the MultipleGradientPaint instance
215
this.model = mgp.model;
216             this.normalizedIntervals = mgp.normalizedIntervals;
217             this.isSimpleLookup = mgp.isSimpleLookup;
218             this.gradient = gradient;
219             this.fastGradientArraySize = mgp.fastGradientArraySize;
220             this.gradients = gradients;
221         }
222     }
223     
224     /**
225      * This function is the meat of this class. It calculates an array of
226      * gradient colors based on an array of fractions and color values at
227      * those fractions.
228      */

229     private void calculateLookupData(Color JavaDoc[] colors) {
230         Color JavaDoc[] normalizedColors;
231         if (colorSpace == ColorSpaceType.LINEAR_RGB) {
232             // create a new colors array
233
normalizedColors = new Color JavaDoc[colors.length];
234             // convert the colors using the lookup table
235
for (int i = 0; i < colors.length; i++) {
236                 int argb = colors[i].getRGB();
237                 int a = argb >>> 24;
238                 int r = SRGBtoLinearRGB[(argb >> 16) & 0xff];
239                 int g = SRGBtoLinearRGB[(argb >> 8) & 0xff];
240                 int b = SRGBtoLinearRGB[(argb ) & 0xff];
241                 normalizedColors[i] = new Color JavaDoc(r, g, b, a);
242             }
243         } else {
244             // we can just use this array by reference since we do not
245
// modify its values in the case of SRGB
246
normalizedColors = colors;
247         }
248
249         // this will store the intervals (distances) between gradient stops
250
normalizedIntervals = new float[fractions.length-1];
251
252         // convert from fractions into intervals
253
for (int i = 0; i < normalizedIntervals.length; i++) {
254             // interval distance is equal to the difference in positions
255
normalizedIntervals[i] = this.fractions[i+1] - this.fractions[i];
256         }
257
258         // initialize to be fully opaque for ANDing with colors
259
transparencyTest = 0xff000000;
260
261         // array of interpolation arrays
262
gradients = new int[normalizedIntervals.length][];
263
264         // find smallest interval
265
float Imin = 1;
266         for (int i = 0; i < normalizedIntervals.length; i++) {
267             Imin = (Imin > normalizedIntervals[i]) ?
268                 normalizedIntervals[i] : Imin;
269         }
270
271         // Estimate the size of the entire gradients array.
272
// This is to prevent a tiny interval from causing the size of array
273
// to explode. If the estimated size is too large, break to using
274
// separate arrays for each interval, and using an indexing scheme at
275
// look-up time.
276
int estimatedSize = 0;
277         for (int i = 0; i < normalizedIntervals.length; i++) {
278             estimatedSize += (normalizedIntervals[i]/Imin) * GRADIENT_SIZE;
279         }
280         
281         if (estimatedSize > MAX_GRADIENT_ARRAY_SIZE) {
282             // slow method
283
calculateMultipleArrayGradient(normalizedColors);
284         } else {
285             // fast method
286
calculateSingleArrayGradient(normalizedColors, Imin);
287         }
288         
289         // use the most "economical" model
290
if ((transparencyTest >>> 24) == 0xff) {
291             model = xrgbmodel;
292         } else {
293             model = ColorModel.getRGBdefault();
294         }
295     }
296     
297     /**
298      * FAST LOOKUP METHOD
299      *
300      * This method calculates the gradient color values and places them in a
301      * single int array, gradient[]. It does this by allocating space for
302      * each interval based on its size relative to the smallest interval in
303      * the array. The smallest interval is allocated 255 interpolated values
304      * (the maximum number of unique in-between colors in a 24 bit color
305      * system), and all other intervals are allocated
306      * size = (255 * the ratio of their size to the smallest interval).
307      *
308      * This scheme expedites a speedy retrieval because the colors are
309      * distributed along the array according to their user-specified
310      * distribution. All that is needed is a relative index from 0 to 1.
311      *
312      * The only problem with this method is that the possibility exists for
313      * the array size to balloon in the case where there is a
314      * disproportionately small gradient interval. In this case the other
315      * intervals will be allocated huge space, but much of that data is
316      * redundant. We thus need to use the space conserving scheme below.
317      *
318      * @param Imin the size of the smallest interval
319      */

320     private void calculateSingleArrayGradient(Color JavaDoc[] colors, float Imin) {
321         // set the flag so we know later it is a simple (fast) lookup
322
isSimpleLookup = true;
323
324         // 2 colors to interpolate
325
int rgb1, rgb2;
326
327         //the eventual size of the single array
328
int gradientsTot = 1;
329         
330         // for every interval (transition between 2 colors)
331
for (int i = 0; i < gradients.length; i++) {
332             // create an array whose size is based on the ratio to the
333
// smallest interval
334
int nGradients = (int)((normalizedIntervals[i]/Imin)*255f);
335             gradientsTot += nGradients;
336             gradients[i] = new int[nGradients];
337             
338             // the 2 colors (keyframes) to interpolate between
339
rgb1 = colors[i].getRGB();
340             rgb2 = colors[i+1].getRGB();
341             
342             // fill this array with the colors in between rgb1 and rgb2
343
interpolate(rgb1, rgb2, gradients[i]);
344             
345             // if the colors are opaque, transparency should still
346
// be 0xff000000
347
transparencyTest &= rgb1;
348             transparencyTest &= rgb2;
349         }
350
351         // put all gradients in a single array
352
gradient = new int[gradientsTot];
353         int curOffset = 0;
354         for (int i = 0; i < gradients.length; i++){
355             System.arraycopy(gradients[i], 0, gradient,
356                              curOffset, gradients[i].length);
357             curOffset += gradients[i].length;
358         }
359         gradient[gradient.length-1] = colors[colors.length-1].getRGB();
360
361         // if interpolation occurred in Linear RGB space, convert the
362
// gradients back to sRGB using the lookup table
363
if (colorSpace == ColorSpaceType.LINEAR_RGB) {
364             for (int i = 0; i < gradient.length; i++) {
365                 gradient[i] = convertEntireColorLinearRGBtoSRGB(gradient[i]);
366             }
367         }
368
369         fastGradientArraySize = gradient.length - 1;
370     }
371
372     /**
373      * SLOW LOOKUP METHOD
374      *
375      * This method calculates the gradient color values for each interval and
376      * places each into its own 255 size array. The arrays are stored in
377      * gradients[][]. (255 is used because this is the maximum number of
378      * unique colors between 2 arbitrary colors in a 24 bit color system.)
379      *
380      * This method uses the minimum amount of space (only 255 * number of
381      * intervals), but it aggravates the lookup procedure, because now we
382      * have to find out which interval to select, then calculate the index
383      * within that interval. This causes a significant performance hit,
384      * because it requires this calculation be done for every point in
385      * the rendering loop.
386      *
387      * For those of you who are interested, this is a classic example of the
388      * time-space tradeoff.
389      */

390     private void calculateMultipleArrayGradient(Color JavaDoc[] colors) {
391         // set the flag so we know later it is a non-simple lookup
392
isSimpleLookup = false;
393
394         // 2 colors to interpolate
395
int rgb1, rgb2;
396         
397         // for every interval (transition between 2 colors)
398
for (int i = 0; i < gradients.length; i++){
399             // create an array of the maximum theoretical size for
400
// each interval
401
gradients[i] = new int[GRADIENT_SIZE];
402                         
403             // get the the 2 colors
404
rgb1 = colors[i].getRGB();
405             rgb2 = colors[i+1].getRGB();
406             
407             // fill this array with the colors in between rgb1 and rgb2
408
interpolate(rgb1, rgb2, gradients[i]);
409             
410             // if the colors are opaque, transparency should still
411
// be 0xff000000
412
transparencyTest &= rgb1;
413             transparencyTest &= rgb2;
414         }
415         
416         // if interpolation occurred in Linear RGB space, convert the
417
// gradients back to SRGB using the lookup table
418
if (colorSpace == ColorSpaceType.LINEAR_RGB) {
419             for (int j = 0; j < gradients.length; j++) {
420                 for (int i = 0; i < gradients[j].length; i++) {
421                     gradients[j][i] =
422                         convertEntireColorLinearRGBtoSRGB(gradients[j][i]);
423                 }
424             }
425         }
426     }
427     
428     /**
429      * Yet another helper function. This one linearly interpolates between
430      * 2 colors, filling up the output array.
431      *
432      * @param rgb1 the start color
433      * @param rgb2 the end color
434      * @param output the output array of colors; must not be null
435      */

436     private void interpolate(int rgb1, int rgb2, int[] output) {
437         // color components
438
int a1, r1, g1, b1, da, dr, dg, db;
439         
440         // step between interpolated values
441
float stepSize = 1.0f / output.length;
442         
443         // extract color components from packed integer
444
a1 = (rgb1 >> 24) & 0xff;
445         r1 = (rgb1 >> 16) & 0xff;
446         g1 = (rgb1 >> 8) & 0xff;
447         b1 = (rgb1 ) & 0xff;
448
449         // calculate the total change in alpha, red, green, blue
450
da = ((rgb2 >> 24) & 0xff) - a1;
451         dr = ((rgb2 >> 16) & 0xff) - r1;
452         dg = ((rgb2 >> 8) & 0xff) - g1;
453         db = ((rgb2 ) & 0xff) - b1;
454         
455         // for each step in the interval calculate the in-between color by
456
// multiplying the normalized current position by the total color
457
// change (0.5 is added to prevent truncation round-off error)
458
for (int i = 0; i < output.length; i++) {
459             output[i] =
460                 (((int) ((a1 + i * da * stepSize) + 0.5) << 24)) |
461                 (((int) ((r1 + i * dr * stepSize) + 0.5) << 16)) |
462                 (((int) ((g1 + i * dg * stepSize) + 0.5) << 8)) |
463                 (((int) ((b1 + i * db * stepSize) + 0.5) ));
464         }
465     }
466     
467     /**
468      * Yet another helper function. This one extracts the color components
469      * of an integer RGB triple, converts them from LinearRGB to SRGB, then
470      * recompacts them into an int.
471      */

472     private int convertEntireColorLinearRGBtoSRGB(int rgb) {
473         // color components
474
int a1, r1, g1, b1;
475
476         // extract red, green, blue components
477
a1 = (rgb >> 24) & 0xff;
478         r1 = (rgb >> 16) & 0xff;
479         g1 = (rgb >> 8) & 0xff;
480         b1 = (rgb ) & 0xff;
481
482         // use the lookup table
483
r1 = LinearRGBtoSRGB[r1];
484         g1 = LinearRGBtoSRGB[g1];
485         b1 = LinearRGBtoSRGB[b1];
486
487         // re-compact the components
488
return ((a1 << 24) |
489                 (r1 << 16) |
490                 (g1 << 8) |
491                 (b1 ));
492     }
493
494     /**
495      * Helper function to index into the gradients array. This is necessary
496      * because each interval has an array of colors with uniform size 255.
497      * However, the color intervals are not necessarily of uniform length, so
498      * a conversion is required.
499      *
500      * @param position the unmanipulated position, which will be mapped
501      * into the range 0 to 1
502      * @returns integer color to display
503      */

504     protected final int indexIntoGradientsArrays(float position) {
505         // first, manipulate position value depending on the cycle method
506
if (cycleMethod == CycleMethod.NO_CYCLE) {
507             if (position > 1) {
508                 // upper bound is 1
509
position = 1;
510             } else if (position < 0) {
511                 // lower bound is 0
512
position = 0;
513             }
514         } else if (cycleMethod == CycleMethod.REPEAT) {
515             // get the fractional part
516
// (modulo behavior discards integer component)
517
position = position - (int)position;
518
519             //position should now be between -1 and 1
520
if (position < 0) {
521                 // force it to be in the range 0-1
522
position = position + 1;
523             }
524         } else { // cycleMethod == CycleMethod.REFLECT
525
if (position < 0) {
526                 // take absolute value
527
position = -position;
528             }
529
530             // get the integer part
531
int part = (int)position;
532
533             // get the fractional part
534
position = position - part;
535
536             if ((part & 1) == 1) {
537                 // integer part is odd, get reflected color instead
538
position = 1 - position;
539             }
540         }
541        
542         // now, get the color based on this 0-1 position...
543

544         if (isSimpleLookup) {
545             // easy to compute: just scale index by array size
546
return gradient[(int)(position * fastGradientArraySize)];
547         } else {
548             // more complicated computation, to save space
549

550             // for all the gradient interval arrays
551
for (int i = 0; i < gradients.length; i++) {
552                 if (position < fractions[i+1]) {
553                     // this is the array we want
554
float delta = position - fractions[i];
555
556                     // this is the interval we want
557
int index = (int)((delta / normalizedIntervals[i])
558                                       * (GRADIENT_SIZE_INDEX));
559                     
560                     return gradients[i][index];
561                 }
562             }
563         }
564         
565         return gradients[gradients.length - 1][GRADIENT_SIZE_INDEX];
566     }
567     
568     /**
569      * Helper function to convert a color component in sRGB space to linear
570      * RGB space. Used to build a static lookup table.
571      */

572     private static int convertSRGBtoLinearRGB(int color) {
573         float input, output;
574
575         input = color / 255.0f;
576         if (input <= 0.04045f) {
577             output = input / 12.92f;
578         } else {
579             output = (float)Math.pow((input + 0.055) / 1.055, 2.4);
580         }
581
582         return Math.round(output * 255.0f);
583     }
584
585     /**
586      * Helper function to convert a color component in linear RGB space to
587      * SRGB space. Used to build a static lookup table.
588      */

589     private static int convertLinearRGBtoSRGB(int color) {
590         float input, output;
591
592         input = color/255.0f;
593         if (input <= 0.0031308) {
594             output = input * 12.92f;
595         } else {
596             output = (1.055f *
597                 ((float) Math.pow(input, (1.0 / 2.4)))) - 0.055f;
598         }
599
600         return Math.round(output * 255.0f);
601     }
602
603     /**
604      * {@inheritDoc}
605      */

606     public final Raster JavaDoc getRaster(int x, int y, int w, int h) {
607         // If working raster is big enough, reuse it. Otherwise,
608
// build a large enough new one.
609
Raster JavaDoc raster = saved;
610         if (raster == null ||
611             raster.getWidth() < w || raster.getHeight() < h)
612         {
613             raster = getCachedRaster(model, w, h);
614             saved = raster;
615         }
616
617         // Access raster internal int array. Because we use a DirectColorModel,
618
// we know the DataBuffer is of type DataBufferInt and the SampleModel
619
// is SinglePixelPackedSampleModel.
620
// Adjust for initial offset in DataBuffer and also for the scanline
621
// stride.
622
DataBufferInt JavaDoc rasterDB = (DataBufferInt JavaDoc)raster.getDataBuffer();
623         int[] pixels = rasterDB.getBankData()[0];
624         int off = rasterDB.getOffset();
625         int scanlineStride = ((SinglePixelPackedSampleModel JavaDoc)
626                               raster.getSampleModel()).getScanlineStride();
627         int adjust = scanlineStride - w;
628         
629         fillRaster(pixels, off, adjust, x, y, w, h); // delegate to subclass
630

631         return raster;
632     }
633     
634     protected abstract void fillRaster(int pixels[], int off, int adjust,
635                                        int x, int y, int w, int h);
636
637     
638     /**
639      * Took this cacheRaster code from GradientPaint. It appears to recycle
640      * rasters for use by any other instance, as long as they are sufficiently
641      * large.
642      */

643     private static synchronized Raster JavaDoc getCachedRaster(ColorModel JavaDoc cm,
644                                                        int w, int h)
645     {
646         if (cm == cachedModel) {
647             if (cached != null) {
648                 Raster JavaDoc ras = (Raster JavaDoc) cached.get();
649                 if (ras != null &&
650                     ras.getWidth() >= w &&
651                     ras.getHeight() >= h)
652                 {
653                     cached = null;
654                     return ras;
655                 }
656             }
657         }
658         return cm.createCompatibleWritableRaster(w, h);
659     }
660     
661     /**
662      * Took this cacheRaster code from GradientPaint. It appears to recycle
663      * rasters for use by any other instance, as long as they are sufficiently
664      * large.
665      */

666     private static synchronized void putCachedRaster(ColorModel JavaDoc cm,
667                                                      Raster JavaDoc ras)
668     {
669         if (cached != null) {
670             Raster JavaDoc cras = (Raster JavaDoc) cached.get();
671             if (cras != null) {
672                 int cw = cras.getWidth();
673                 int ch = cras.getHeight();
674                 int iw = ras.getWidth();
675                 int ih = ras.getHeight();
676                 if (cw >= iw && ch >= ih) {
677                     return;
678                 }
679                 if (cw * ch >= iw * ih) {
680                     return;
681                 }
682             }
683         }
684         cachedModel = cm;
685         cached = new WeakReference JavaDoc<Raster JavaDoc>(ras);
686     }
687     
688     /**
689      * {@inheritDoc}
690      */

691     public final void dispose() {
692         if (saved != null) {
693             putCachedRaster(model, saved);
694             saved = null;
695         }
696     }
697     
698     /**
699      * {@inheritDoc}
700      */

701     public final ColorModel JavaDoc getColorModel() {
702         return model;
703     }
704 }
705
Popular Tags