KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > ext > awt > MultipleGradientPaintContext


1 /*
2
3    Copyright 2001-2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.ext.awt;
19
20 import java.awt.Color JavaDoc;
21 import java.awt.PaintContext JavaDoc;
22 import java.awt.Rectangle JavaDoc;
23 import java.awt.RenderingHints JavaDoc;
24 import java.awt.color.ColorSpace JavaDoc;
25 import java.awt.geom.AffineTransform JavaDoc;
26 import java.awt.geom.NoninvertibleTransformException JavaDoc;
27 import java.awt.geom.Rectangle2D JavaDoc;
28 import java.awt.image.ColorModel JavaDoc;
29 import java.awt.image.DataBuffer JavaDoc;
30 import java.awt.image.DataBufferInt JavaDoc;
31 import java.awt.image.DirectColorModel JavaDoc;
32 import java.awt.image.Raster JavaDoc;
33 import java.awt.image.SinglePixelPackedSampleModel JavaDoc;
34 import java.awt.image.WritableRaster JavaDoc;
35 import java.lang.ref.WeakReference JavaDoc;
36
37 import org.apache.batik.ext.awt.image.GraphicsUtil;
38
39 /** This is the superclass for all PaintContexts which use a multiple color
40  * gradient to fill in their raster. It provides the actual color interpolation
41  * functionality. Subclasses only have to deal with using the gradient to fill
42  * pixels in a raster.
43  *
44  * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
45  * @author <a HREF="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
46  * @version $Id: MultipleGradientPaintContext.java,v 1.19 2004/08/18 07:13:41 vhardy Exp $
47  *
48  */

49 abstract class MultipleGradientPaintContext implements PaintContext JavaDoc {
50
51     protected final static boolean DEBUG = false;
52
53     /**
54      * The color model data is generated in (always un premult).
55      */

56     protected ColorModel JavaDoc dataModel;
57     /**
58      * PaintContext's output ColorModel ARGB if colors are not all
59      * opaque, RGB otherwise. Linear and premult are matched to
60      * output ColorModel.
61      */

62     protected ColorModel JavaDoc model;
63
64     /** Color model used if gradient colors are all opaque */
65     private static ColorModel JavaDoc lrgbmodel_NA = new DirectColorModel JavaDoc
66         (ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB),
67          24, 0xff0000, 0xFF00, 0xFF, 0x0,
68          false, DataBuffer.TYPE_INT);
69
70     private static ColorModel JavaDoc srgbmodel_NA = new DirectColorModel JavaDoc
71         (ColorSpace.getInstance(ColorSpace.CS_sRGB),
72          24, 0xff0000, 0xFF00, 0xFF, 0x0,
73          false, DataBuffer.TYPE_INT);
74
75     /** Color model used if some gradient colors are transparent */
76     private static ColorModel JavaDoc lrgbmodel_A = new DirectColorModel JavaDoc
77         (ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB),
78          32, 0xff0000, 0xFF00, 0xFF, 0xFF000000,
79          false, DataBuffer.TYPE_INT);
80
81     private static ColorModel JavaDoc srgbmodel_A = new DirectColorModel JavaDoc
82         (ColorSpace.getInstance(ColorSpace.CS_sRGB),
83          32, 0xff0000, 0xFF00, 0xFF, 0xFF000000,
84          false, DataBuffer.TYPE_INT);
85
86      /** The cached colorModel */
87     protected static ColorModel JavaDoc cachedModel;
88
89     /** The cached raster, which is reusable among instances */
90     protected static WeakReference JavaDoc cached;
91
92     /** Raster is reused whenever possible */
93     protected WritableRaster JavaDoc saved;
94
95     /** The method to use when painting out of the gradient bounds. */
96     protected MultipleGradientPaint.CycleMethodEnum cycleMethod;
97
98     /** The colorSpace in which to perform the interpolation */
99     protected MultipleGradientPaint.ColorSpaceEnum colorSpace;
100
101     /** Elements of the inverse transform matrix. */
102     protected float a00, a01, a10, a11, a02, a12;
103
104     /** This boolean specifies wether we are in simple lookup mode, where an
105      * input value between 0 and 1 may be used to directly index into a single
106      * array of gradient colors. If this boolean value is false, then we have
107      * to use a 2-step process where we have to determine which gradient array
108      * we fall into, then determine the index into that array.
109      */

110     protected boolean isSimpleLookup = true;
111
112     /** This boolean indicates if the gradient appears to have sudden
113      * discontinuities in it, this may be because of multiple stops
114      * at the same location or use of the REPEATE mode.
115      */

116     protected boolean hasDiscontinuity = false;
117
118     /** Size of gradients array for scaling the 0-1 index when looking up
119      * colors the fast way. */

120     protected int fastGradientArraySize;
121
122     /**
123      * Array which contains the interpolated color values for each interval,
124      * used by calculateSingleArrayGradient(). It is protected for possible
125      * direct access by subclasses.
126      */

127     protected int[] gradient;
128
129     /** Array of gradient arrays, one array for each interval. Used by
130      * calculateMultipleArrayGradient().
131      */

132     protected int[][] gradients;
133
134     /** This holds the blend of all colors in the gradient.
135      * we use this at extreamly low resolutions to ensure we
136      * get a decent blend of the colors.
137      */

138     protected int gradientAverage;
139
140     /** This holds the color to use when we are off the bottom of the
141      * gradient */

142     protected int gradientUnderflow;
143
144     /** This holds the color to use when we are off the top of the
145      * gradient */

146     protected int gradientOverflow;
147
148     /** Length of the 2D slow lookup gradients array. */
149     protected int gradientsLength;
150
151     /** Normalized intervals array */
152     protected float[] normalizedIntervals;
153
154     /** fractions array */
155     protected float[] fractions;
156
157     /** Used to determine if gradient colors are all opaque */
158     private int transparencyTest;
159
160     /** Colorspace conversion lookup tables */
161     private static final int SRGBtoLinearRGB[] = new int[256];
162     private static final int LinearRGBtoSRGB[] = new int[256];
163
164     //build the tables
165
static{
166         for (int k = 0; k < 256; k++) {
167             SRGBtoLinearRGB[k] = convertSRGBtoLinearRGB(k);
168             LinearRGBtoSRGB[k] = convertLinearRGBtoSRGB(k);
169         }
170     }
171
172     /** Constant number of max colors between any 2 arbitrary colors.
173      * Used for creating and indexing gradients arrays.
174      */

175     protected static final int GRADIENT_SIZE = 256;
176     protected static final int GRADIENT_SIZE_INDEX = GRADIENT_SIZE -1;
177
178     /** Maximum length of the fast single-array. If the estimated array size
179      * is greater than this, switch over to the slow lookup method.
180      * No particular reason for choosing this number, but it seems to provide
181      * satisfactory performance for the common case (fast lookup).
182      */

183     private static final int MAX_GRADIENT_ARRAY_SIZE = 5000;
184
185    /** Constructor for superclass. Does some initialization, but leaves most
186     * of the heavy-duty math for calculateGradient(), so the subclass may do
187     * some other manipulation beforehand if necessary. This is not possible
188     * if this computation is done in the superclass constructor which always
189     * gets called first.
190     **/

191     public MultipleGradientPaintContext(ColorModel JavaDoc cm,
192                                         Rectangle JavaDoc deviceBounds,
193                                         Rectangle2D JavaDoc userBounds,
194                                         AffineTransform JavaDoc t,
195                                         RenderingHints JavaDoc hints,
196                                         float[] fractions,
197                                         Color JavaDoc[] colors,
198                                         MultipleGradientPaint.CycleMethodEnum
199                                         cycleMethod,
200                                         MultipleGradientPaint.ColorSpaceEnum
201                                         colorSpace)
202         throws NoninvertibleTransformException JavaDoc
203     {
204         //We have to deal with the cases where the 1st gradient stop is not
205
//equal to 0 and/or the last gradient stop is not equal to 1.
206
//In both cases, create a new point and replicate the previous
207
//extreme point's color.
208

209         boolean fixFirst = false;
210         boolean fixLast = false;
211         int len = fractions.length;
212
213         //if the first gradient stop is not equal to zero, fix this condition
214
if (fractions[0] != 0f) {
215             fixFirst = true;
216             len++;
217         }
218
219         //if the last gradient stop is not equal to one, fix this condition
220
if (fractions[fractions.length - 1] != 1f) {
221             fixLast = true;
222             len++;
223         }
224         
225         for (int i=0; i<fractions.length-1; i++)
226             if (fractions[i] == fractions[i+1])
227                 len--;
228
229         this.fractions = new float[len];
230         Color JavaDoc [] loColors = new Color JavaDoc[len-1];
231         Color JavaDoc [] hiColors = new Color JavaDoc[len-1];
232         normalizedIntervals = new float[len-1];
233
234         gradientUnderflow = colors[0].getRGB();
235         gradientOverflow = colors[colors.length-1].getRGB();
236
237         int idx = 0;
238         if (fixFirst) {
239             this.fractions[0] = 0;
240             loColors[0] = colors[0];
241             hiColors[0] = colors[0];
242             normalizedIntervals[0] = fractions[0];
243             idx++;
244         }
245
246         for (int i=0; i<fractions.length-1; i++) {
247             if (fractions[i] == fractions[i+1]) {
248                 // System.out.println("EQ Fracts");
249
if (!colors[i].equals(colors[i+1])) {
250                     hasDiscontinuity = true;
251                 }
252                 continue;
253             }
254             this.fractions[idx] = fractions[i];
255             loColors[idx] = colors[i];
256             hiColors[idx] = colors[i+1];
257             normalizedIntervals[idx] = fractions[i+1]-fractions[i];
258             idx++;
259         }
260             
261         this.fractions[idx] = fractions[fractions.length-1];
262
263         if (fixLast) {
264             loColors[idx] = hiColors[idx] = colors[colors.length-1];
265             normalizedIntervals[idx] = 1-fractions[fractions.length-1];
266             idx++;
267             this.fractions[idx] = 1;
268         }
269
270         // The inverse transform is needed to from device to user space.
271
// Get all the components of the inverse transform matrix.
272
AffineTransform JavaDoc tInv = t.createInverse();
273
274         double m[] = new double[6];
275         tInv.getMatrix(m);
276         a00 = (float)m[0];
277         a10 = (float)m[1];
278         a01 = (float)m[2];
279         a11 = (float)m[3];
280         a02 = (float)m[4];
281         a12 = (float)m[5];
282
283         //copy some flags
284
this.cycleMethod = cycleMethod;
285         this.colorSpace = colorSpace;
286
287         // Setup an example Model, we may refine it later.
288
if (cm.getColorSpace() == lrgbmodel_A.getColorSpace())
289             dataModel = lrgbmodel_A;
290         else if (cm.getColorSpace() == srgbmodel_A.getColorSpace())
291             dataModel = srgbmodel_A;
292         else
293             throw new IllegalArgumentException JavaDoc
294                 ("Unsupported ColorSpace for interpolation");
295
296         calculateGradientFractions(loColors, hiColors);
297
298         model = GraphicsUtil.coerceColorModel(dataModel,
299                                               cm.isAlphaPremultiplied());
300     }
301
302
303     /** This function is the meat of this class. It calculates an array of
304      * gradient colors based on an array of fractions and color values at those
305      * fractions.
306      */

307     protected final void calculateGradientFractions
308         (Color JavaDoc []loColors, Color JavaDoc []hiColors) {
309
310         //if interpolation should occur in Linear RGB space, convert the
311
//colors using the lookup table
312
if (colorSpace == LinearGradientPaint.LINEAR_RGB) {
313             for (int i = 0; i < loColors.length; i++) {
314                 loColors[i] =
315                     new Color JavaDoc(SRGBtoLinearRGB[loColors[i].getRed()],
316                               SRGBtoLinearRGB[loColors[i].getGreen()],
317                               SRGBtoLinearRGB[loColors[i].getBlue()],
318                               loColors[i].getAlpha());
319                 
320                 hiColors[i] =
321                     new Color JavaDoc(SRGBtoLinearRGB[hiColors[i].getRed()],
322                               SRGBtoLinearRGB[hiColors[i].getGreen()],
323                               SRGBtoLinearRGB[hiColors[i].getBlue()],
324                               hiColors[i].getAlpha());
325             }
326         }
327
328         //initialize to be fully opaque for ANDing with colors
329
transparencyTest = 0xff000000;
330         if (cycleMethod == MultipleGradientPaint.NO_CYCLE) {
331             // Include overflow and underflow colors in transparency
332
// test.
333
transparencyTest &= gradientUnderflow;
334             transparencyTest &= gradientOverflow;
335         }
336
337         //array of interpolation arrays
338
gradients = new int[fractions.length - 1][];
339         gradientsLength = gradients.length;
340
341         // Find smallest interval
342
int n = normalizedIntervals.length;
343
344         float Imin = 1;
345
346         for(int i = 0; i < n; i++) {
347             Imin = (Imin > normalizedIntervals[i]) ?
348                 normalizedIntervals[i] : Imin;
349         }
350
351         //estimate the size of the entire gradients array.
352
//This is to prevent a tiny interval from causing the size of array to
353
//explode. If the estimated size is too large, break to using
354
//seperate arrays for each interval, and using an indexing scheme at
355
//look-up time.
356
int estimatedSize = 0;
357
358         if (Imin == 0) {
359             estimatedSize = Integer.MAX_VALUE;
360             hasDiscontinuity = true;
361         } else {
362             for (int i = 0; i < normalizedIntervals.length; i++) {
363                 estimatedSize += (normalizedIntervals[i]/Imin) * GRADIENT_SIZE;
364             }
365         }
366
367
368         if (estimatedSize > MAX_GRADIENT_ARRAY_SIZE) {
369             //slow method
370
calculateMultipleArrayGradient(loColors, hiColors);
371             if ((cycleMethod == MultipleGradientPaint.REPEAT) &&
372                 (gradients[0][0] !=
373                  gradients[gradients.length-1][GRADIENT_SIZE_INDEX]))
374                 hasDiscontinuity = true;
375         } else {
376             //fast method
377
calculateSingleArrayGradient(loColors, hiColors, Imin);
378             if ((cycleMethod == MultipleGradientPaint.REPEAT) &&
379                 (gradient[0] != gradient[fastGradientArraySize]))
380                 hasDiscontinuity = true;
381         }
382
383         // Use the most 'economical' model (no alpha).
384
if((transparencyTest >>> 24) == 0xff) {
385             if (dataModel.getColorSpace() == lrgbmodel_NA.getColorSpace())
386                 dataModel = lrgbmodel_NA;
387             else if (dataModel.getColorSpace() == srgbmodel_NA.getColorSpace())
388                 dataModel = srgbmodel_NA;
389             model = dataModel;
390         }
391     }
392
393
394     /**
395      * FAST LOOKUP METHOD
396      *
397      * This method calculates the gradient color values and places them in a
398      * single int array, gradient[]. It does this by allocating space for
399      * each interval based on its size relative to the smallest interval in
400      * the array. The smallest interval is allocated 255 interpolated values
401      * (the maximum number of unique in-between colors in a 24 bit color
402      * system), and all other intervals are allocated
403      * size = (255 * the ratio of their size to the smallest interval).
404      *
405      * This scheme expedites a speedy retrieval because the colors are
406      * distributed along the array according to their user-specified
407      * distribution. All that is needed is a relative index from 0 to 1.
408      *
409      * The only problem with this method is that the possibility exists for
410      * the array size to balloon in the case where there is a
411      * disproportionately small gradient interval. In this case the other
412      * intervals will be allocated huge space, but much of that data is
413      * redundant. We thus need to use the space conserving scheme below.
414      *
415      * @param Imin the size of the smallest interval
416      *
417      */

418     private void calculateSingleArrayGradient
419         (Color JavaDoc [] loColors, Color JavaDoc [] hiColors, float Imin) {
420
421         //set the flag so we know later it is a non-simple lookup
422
isSimpleLookup = true;
423
424         int rgb1; //2 colors to interpolate
425
int rgb2;
426
427         int gradientsTot = 1; //the eventual size of the single array
428

429         // These are fixed point 8.16 (start with 0.5)
430
int aveA = 0x008000;
431         int aveR = 0x008000;
432         int aveG = 0x008000;
433         int aveB = 0x008000;
434
435         //for every interval (transition between 2 colors)
436
for(int i=0; i < gradients.length; i++){
437
438             //create an array whose size is based on the ratio to the
439
//smallest interval.
440
int nGradients = (int)((normalizedIntervals[i]/Imin)*255f);
441             gradientsTot += nGradients;
442             gradients[i] = new int[nGradients];
443
444             //the the 2 colors (keyframes) to interpolate between
445
rgb1 = loColors[i].getRGB();
446             rgb2 = hiColors[i].getRGB();
447
448             //fill this array with the colors in between rgb1 and rgb2
449
interpolate(rgb1, rgb2, gradients[i]);
450
451             // Calculate Average of two colors...
452
int argb = gradients[i][GRADIENT_SIZE/2];
453             float norm = normalizedIntervals[i];
454             aveA += (int)(((argb>> 8)&0xFF0000)*norm);
455             aveR += (int)(((argb )&0xFF0000)*norm);
456             aveG += (int)(((argb<< 8)&0xFF0000)*norm);
457             aveB += (int)(((argb<<16)&0xFF0000)*norm);
458
459             //if the colors are opaque, transparency should still be 0xff000000
460
transparencyTest &= rgb1;
461             transparencyTest &= rgb2;
462         }
463
464         gradientAverage = (((aveA & 0xFF0000)<< 8) |
465                            ((aveR & 0xFF0000) ) |
466                            ((aveG & 0xFF0000)>> 8) |
467                            ((aveB & 0xFF0000)>>16));
468
469         // Put all gradients in a single array
470
gradient = new int[gradientsTot];
471         int curOffset = 0;
472         for(int i = 0; i < gradients.length; i++){
473             System.arraycopy(gradients[i], 0, gradient,
474                              curOffset, gradients[i].length);
475             curOffset += gradients[i].length;
476         }
477         gradient[gradient.length-1] = hiColors[hiColors.length-1].getRGB();
478
479         //if interpolation occurred in Linear RGB space, convert the
480
//gradients back to SRGB using the lookup table
481
if (colorSpace == LinearGradientPaint.LINEAR_RGB) {
482             if (dataModel.getColorSpace() ==
483                 ColorSpace.getInstance(ColorSpace.CS_sRGB)) {
484                 for (int i = 0; i < gradient.length; i++) {
485                     gradient[i] =
486                         convertEntireColorLinearRGBtoSRGB(gradient[i]);
487                 }
488                 gradientAverage =
489                     convertEntireColorLinearRGBtoSRGB(gradientAverage);
490             }
491         } else {
492             if (dataModel.getColorSpace() ==
493                 ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) {
494                 for (int i = 0; i < gradient.length; i++) {
495                     gradient[i] =
496                         convertEntireColorSRGBtoLinearRGB(gradient[i]);
497                 }
498                 gradientAverage =
499                     convertEntireColorSRGBtoLinearRGB(gradientAverage);
500             }
501         }
502
503         fastGradientArraySize = gradient.length - 1;
504     }
505
506
507     /**
508      * SLOW LOOKUP METHOD
509      *
510      * This method calculates the gradient color values for each interval and
511      * places each into its own 255 size array. The arrays are stored in
512      * gradients[][]. (255 is used because this is the maximum number of
513      * unique colors between 2 arbitrary colors in a 24 bit color system)
514      *
515      * This method uses the minimum amount of space (only 255 * number of
516      * intervals), but it aggravates the lookup procedure, because now we
517      * have to find out which interval to select, then calculate the index
518      * within that interval. This causes a significant performance hit,
519      * because it requires this calculation be done for every point in
520      * the rendering loop.
521      *
522      * For those of you who are interested, this is a classic example of the
523      * time-space tradeoff.
524      *
525      */

526     private void calculateMultipleArrayGradient
527         (Color JavaDoc [] loColors, Color JavaDoc [] hiColors) {
528
529         //set the flag so we know later it is a non-simple lookup
530
isSimpleLookup = false;
531
532         int rgb1; //2 colors to interpolate
533
int rgb2;
534
535         // These are fixed point 8.16 (start with 0.5)
536
int aveA = 0x008000;
537         int aveR = 0x008000;
538         int aveG = 0x008000;
539         int aveB = 0x008000;
540
541         //for every interval (transition between 2 colors)
542
for(int i=0; i < gradients.length; i++){
543
544             // This interval will never actually be used (zero size)
545
if (normalizedIntervals[i] == 0)
546                 continue;
547
548             //create an array of the maximum theoretical size for each interval
549
gradients[i] = new int[GRADIENT_SIZE];
550
551             //get the the 2 colors
552
rgb1 = loColors[i].getRGB();
553             rgb2 = hiColors[i].getRGB();
554
555             //fill this array with the colors in between rgb1 and rgb2
556
interpolate(rgb1, rgb2, gradients[i]);
557
558             // Calculate Average of two colors...
559
int argb = gradients[i][GRADIENT_SIZE/2];
560             float norm = normalizedIntervals[i];
561             aveA += (int)(((argb>> 8)&0xFF0000)*norm);
562             aveR += (int)(((argb )&0xFF0000)*norm);
563             aveG += (int)(((argb<< 8)&0xFF0000)*norm);
564             aveB += (int)(((argb<<16)&0xFF0000)*norm);
565
566             //if the colors are opaque, transparency should still be 0xff000000
567
transparencyTest &= rgb1;
568             transparencyTest &= rgb2;
569         }
570
571         gradientAverage = (((aveA & 0xFF0000)<< 8) |
572                            ((aveR & 0xFF0000) ) |
573                            ((aveG & 0xFF0000)>> 8) |
574                            ((aveB & 0xFF0000)>>16));
575
576         //if interpolation occurred in Linear RGB space, convert the
577
//gradients back to SRGB using the lookup table
578
if (colorSpace == LinearGradientPaint.LINEAR_RGB) {
579             if (dataModel.getColorSpace() ==
580                 ColorSpace.getInstance(ColorSpace.CS_sRGB)) {
581                 for (int j = 0; j < gradients.length; j++) {
582                     for (int i = 0; i < gradients[j].length; i++) {
583                         gradients[j][i] =
584                             convertEntireColorLinearRGBtoSRGB(gradients[j][i]);
585                     }
586                 }
587                 gradientAverage =
588                     convertEntireColorLinearRGBtoSRGB(gradientAverage);
589             }
590         } else {
591             if (dataModel.getColorSpace() ==
592                 ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) {
593                 for (int j = 0; j < gradients.length; j++) {
594                     for (int i = 0; i < gradients[j].length; i++) {
595                         gradients[j][i] =
596                             convertEntireColorSRGBtoLinearRGB(gradients[j][i]);
597                     }
598                 }
599                 gradientAverage =
600                     convertEntireColorSRGBtoLinearRGB(gradientAverage);
601             }
602         }
603     }
604
605     /** Yet another helper function. This one linearly interpolates between
606      * 2 colors, filling up the output array.
607      *
608      * @param rgb1 the start color
609      * @param rgb2 the end color
610      * @param output the output array of colors... assuming this is not null.
611      *
612      */

613     private void interpolate(int rgb1, int rgb2, int[] output) {
614
615         int a1, r1, g1, b1, da, dr, dg, db; //color components
616

617         //step between interpolated values.
618
float stepSize = 1/(float)output.length;
619
620         //extract color components from packed integer
621
a1 = (rgb1 >> 24) & 0xff;
622         r1 = (rgb1 >> 16) & 0xff;
623         g1 = (rgb1 >> 8) & 0xff;
624         b1 = (rgb1 ) & 0xff;
625         //calculate the total change in alpha, red, green, blue
626
da = ((rgb2 >> 24) & 0xff) - a1;
627         dr = ((rgb2 >> 16) & 0xff) - r1;
628         dg = ((rgb2 >> 8) & 0xff) - g1;
629         db = ((rgb2 ) & 0xff) - b1;
630
631         //for each step in the interval calculate the in-between color by
632
//multiplying the normalized current position by the total color change
633
//(.5 is added to prevent truncation round-off error)
634
for (int i = 0; i < output.length; i++) {
635             output[i] =
636                 (((int) ((a1 + i * da * stepSize) + .5) << 24)) |
637                 (((int) ((r1 + i * dr * stepSize) + .5) << 16)) |
638                 (((int) ((g1 + i * dg * stepSize) + .5) << 8)) |
639                 (((int) ((b1 + i * db * stepSize) + .5) ));
640         }
641     }
642
643
644     /** Yet another helper function. This one extracts the color components
645      * of an integer RGB triple, converts them from LinearRGB to SRGB, then
646      * recompacts them into an int.
647      */

648     private int convertEntireColorLinearRGBtoSRGB(int rgb) {
649
650         int a1, r1, g1, b1; //color components
651

652         //extract red, green, blue components
653
a1 = (rgb >> 24) & 0xff;
654         r1 = (rgb >> 16) & 0xff;
655         g1 = (rgb >> 8) & 0xff;
656         b1 = rgb & 0xff;
657
658         //use the lookup table
659
r1 = LinearRGBtoSRGB[r1];
660         g1 = LinearRGBtoSRGB[g1];
661         b1 = LinearRGBtoSRGB[b1];
662
663         //re-compact the components
664
return ((a1 << 24) |
665                 (r1 << 16) |
666                 (g1 << 8) |
667                 b1);
668     }
669
670     /** Yet another helper function. This one extracts the color components
671      * of an integer RGB triple, converts them from LinearRGB to SRGB, then
672      * recompacts them into an int.
673      */

674     private int convertEntireColorSRGBtoLinearRGB(int rgb) {
675
676         int a1, r1, g1, b1; //color components
677

678         //extract red, green, blue components
679
a1 = (rgb >> 24) & 0xff;
680         r1 = (rgb >> 16) & 0xff;
681         g1 = (rgb >> 8) & 0xff;
682         b1 = rgb & 0xff;
683
684         //use the lookup table
685
r1 = SRGBtoLinearRGB[r1];
686         g1 = SRGBtoLinearRGB[g1];
687         b1 = SRGBtoLinearRGB[b1];
688
689         //re-compact the components
690
return ((a1 << 24) |
691                 (r1 << 16) |
692                 (g1 << 8) |
693                 b1);
694     }
695
696
697     /** Helper function to index into the gradients array. This is necessary
698      * because each interval has an array of colors with uniform size 255.
699      * However, the color intervals are not necessarily of uniform length, so
700      * a conversion is required.
701      *
702      * @param position the unmanipulated position. want to map this into the
703      * range 0 to 1
704      *
705      * @returns integer color to display
706      *
707      */

708     protected final int indexIntoGradientsArrays(float position) {
709
710         //first, manipulate position value depending on the cycle method.
711

712         if (cycleMethod == MultipleGradientPaint.NO_CYCLE) {
713
714             if (position >= 1) { //upper bound is 1
715
return gradientOverflow;
716             }
717
718             else if (position <= 0) { //lower bound is 0
719
return gradientUnderflow;
720             }
721         }
722
723         else if (cycleMethod == MultipleGradientPaint.REPEAT) {
724             //get the fractional part
725
//(modulo behavior discards integer component)
726
position = position - (int)position;
727
728             //position now be between -1 and 1
729

730             if (position < 0) {
731                 position = position + 1; //force it to be in the range 0-1
732
}
733
734             int w=0, c1=0, c2=0;
735             if (isSimpleLookup) {
736               position *= gradient.length;
737               int idx1 = (int)(position);
738               if (idx1+1 < gradient.length)
739                 return gradient[idx1];
740
741               w = (int)((position-idx1)*(1<<16));
742               c1 = gradient[idx1];
743               c2 = gradient[0];
744             } else {
745               //for all the gradient interval arrays
746
for (int i = 0; i < gradientsLength; i++) {
747
748                 if (position < fractions[i+1]) { //this is the array we want
749

750                   float delta = position - fractions[i];
751                   
752                   delta = ((delta / normalizedIntervals[i]) * GRADIENT_SIZE);
753                   //this is the interval we want.
754
int index = (int)delta;
755                   if ((index+1<gradients[i].length) ||
756                       (i+1 < gradientsLength))
757                     return gradients[i][index];
758
759                   w = (int)((delta-index)*(1<<16));
760                   c1 = gradients[i][index];
761                   c2 = gradients[0][0];
762                   break;
763                 }
764               }
765             }
766
767             return
768               (((( ( (c1>> 8) &0xFF0000)+
769                     ((((c2>>>24) )-((c1>>>24) ))*w))&0xFF0000)<< 8) |
770                
771                ((( ( (c1 ) &0xFF0000)+
772                     ((((c2>> 16)&0xFF)-((c1>> 16)&0xFF))*w))&0xFF0000) ) |
773                     
774                ((( ( (c1<< 8) &0xFF0000)+
775                     ((((c2>> 8)&0xFF)-((c1>> 8)&0xFF))*w))&0xFF0000)>> 8) |
776                
777                ((( ( (c1<< 16) &0xFF0000)+
778                     ((((c2 )&0xFF)-((c1 )&0xFF))*w))&0xFF0000)>>16));
779
780             // return c1 +
781
// ((( ((((c2>>>24) )-((c1>>>24) ))*w)&0xFF0000)<< 8) |
782
// (( ((((c2>> 16)&0xFF)-((c1>> 16)&0xFF))*w)&0xFF0000) ) |
783
// (( ((((c2>> 8)&0xFF)-((c1>> 8)&0xFF))*w)&0xFF0000)>> 8) |
784
// (( ((((c2 )&0xFF)-((c1 )&0xFF))*w)&0xFF0000)>>16));
785
}
786
787         else { //cycleMethod == MultipleGradientPaint.REFLECT
788

789             if (position < 0) {
790                 position = -position; //take absolute value
791
}
792
793             int part = (int)position; //take the integer part
794

795             position = position - part; //get the fractional part
796

797             if ((part & 0x00000001) == 1) { //if integer part is odd
798
position = 1 - position; //want the reflected color instead
799
}
800         }
801
802         //now, get the color based on this 0-1 position:
803

804         if (isSimpleLookup) { //easy to compute: just scale index by array size
805
return gradient[(int)(position * fastGradientArraySize)];
806         }
807
808         else { //more complicated computation, to save space
809

810             //for all the gradient interval arrays
811
for (int i = 0; i < gradientsLength; i++) {
812
813                 if (position < fractions[i+1]) { //this is the array we want
814

815                     float delta = position - fractions[i];
816
817                     //this is the interval we want.
818
int index = (int)((delta / normalizedIntervals[i])
819                                       * (GRADIENT_SIZE_INDEX));
820
821                     return gradients[i][index];
822                 }
823             }
824
825         }
826
827         return gradientOverflow;
828     }
829
830
831     /** Helper function to index into the gradients array. This is necessary
832      * because each interval has an array of colors with uniform size 255.
833      * However, the color intervals are not necessarily of uniform length, so
834      * a conversion is required. This version also does anti-aliasing by
835      * averaging the gradient over position+/-(sz/2).
836      *
837      * @param position the unmanipulated position. want to map this into the
838      * range 0 to 1
839      * @param sz the size in gradient space to average.
840      *
841      * @returns ARGB integer color to display
842      */

843     protected final int indexGradientAntiAlias(float position, float sz) {
844         //first, manipulate position value depending on the cycle method.
845
if (cycleMethod == MultipleGradientPaint.NO_CYCLE) {
846             if (DEBUG) System.out.println("NO_CYCLE");
847             float p1 = position-(sz/2);
848             float p2 = position+(sz/2);
849
850             if (p1 >= 1)
851                 return gradientOverflow;
852
853             if (p2 <= 0)
854                 return gradientUnderflow;
855
856             int interior;
857             float top_weight=0, bottom_weight=0, frac;
858             if (p2 >= 1) {
859                 top_weight = (p2-1)/sz;
860                 if (p1 <= 0) {
861                     bottom_weight = -p1/sz;
862                     frac=1;
863                     interior = gradientAverage;
864                 } else {
865                     frac=1-p1;
866                     interior = getAntiAlias(p1, true, 1, false, 1-p1, 1);
867                 }
868             } else if (p1 <= 0) {
869                 bottom_weight = -p1/sz;
870                 frac = p2;
871                 interior = getAntiAlias(0, true, p2, false, p2, 1);
872             } else
873                 return getAntiAlias(p1, true, p2, false, sz, 1);
874             
875             int norm = (int)((1<<16)*frac/sz);
876             int pA = (((interior>>>20)&0xFF0)*norm)>>16;
877             int pR = (((interior>> 12)&0xFF0)*norm)>>16;
878             int pG = (((interior>> 4)&0xFF0)*norm)>>16;
879             int pB = (((interior<< 4)&0xFF0)*norm)>>16;
880
881             if (bottom_weight != 0) {
882                 int bPix = gradientUnderflow;
883                 // System.out.println("ave: " + gradientAverage);
884
norm = (int)((1<<16)*bottom_weight);
885                 pA += (((bPix>>>20) & 0xFF0)*norm)>>16;
886                 pR += (((bPix>> 12) & 0xFF0)*norm)>>16;
887                 pG += (((bPix>> 4) & 0xFF0)*norm)>>16;
888                 pB += (((bPix<< 4) & 0xFF0)*norm)>>16;
889             }
890
891             if (top_weight != 0) {
892                 int tPix = gradientOverflow;
893
894                 norm = (int)((1<<16)*top_weight);
895                 pA += (((tPix>>>20) & 0xFF0)*norm)>>16;
896                 pR += (((tPix>> 12) & 0xFF0)*norm)>>16;
897                 pG += (((tPix>> 4) & 0xFF0)*norm)>>16;
898                 pB += (((tPix<< 4) & 0xFF0)*norm)>>16;
899             }
900
901             return (((pA&0xFF0)<<20) |
902                     ((pR&0xFF0)<<12) |
903                     ((pG&0xFF0)<< 4) |
904                     ((pB&0xFF0)>> 4));
905         }
906
907         // See how many times we are going to "wrap around" the gradient,
908
// array.
909
int intSz = (int)sz;
910         
911         float weight = 1f;
912         if (intSz != 0) {
913             // We need to make sure that sz is < 1.0 otherwise
914
// p1 and p2 my pass each other which will cause no end of
915
// trouble.
916
sz -= intSz;
917             weight = sz/(intSz+sz);
918             if (weight < 0.1)
919                 // The part of the color from the location will be swamped
920
// by the averaged part of the gradient so just use the
921
// average color for the gradient.
922
return gradientAverage;
923         }
924             
925         // So close to full gradient just use the average value...
926
if (sz > 0.99)
927             return gradientAverage;
928             
929             // Go up and down from position by 1/2 sz.
930
float p1 = position-(sz/2);
931         float p2 = position+(sz/2);
932         if (DEBUG) System.out.println("P1: " + p1 + " P2: " + p2);
933
934         // These indicate the direction to go from p1 and p2 when
935
// averaging...
936
boolean p1_up=true;
937         boolean p2_up=false;
938
939         if (cycleMethod == MultipleGradientPaint.REPEAT) {
940             if (DEBUG) System.out.println("REPEAT");
941
942             // Get positions between -1 and 1
943
p1=p1-(int)p1;
944             p2=p2-(int)p2;
945
946             // force to be in rage 0-1.
947
if (p1 <0) p1 += 1;
948             if (p2 <0) p2 += 1;
949         }
950
951         else { //cycleMethod == MultipleGradientPaint.REFLECT
952
if (DEBUG) System.out.println("REFLECT");
953
954             //take absolute values
955
// Note when we reflect we change sense of p1/2_up.
956
if (p2 < 0) {
957                 p1 = -p1; p1_up = !p1_up;
958                 p2 = -p2; p2_up = !p2_up;
959             } else if (p1 < 0) {
960                 p1 = -p1; p1_up = !p1_up;
961             }
962
963             int part1, part2;
964             part1 = (int)p1; // take the integer part
965
p1 = p1 - part1; // get the fractional part
966

967             part2 = (int)p2; // take the integer part
968
p2 = p2 - part2; // get the fractional part
969

970             // if integer part is odd we want the reflected color instead.
971
// Note when we reflect we change sense of p1/2_up.
972
if ((part1 & 0x01) == 1) {
973                 p1 = 1-p1;
974                 p1_up = !p1_up;
975             }
976
977             if ((part2 & 0x01) == 1) {
978                 p2 = 1-p2;
979                 p2_up = !p2_up;
980             }
981
982             // Check if in the end they just got switched around.
983
// this commonly happens if they both end up negative.
984
if ((p1 > p2) && !p1_up && p2_up) {
985                 float t = p1;
986                 p1 = p2;
987                 p2 = t;
988                 p1_up = true;
989                 p2_up = false;
990             }
991         }
992
993         return getAntiAlias(p1, p1_up, p2, p2_up, sz, weight);
994     }
995
996
997     private final int getAntiAlias(float p1, boolean p1_up,
998                                    float p2, boolean p2_up,
999                                    float sz, float weight) {
1000
1001        // Until the last set of ops these are 28.4 fixed point values.
1002
int ach=0, rch=0, gch=0, bch=0;
1003        if (isSimpleLookup) {
1004            p1 *= fastGradientArraySize;
1005            p2 *= fastGradientArraySize;
1006
1007            int idx1 = (int)p1;
1008            int idx2 = (int)p2;
1009
1010            int i, pix;
1011
1012            if (p1_up && !p2_up && (idx1 <= idx2)) {
1013
1014                if (idx1 == idx2)
1015                    return gradient[idx1];
1016
1017                // Sum between idx1 and idx2.
1018
for (i=idx1+1; i<idx2; i++) {
1019                    pix = gradient[i];
1020                    ach += ((pix>>>20)&0xFF0);
1021                    rch += ((pix>>>12)&0xFF0);
1022                    gch += ((pix>>> 4)&0xFF0);
1023                    bch += ((pix<< 4)&0xFF0);
1024                }
1025            } else {
1026                // Do the bulk of the work, all the whole gradient entries
1027
// for idx1 and idx2.
1028
if (p1_up) {
1029                    for (i=idx1+1; i<fastGradientArraySize; i++) {
1030                        pix = gradient[i];
1031                        ach += ((pix>>>20)&0xFF0);
1032                        rch += ((pix>>>12)&0xFF0);
1033                        gch += ((pix>>> 4)&0xFF0);
1034                        bch += ((pix<< 4)&0xFF0);
1035                    }
1036                } else {
1037                    for (i=0; i<idx1; i++) {
1038                        pix = gradient[i];
1039                        ach += ((pix>>>20)&0xFF0);
1040                        rch += ((pix>>>12)&0xFF0);
1041                        gch += ((pix>>> 4)&0xFF0);
1042                        bch += ((pix<< 4)&0xFF0);
1043                    }
1044                }
1045
1046                if (p2_up) {
1047                    for (i=idx2+1; i<fastGradientArraySize; i++) {
1048                        pix = gradient[i];
1049                        ach += ((pix>>>20)&0xFF0);
1050                        rch += ((pix>>>12)&0xFF0);
1051                        gch += ((pix>>> 4)&0xFF0);
1052                        bch += ((pix<< 4)&0xFF0);
1053                    }
1054                } else {
1055                    for (i=0; i<idx2; i++) {
1056                        pix = gradient[i];
1057                        ach += ((pix>>>20)&0xFF0);
1058                        rch += ((pix>>>12)&0xFF0);
1059                        gch += ((pix>>> 4)&0xFF0);
1060                        bch += ((pix<< 4)&0xFF0);
1061                    }
1062                }
1063            }
1064
1065            int norm, isz;
1066
1067            // Normalize the summation so far...
1068
isz = (int)((1<<16)/(sz*fastGradientArraySize));
1069            ach = (ach*isz)>>16;
1070            rch = (rch*isz)>>16;
1071            gch = (gch*isz)>>16;
1072            bch = (bch*isz)>>16;
1073
1074            // Clean up with the partial buckets at each end.
1075
if (p1_up) norm = (int)((1-(p1-idx1))*isz);
1076            else norm = (int)( (p1-idx1) *isz);
1077            pix = gradient[idx1];
1078            ach += (((pix>>>20)&0xFF0) *norm)>>16;
1079            rch += (((pix>>>12)&0xFF0) *norm)>>16;
1080            gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1081            bch += (((pix<< 4)&0xFF0) *norm)>>16;
1082
1083            if (p2_up) norm = (int)((1-(p2-idx2))*isz);
1084            else norm = (int)( (p2-idx2) *isz);
1085            pix = gradient[idx2];
1086            ach += (((pix>>>20)&0xFF0) *norm)>>16;
1087            rch += (((pix>>>12)&0xFF0) *norm)>>16;
1088            gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1089            bch += (((pix<< 4)&0xFF0) *norm)>>16;
1090
1091            // Round and drop the 4bits frac.
1092
ach = (ach+0x08)>>4;
1093            rch = (rch+0x08)>>4;
1094            gch = (gch+0x08)>>4;
1095            bch = (bch+0x08)>>4;
1096
1097        } else {
1098            int idx1=0, idx2=0;
1099            int i1=-1, i2=-1;
1100            float f1=0, f2=0;
1101            // Find which gradient interval our points fall into.
1102
for (int i = 0; i < gradientsLength; i++) {
1103                if ((p1 < fractions[i+1]) && (i1 == -1)) {
1104                    //this is the array we want
1105
i1 = i;
1106                    f1 = p1 - fractions[i];
1107
1108                    f1 = ((f1/normalizedIntervals[i])
1109                             *GRADIENT_SIZE_INDEX);
1110                    //this is the interval we want.
1111
idx1 = (int)f1;
1112                    if (i2 != -1) break;
1113                }
1114                if ((p2 < fractions[i+1]) && (i2 == -1)) {
1115                    //this is the array we want
1116
i2 = i;
1117                    f2 = p2 - fractions[i];
1118                    
1119                    f2 = ((f2/normalizedIntervals[i])
1120                             *GRADIENT_SIZE_INDEX);
1121                    //this is the interval we want.
1122
idx2 = (int)f2;
1123                    if (i1 != -1) break;
1124                }
1125            }
1126
1127            if (i1 == -1) {
1128                i1 = gradients.length - 1;
1129                f1 = idx1 = GRADIENT_SIZE_INDEX;
1130            }
1131
1132            if (i2 == -1) {
1133                i2 = gradients.length - 1;
1134                f2 = idx2 = GRADIENT_SIZE_INDEX;
1135            }
1136
1137            if (DEBUG) System.out.println("I1: " + i1 + " Idx1: " + idx1 +
1138                                          " I2: " + i2 + " Idx2: " + idx2);
1139
1140            // Simple case within one gradient array (so the average
1141
// of the two idx gives us the true average of colors).
1142
if ((i1 == i2) && (idx1 <= idx2) && p1_up && !p2_up)
1143                return gradients[i1][(idx1+idx2+1)>>1];
1144
1145            // i1 != i2
1146

1147            int pix, norm;
1148            int base = (int)((1<<16)/sz);
1149            if ((i1 < i2) && p1_up && !p2_up) {
1150                norm = (int)((base
1151                              *normalizedIntervals[i1]
1152                              *(GRADIENT_SIZE_INDEX-f1))
1153                             /GRADIENT_SIZE_INDEX);
1154                pix = gradients[i1][(idx1+GRADIENT_SIZE)>>1];
1155                ach += (((pix>>>20)&0xFF0) *norm)>>16;
1156                rch += (((pix>>>12)&0xFF0) *norm)>>16;
1157                gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1158                bch += (((pix<< 4)&0xFF0) *norm)>>16;
1159
1160                for (int i=i1+1; i<i2; i++) {
1161                    norm = (int)(base*normalizedIntervals[i]);
1162                    pix = gradients[i][GRADIENT_SIZE>>1];
1163                  
1164                    ach += (((pix>>>20)&0xFF0) *norm)>>16;
1165                    rch += (((pix>>>12)&0xFF0) *norm)>>16;
1166                    gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1167                    bch += (((pix<< 4)&0xFF0) *norm)>>16;
1168                }
1169
1170                norm = (int)((base*normalizedIntervals[i2]*f2)
1171                             /GRADIENT_SIZE_INDEX);
1172                pix = gradients[i2][(idx2+1)>>1];
1173                ach += (((pix>>>20)&0xFF0) *norm)>>16;
1174                rch += (((pix>>>12)&0xFF0) *norm)>>16;
1175                gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1176                bch += (((pix<< 4)&0xFF0) *norm)>>16;
1177            } else {
1178                if (p1_up) {
1179                    norm = (int)((base
1180                                  *normalizedIntervals[i1]
1181                                  *(GRADIENT_SIZE_INDEX-f1))
1182                                 /GRADIENT_SIZE_INDEX);
1183                    pix = gradients[i1][(idx1+GRADIENT_SIZE)>>1];
1184                } else {
1185                    norm = (int)((base*normalizedIntervals[i1]*f1)
1186                                 /GRADIENT_SIZE_INDEX);
1187                    pix = gradients[i1][(idx1+1)>>1];
1188                }
1189                ach += (((pix>>>20)&0xFF0) *norm)>>16;
1190                rch += (((pix>>>12)&0xFF0) *norm)>>16;
1191                gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1192                bch += (((pix<< 4)&0xFF0) *norm)>>16;
1193
1194                if (p2_up) {
1195                    norm = (int)((base
1196                                  *normalizedIntervals[i2]
1197                                  *(GRADIENT_SIZE_INDEX-f2))
1198                                 /GRADIENT_SIZE_INDEX);
1199                    pix = gradients[i2][(idx2+GRADIENT_SIZE)>>1];
1200                } else {
1201                    norm = (int)((base*normalizedIntervals[i2]*f2)
1202                                 /GRADIENT_SIZE_INDEX);
1203                    pix = gradients[i2][(idx2+1)>>1];
1204                }
1205                ach += (((pix>>>20)&0xFF0) *norm)>>16;
1206                rch += (((pix>>>12)&0xFF0) *norm)>>16;
1207                gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1208                bch += (((pix<< 4)&0xFF0) *norm)>>16;
1209
1210                if (p1_up) {
1211                    for (int i=i1+1; i<gradientsLength; i++) {
1212                        norm = (int)(base*normalizedIntervals[i]);
1213                        pix = gradients[i][GRADIENT_SIZE>>1];
1214
1215                        ach += (((pix>>>20)&0xFF0) *norm)>>16;
1216                        rch += (((pix>>>12)&0xFF0) *norm)>>16;
1217                        gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1218                        bch += (((pix<< 4)&0xFF0) *norm)>>16;
1219                    }
1220                } else {
1221                    for (int i=0; i<i1; i++) {
1222                        norm = (int)(base*normalizedIntervals[i]);
1223                        pix = gradients[i][GRADIENT_SIZE>>1];
1224                  
1225                        ach += (((pix>>>20)&0xFF0) *norm)>>16;
1226                        rch += (((pix>>>12)&0xFF0) *norm)>>16;
1227                        gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1228                        bch += (((pix<< 4)&0xFF0) *norm)>>16;
1229                    }
1230                }
1231
1232                if (p2_up) {
1233                    for (int i=i2+1; i<gradientsLength; i++) {
1234                        norm = (int)(base*normalizedIntervals[i]);
1235                        pix = gradients[i][GRADIENT_SIZE>>1];
1236
1237                        ach += (((pix>>>20)&0xFF0) *norm)>>16;
1238                        rch += (((pix>>>12)&0xFF0) *norm)>>16;
1239                        gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1240                        bch += (((pix<< 4)&0xFF0) *norm)>>16;
1241                    }
1242                } else {
1243                    for (int i=0; i<i2; i++) {
1244                        norm = (int)(base*normalizedIntervals[i]);
1245                        pix = gradients[i][GRADIENT_SIZE>>1];
1246
1247                        ach += (((pix>>>20)&0xFF0) *norm)>>16;
1248                        rch += (((pix>>>12)&0xFF0) *norm)>>16;
1249                        gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1250                        bch += (((pix<< 4)&0xFF0) *norm)>>16;
1251                    }
1252                }
1253
1254            }
1255            ach = (ach+0x08)>>4;
1256            rch = (rch+0x08)>>4;
1257            gch = (gch+0x08)>>4;
1258            bch = (bch+0x08)>>4;
1259            if (DEBUG) System.out.println("Pix: [" + ach + ", " + rch +
1260                                          ", " + gch + ", " + bch + "]");
1261        }
1262
1263        if (weight != 1) {
1264            // System.out.println("ave: " + gradientAverage);
1265
int aveW = (int)((1<<16)*(1-weight));
1266            int aveA = ((gradientAverage>>>24) & 0xFF)*aveW;
1267            int aveR = ((gradientAverage>> 16) & 0xFF)*aveW;
1268            int aveG = ((gradientAverage>> 8) & 0xFF)*aveW;
1269            int aveB = ((gradientAverage ) & 0xFF)*aveW;
1270
1271            int iw = (int)(weight*(1<<16));
1272            ach = ((ach*iw)+aveA)>>16;
1273            rch = ((rch*iw)+aveR)>>16;
1274            gch = ((gch*iw)+aveG)>>16;
1275            bch = ((bch*iw)+aveB)>>16;
1276        }
1277              
1278        return ((ach<<24) | (rch<<16) | (gch<<8) | bch);
1279    }
1280
1281
1282    /** Helper function to convert a color component in sRGB space to linear
1283     * RGB space. Used to build a static lookup table.
1284     */

1285    private static int convertSRGBtoLinearRGB(int color) {
1286
1287        float input, output;
1288
1289        input = color/255.0f;
1290        if (input <= 0.04045f) {
1291            output = input/12.92f;
1292        }
1293        else {
1294            output = (float) Math.pow((input + 0.055) / 1.055, 2.4);
1295        }
1296        int o = Math.round(output * 255.0f);
1297
1298        return o;
1299    }
1300
1301     /** Helper function to convert a color component in linear RGB space to
1302      * SRGB space. Used to build a static lookup table.
1303      */

1304    private static int convertLinearRGBtoSRGB(int color) {
1305
1306        float input, output;
1307
1308        input = color/255.0f;
1309
1310        if (input <= 0.0031308) {
1311            output = input * 12.92f;
1312        }
1313        else {
1314            output = (1.055f *
1315                ((float) Math.pow(input, (1.0 / 2.4)))) - 0.055f;
1316        }
1317
1318        int o = Math.round(output * 255.0f);
1319
1320        return o;
1321    }
1322
1323
1324    /** Superclass getRaster... */
1325    public final Raster JavaDoc getRaster(int x, int y, int w, int h) {
1326        if (w == 0 || h == 0) {
1327            return null;
1328        }
1329
1330        //
1331
// If working raster is big enough, reuse it. Otherwise,
1332
// build a large enough new one.
1333
//
1334
WritableRaster JavaDoc raster = saved;
1335        if (raster == null || raster.getWidth() < w || raster.getHeight() < h)
1336            {
1337                raster = getCachedRaster(dataModel, w, h);
1338                saved = raster;
1339            }
1340
1341        // Access raster internal int array. Because we use a DirectColorModel,
1342
// we know the DataBuffer is of type DataBufferInt and the SampleModel
1343
// is SinglePixelPackedSampleModel.
1344
// Adjust for initial offset in DataBuffer and also for the scanline
1345
// stride.
1346
//
1347
DataBufferInt JavaDoc rasterDB = (DataBufferInt JavaDoc)raster.getDataBuffer();
1348        int[] pixels = rasterDB.getBankData()[0];
1349        int off = rasterDB.getOffset();
1350        int scanlineStride = ((SinglePixelPackedSampleModel JavaDoc)
1351                              raster.getSampleModel()).getScanlineStride();
1352        int adjust = scanlineStride - w;
1353
1354        fillRaster(pixels, off, adjust, x, y, w, h); //delegate to subclass.
1355

1356        GraphicsUtil.coerceData(raster, dataModel,
1357                                model.isAlphaPremultiplied());
1358
1359
1360        return raster;
1361    }
1362
1363    /** Subclasses should implement this. */
1364    protected abstract void fillRaster(int pixels[], int off, int adjust,
1365                                       int x, int y, int w, int h);
1366
1367
1368    /** Took this cacheRaster code from GradientPaint. It appears to recycle
1369     * rasters for use by any other instance, as long as they are sufficiently
1370     * large.
1371     */

1372    protected final
1373    static synchronized WritableRaster JavaDoc getCachedRaster
1374        (ColorModel JavaDoc cm, int w, int h) {
1375        if (cm == cachedModel) {
1376            if (cached != null) {
1377                WritableRaster JavaDoc ras = (WritableRaster JavaDoc) cached.get();
1378                if (ras != null &&
1379                    ras.getWidth() >= w &&
1380                    ras.getHeight() >= h)
1381                    {
1382                        cached = null;
1383                        return ras;
1384                    }
1385            }
1386        }
1387        // Don't create rediculously small rasters...
1388
if (w<32) w=32;
1389        if (h<32) h=32;
1390        return cm.createCompatibleWritableRaster(w, h);
1391    }
1392
1393    /** Took this cacheRaster code from GradientPaint. It appears to recycle
1394     * rasters for use by any other instance, as long as they are sufficiently
1395     * large.
1396     */

1397    protected final
1398    static synchronized void putCachedRaster(ColorModel JavaDoc cm,
1399                                             WritableRaster JavaDoc ras) {
1400        if (cached != null) {
1401            WritableRaster JavaDoc cras = (WritableRaster JavaDoc) cached.get();
1402            if (cras != null) {
1403                int cw = cras.getWidth();
1404                int ch = cras.getHeight();
1405                int iw = ras.getWidth();
1406                int ih = ras.getHeight();
1407                if (cw >= iw && ch >= ih) {
1408                    return;
1409                }
1410                if (cw * ch >= iw * ih) {
1411                    return;
1412                }
1413            }
1414        }
1415        cachedModel = cm;
1416        cached = new WeakReference JavaDoc(ras);
1417    }
1418
1419    /**
1420     * Release the resources allocated for the operation.
1421     */

1422    public final void dispose() {
1423        if (saved != null) {
1424            putCachedRaster(model, saved);
1425            saved = null;
1426        }
1427    }
1428
1429    /**
1430     * Return the ColorModel of the output.
1431     */

1432    public final ColorModel JavaDoc getColorModel() {
1433        return model;
1434    }
1435}
1436
1437
Popular Tags