source: josm/trunk/src/com/kitfox/svg/batik/MultipleGradientPaintContext.java@ 10746

Last change on this file since 10746 was 8084, checked in by bastiK, 10 years ago

add svn:eol-style=native for svgsalamander

  • Property svn:eol-style set to native
File size: 51.9 KB
Line 
1/*****************************************************************************
2 * Copyright (C) The Apache Software Foundation. All rights reserved. *
3 * ------------------------------------------------------------------------- *
4 * This software is published under the terms of the Apache Software License *
5 * version 1.1, a copy of which has been included with this distribution in *
6 * the LICENSE file. *
7 *****************************************************************************/
8
9package com.kitfox.svg.batik;
10
11import java.awt.Color;
12import java.awt.PaintContext;
13import java.awt.Rectangle;
14import java.awt.RenderingHints;
15import java.awt.color.ColorSpace;
16import java.awt.geom.AffineTransform;
17import java.awt.geom.NoninvertibleTransformException;
18import java.awt.geom.Rectangle2D;
19import java.awt.image.ColorModel;
20import java.awt.image.DataBuffer;
21import java.awt.image.DataBufferInt;
22import java.awt.image.DirectColorModel;
23import java.awt.image.Raster;
24import java.awt.image.SinglePixelPackedSampleModel;
25import java.awt.image.WritableRaster;
26import java.lang.ref.WeakReference;
27
28//import org.apache.batik.ext.awt.image.GraphicsUtil;
29
30/** This is the superclass for all PaintContexts which use a multiple color
31 * gradient to fill in their raster. It provides the actual color interpolation
32 * functionality. Subclasses only have to deal with using the gradient to fill
33 * pixels in a raster.
34 *
35 * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
36 * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
37 * @version $Id: MultipleGradientPaintContext.java,v 1.1 2004/09/06 19:35:39 kitfox Exp $
38 *
39 */
40abstract class MultipleGradientPaintContext implements PaintContext {
41
42 protected final static boolean DEBUG = false;
43
44 /**
45 * The color model data is generated in (always un premult).
46 */
47 protected ColorModel dataModel;
48 /**
49 * PaintContext's output ColorModel ARGB if colors are not all
50 * opaque, RGB otherwise. Linear and premult are matched to
51 * output ColorModel.
52 */
53 protected ColorModel model;
54
55 /** Color model used if gradient colors are all opaque */
56 private static ColorModel lrgbmodel_NA = new DirectColorModel
57 (ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB),
58 24, 0xff0000, 0xFF00, 0xFF, 0x0,
59 false, DataBuffer.TYPE_INT);
60
61 private static ColorModel srgbmodel_NA = new DirectColorModel
62 (ColorSpace.getInstance(ColorSpace.CS_sRGB),
63 24, 0xff0000, 0xFF00, 0xFF, 0x0,
64 false, DataBuffer.TYPE_INT);
65
66 /** Color model used if some gradient colors are transparent */
67 private static ColorModel lrgbmodel_A = new DirectColorModel
68 (ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB),
69 32, 0xff0000, 0xFF00, 0xFF, 0xFF000000,
70 false, DataBuffer.TYPE_INT);
71
72 private static ColorModel srgbmodel_A = new DirectColorModel
73 (ColorSpace.getInstance(ColorSpace.CS_sRGB),
74 32, 0xff0000, 0xFF00, 0xFF, 0xFF000000,
75 false, DataBuffer.TYPE_INT);
76
77 /** The cached colorModel */
78 protected static ColorModel cachedModel;
79
80 /** The cached raster, which is reusable among instances */
81 protected static WeakReference cached;
82
83 /** Raster is reused whenever possible */
84 protected WritableRaster saved;
85
86 /** The method to use when painting out of the gradient bounds. */
87 protected MultipleGradientPaint.CycleMethodEnum cycleMethod;
88
89 /** The colorSpace in which to perform the interpolation */
90 protected MultipleGradientPaint.ColorSpaceEnum colorSpace;
91
92 /** Elements of the inverse transform matrix. */
93 protected float a00, a01, a10, a11, a02, a12;
94
95 /** This boolean specifies wether we are in simple lookup mode, where an
96 * input value between 0 and 1 may be used to directly index into a single
97 * array of gradient colors. If this boolean value is false, then we have
98 * to use a 2-step process where we have to determine which gradient array
99 * we fall into, then determine the index into that array.
100 */
101 protected boolean isSimpleLookup = true;
102
103 /** This boolean indicates if the gradient appears to have sudden
104 * discontinuities in it, this may be because of multiple stops
105 * at the same location or use of the REPEATE mode.
106 */
107 protected boolean hasDiscontinuity = false;
108
109 /** Size of gradients array for scaling the 0-1 index when looking up
110 * colors the fast way. */
111 protected int fastGradientArraySize;
112
113 /**
114 * Array which contains the interpolated color values for each interval,
115 * used by calculateSingleArrayGradient(). It is protected for possible
116 * direct access by subclasses.
117 */
118 protected int[] gradient;
119
120 /** Array of gradient arrays, one array for each interval. Used by
121 * calculateMultipleArrayGradient().
122 */
123 protected int[][] gradients;
124
125 /** This holds the blend of all colors in the gradient.
126 * we use this at extreamly low resolutions to ensure we
127 * get a decent blend of the colors.
128 */
129 protected int gradientAverage;
130
131 /** This holds the color to use when we are off the bottom of the
132 * gradient */
133 protected int gradientUnderflow;
134
135 /** This holds the color to use when we are off the top of the
136 * gradient */
137 protected int gradientOverflow;
138
139 /** Length of the 2D slow lookup gradients array. */
140 protected int gradientsLength;
141
142 /** Normalized intervals array */
143 protected float[] normalizedIntervals;
144
145 /** fractions array */
146 protected float[] fractions;
147
148 /** Used to determine if gradient colors are all opaque */
149 private int transparencyTest;
150
151 /** Colorspace conversion lookup tables */
152 private static final int SRGBtoLinearRGB[] = new int[256];
153 private static final int LinearRGBtoSRGB[] = new int[256];
154
155 //build the tables
156 static{
157 for (int k = 0; k < 256; k++) {
158 SRGBtoLinearRGB[k] = convertSRGBtoLinearRGB(k);
159 LinearRGBtoSRGB[k] = convertLinearRGBtoSRGB(k);
160 }
161 }
162
163 /** Constant number of max colors between any 2 arbitrary colors.
164 * Used for creating and indexing gradients arrays.
165 */
166 protected static final int GRADIENT_SIZE = 256;
167 protected static final int GRADIENT_SIZE_INDEX = GRADIENT_SIZE -1;
168
169 /** Maximum length of the fast single-array. If the estimated array size
170 * is greater than this, switch over to the slow lookup method.
171 * No particular reason for choosing this number, but it seems to provide
172 * satisfactory performance for the common case (fast lookup).
173 */
174 private static final int MAX_GRADIENT_ARRAY_SIZE = 5000;
175
176 /** Constructor for superclass. Does some initialization, but leaves most
177 * of the heavy-duty math for calculateGradient(), so the subclass may do
178 * some other manipulation beforehand if necessary. This is not possible
179 * if this computation is done in the superclass constructor which always
180 * gets called first.
181 **/
182 public MultipleGradientPaintContext(ColorModel cm,
183 Rectangle deviceBounds,
184 Rectangle2D userBounds,
185 AffineTransform t,
186 RenderingHints hints,
187 float[] fractions,
188 Color[] colors,
189 MultipleGradientPaint.CycleMethodEnum
190 cycleMethod,
191 MultipleGradientPaint.ColorSpaceEnum
192 colorSpace)
193 throws NoninvertibleTransformException
194 {
195 //We have to deal with the cases where the 1st gradient stop is not
196 //equal to 0 and/or the last gradient stop is not equal to 1.
197 //In both cases, create a new point and replicate the previous
198 //extreme point's color.
199
200 boolean fixFirst = false;
201 boolean fixLast = false;
202 int len = fractions.length;
203
204 //if the first gradient stop is not equal to zero, fix this condition
205 if (fractions[0] != 0f) {
206 fixFirst = true;
207 len++;
208 }
209
210 //if the last gradient stop is not equal to one, fix this condition
211 if (fractions[fractions.length - 1] != 1f) {
212 fixLast = true;
213 len++;
214 }
215
216 for (int i=0; i<fractions.length-1; i++)
217 if (fractions[i] == fractions[i+1])
218 len--;
219
220 this.fractions = new float[len];
221 Color [] loColors = new Color[len-1];
222 Color [] hiColors = new Color[len-1];
223 normalizedIntervals = new float[len-1];
224
225 gradientUnderflow = colors[0].getRGB();
226 gradientOverflow = colors[colors.length-1].getRGB();
227
228 int idx = 0;
229 if (fixFirst) {
230 this.fractions[0] = 0;
231 loColors[0] = colors[0];
232 hiColors[0] = colors[0];
233 normalizedIntervals[0] = fractions[0];
234 idx++;
235 }
236
237 for (int i=0; i<fractions.length-1; i++) {
238 if (fractions[i] == fractions[i+1]) {
239 // System.out.println("EQ Fracts");
240 if (!colors[i].equals(colors[i+1])) {
241 hasDiscontinuity = true;
242 }
243 continue;
244 }
245 this.fractions[idx] = fractions[i];
246 loColors[idx] = colors[i];
247 hiColors[idx] = colors[i+1];
248 normalizedIntervals[idx] = fractions[i+1]-fractions[i];
249 idx++;
250 }
251
252 this.fractions[idx] = fractions[fractions.length-1];
253
254 if (fixLast) {
255 loColors[idx] = hiColors[idx] = colors[colors.length-1];
256 normalizedIntervals[idx] = 1-fractions[fractions.length-1];
257 idx++;
258 this.fractions[idx] = 1;
259 }
260
261 // The inverse transform is needed to from device to user space.
262 // Get all the components of the inverse transform matrix.
263 AffineTransform tInv = t.createInverse();
264
265 double m[] = new double[6];
266 tInv.getMatrix(m);
267 a00 = (float)m[0];
268 a10 = (float)m[1];
269 a01 = (float)m[2];
270 a11 = (float)m[3];
271 a02 = (float)m[4];
272 a12 = (float)m[5];
273
274 //copy some flags
275 this.cycleMethod = cycleMethod;
276 this.colorSpace = colorSpace;
277
278 // Setup an example Model, we may refine it later.
279 if (cm.getColorSpace() == lrgbmodel_A.getColorSpace())
280 dataModel = lrgbmodel_A;
281 else if (cm.getColorSpace() == srgbmodel_A.getColorSpace())
282 dataModel = srgbmodel_A;
283 else
284 throw new IllegalArgumentException
285 ("Unsupported ColorSpace for interpolation");
286
287 calculateGradientFractions(loColors, hiColors);
288
289 model = GraphicsUtil.coerceColorModel(dataModel,
290 cm.isAlphaPremultiplied());
291 }
292
293
294 /** This function is the meat of this class. It calculates an array of
295 * gradient colors based on an array of fractions and color values at those
296 * fractions.
297 */
298 protected final void calculateGradientFractions
299 (Color []loColors, Color []hiColors) {
300
301 //if interpolation should occur in Linear RGB space, convert the
302 //colors using the lookup table
303 if (colorSpace == LinearGradientPaint.LINEAR_RGB) {
304 for (int i = 0; i < loColors.length; i++) {
305 loColors[i] =
306 new Color(SRGBtoLinearRGB[loColors[i].getRed()],
307 SRGBtoLinearRGB[loColors[i].getGreen()],
308 SRGBtoLinearRGB[loColors[i].getBlue()],
309 loColors[i].getAlpha());
310
311 hiColors[i] =
312 new Color(SRGBtoLinearRGB[hiColors[i].getRed()],
313 SRGBtoLinearRGB[hiColors[i].getGreen()],
314 SRGBtoLinearRGB[hiColors[i].getBlue()],
315 hiColors[i].getAlpha());
316 }
317 }
318
319 //initialize to be fully opaque for ANDing with colors
320 transparencyTest = 0xff000000;
321
322 //array of interpolation arrays
323 gradients = new int[fractions.length - 1][];
324 gradientsLength = gradients.length;
325
326 // Find smallest interval
327 int n = normalizedIntervals.length;
328
329 float Imin = 1;
330
331 for(int i = 0; i < n; i++) {
332 Imin = (Imin > normalizedIntervals[i]) ?
333 normalizedIntervals[i] : Imin;
334 }
335
336 //estimate the size of the entire gradients array.
337 //This is to prevent a tiny interval from causing the size of array to
338 //explode. If the estimated size is too large, break to using
339 //seperate arrays for each interval, and using an indexing scheme at
340 //look-up time.
341 int estimatedSize = 0;
342
343 if (Imin == 0) {
344 estimatedSize = Integer.MAX_VALUE;
345 hasDiscontinuity = true;
346 } else {
347 for (int i = 0; i < normalizedIntervals.length; i++) {
348 estimatedSize += (normalizedIntervals[i]/Imin) * GRADIENT_SIZE;
349 }
350 }
351
352
353 if (estimatedSize > MAX_GRADIENT_ARRAY_SIZE) {
354 //slow method
355 calculateMultipleArrayGradient(loColors, hiColors);
356 if ((cycleMethod == MultipleGradientPaint.REPEAT) &&
357 (gradients[0][0] !=
358 gradients[gradients.length-1][GRADIENT_SIZE_INDEX]))
359 hasDiscontinuity = true;
360 } else {
361 //fast method
362 calculateSingleArrayGradient(loColors, hiColors, Imin);
363 if ((cycleMethod == MultipleGradientPaint.REPEAT) &&
364 (gradient[0] != gradient[fastGradientArraySize]))
365 hasDiscontinuity = true;
366 }
367
368 // Use the most 'economical' model (no alpha).
369 if((transparencyTest >>> 24) == 0xff) {
370 if (dataModel.getColorSpace() == lrgbmodel_NA.getColorSpace())
371 dataModel = lrgbmodel_NA;
372 else if (dataModel.getColorSpace() == srgbmodel_NA.getColorSpace())
373 dataModel = srgbmodel_NA;
374 model = dataModel;
375 }
376 }
377
378
379 /**
380 * FAST LOOKUP METHOD
381 *
382 * This method calculates the gradient color values and places them in a
383 * single int array, gradient[]. It does this by allocating space for
384 * each interval based on its size relative to the smallest interval in
385 * the array. The smallest interval is allocated 255 interpolated values
386 * (the maximum number of unique in-between colors in a 24 bit color
387 * system), and all other intervals are allocated
388 * size = (255 * the ratio of their size to the smallest interval).
389 *
390 * This scheme expedites a speedy retrieval because the colors are
391 * distributed along the array according to their user-specified
392 * distribution. All that is needed is a relative index from 0 to 1.
393 *
394 * The only problem with this method is that the possibility exists for
395 * the array size to balloon in the case where there is a
396 * disproportionately small gradient interval. In this case the other
397 * intervals will be allocated huge space, but much of that data is
398 * redundant. We thus need to use the space conserving scheme below.
399 *
400 * @param Imin the size of the smallest interval
401 *
402 */
403 private void calculateSingleArrayGradient
404 (Color [] loColors, Color [] hiColors, float Imin) {
405
406 //set the flag so we know later it is a non-simple lookup
407 isSimpleLookup = true;
408
409 int rgb1; //2 colors to interpolate
410 int rgb2;
411
412 int gradientsTot = 1; //the eventual size of the single array
413
414 // These are fixed point 8.16 (start with 0.5)
415 int aveA = 0x008000;
416 int aveR = 0x008000;
417 int aveG = 0x008000;
418 int aveB = 0x008000;
419
420 //for every interval (transition between 2 colors)
421 for(int i=0; i < gradients.length; i++){
422
423 //create an array whose size is based on the ratio to the
424 //smallest interval.
425 int nGradients = (int)((normalizedIntervals[i]/Imin)*255f);
426 gradientsTot += nGradients;
427 gradients[i] = new int[nGradients];
428
429 //the the 2 colors (keyframes) to interpolate between
430 rgb1 = loColors[i].getRGB();
431 rgb2 = hiColors[i].getRGB();
432
433 //fill this array with the colors in between rgb1 and rgb2
434 interpolate(rgb1, rgb2, gradients[i]);
435
436 // Calculate Average of two colors...
437 int argb = gradients[i][GRADIENT_SIZE/2];
438 float norm = normalizedIntervals[i];
439 aveA += (int)(((argb>> 8)&0xFF0000)*norm);
440 aveR += (int)(((argb )&0xFF0000)*norm);
441 aveG += (int)(((argb<< 8)&0xFF0000)*norm);
442 aveB += (int)(((argb<<16)&0xFF0000)*norm);
443
444 //if the colors are opaque, transparency should still be 0xff000000
445 transparencyTest &= rgb1;
446 transparencyTest &= rgb2;
447 }
448
449 gradientAverage = (((aveA & 0xFF0000)<< 8) |
450 ((aveR & 0xFF0000) ) |
451 ((aveG & 0xFF0000)>> 8) |
452 ((aveB & 0xFF0000)>>16));
453
454 // Put all gradients in a single array
455 gradient = new int[gradientsTot];
456 int curOffset = 0;
457 for(int i = 0; i < gradients.length; i++){
458 System.arraycopy(gradients[i], 0, gradient,
459 curOffset, gradients[i].length);
460 curOffset += gradients[i].length;
461 }
462 gradient[gradient.length-1] = hiColors[hiColors.length-1].getRGB();
463
464 //if interpolation occurred in Linear RGB space, convert the
465 //gradients back to SRGB using the lookup table
466 if (colorSpace == LinearGradientPaint.LINEAR_RGB) {
467 if (dataModel.getColorSpace() ==
468 ColorSpace.getInstance(ColorSpace.CS_sRGB)) {
469 for (int i = 0; i < gradient.length; i++) {
470 gradient[i] =
471 convertEntireColorLinearRGBtoSRGB(gradient[i]);
472 }
473 gradientAverage =
474 convertEntireColorLinearRGBtoSRGB(gradientAverage);
475 }
476 } else {
477 if (dataModel.getColorSpace() ==
478 ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) {
479 for (int i = 0; i < gradient.length; i++) {
480 gradient[i] =
481 convertEntireColorSRGBtoLinearRGB(gradient[i]);
482 }
483 gradientAverage =
484 convertEntireColorSRGBtoLinearRGB(gradientAverage);
485 }
486 }
487
488 fastGradientArraySize = gradient.length - 1;
489 }
490
491
492 /**
493 * SLOW LOOKUP METHOD
494 *
495 * This method calculates the gradient color values for each interval and
496 * places each into its own 255 size array. The arrays are stored in
497 * gradients[][]. (255 is used because this is the maximum number of
498 * unique colors between 2 arbitrary colors in a 24 bit color system)
499 *
500 * This method uses the minimum amount of space (only 255 * number of
501 * intervals), but it aggravates the lookup procedure, because now we
502 * have to find out which interval to select, then calculate the index
503 * within that interval. This causes a significant performance hit,
504 * because it requires this calculation be done for every point in
505 * the rendering loop.
506 *
507 * For those of you who are interested, this is a classic example of the
508 * time-space tradeoff.
509 *
510 */
511 private void calculateMultipleArrayGradient
512 (Color [] loColors, Color [] hiColors) {
513
514 //set the flag so we know later it is a non-simple lookup
515 isSimpleLookup = false;
516
517 int rgb1; //2 colors to interpolate
518 int rgb2;
519
520 // These are fixed point 8.16 (start with 0.5)
521 int aveA = 0x008000;
522 int aveR = 0x008000;
523 int aveG = 0x008000;
524 int aveB = 0x008000;
525
526 //for every interval (transition between 2 colors)
527 for(int i=0; i < gradients.length; i++){
528
529 // This interval will never actually be used (zero size)
530 if (normalizedIntervals[i] == 0)
531 continue;
532
533 //create an array of the maximum theoretical size for each interval
534 gradients[i] = new int[GRADIENT_SIZE];
535
536 //get the the 2 colors
537 rgb1 = loColors[i].getRGB();
538 rgb2 = hiColors[i].getRGB();
539
540 //fill this array with the colors in between rgb1 and rgb2
541 interpolate(rgb1, rgb2, gradients[i]);
542
543 // Calculate Average of two colors...
544 int argb = gradients[i][GRADIENT_SIZE/2];
545 float norm = normalizedIntervals[i];
546 aveA += (int)(((argb>> 8)&0xFF0000)*norm);
547 aveR += (int)(((argb )&0xFF0000)*norm);
548 aveG += (int)(((argb<< 8)&0xFF0000)*norm);
549 aveB += (int)(((argb<<16)&0xFF0000)*norm);
550
551 //if the colors are opaque, transparency should still be 0xff000000
552 transparencyTest &= rgb1;
553 transparencyTest &= rgb2;
554 }
555
556 gradientAverage = (((aveA & 0xFF0000)<< 8) |
557 ((aveR & 0xFF0000) ) |
558 ((aveG & 0xFF0000)>> 8) |
559 ((aveB & 0xFF0000)>>16));
560
561 //if interpolation occurred in Linear RGB space, convert the
562 //gradients back to SRGB using the lookup table
563 if (colorSpace == LinearGradientPaint.LINEAR_RGB) {
564 if (dataModel.getColorSpace() ==
565 ColorSpace.getInstance(ColorSpace.CS_sRGB)) {
566 for (int j = 0; j < gradients.length; j++) {
567 for (int i = 0; i < gradients[j].length; i++) {
568 gradients[j][i] =
569 convertEntireColorLinearRGBtoSRGB(gradients[j][i]);
570 }
571 }
572 gradientAverage =
573 convertEntireColorLinearRGBtoSRGB(gradientAverage);
574 }
575 } else {
576 if (dataModel.getColorSpace() ==
577 ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) {
578 for (int j = 0; j < gradients.length; j++) {
579 for (int i = 0; i < gradients[j].length; i++) {
580 gradients[j][i] =
581 convertEntireColorSRGBtoLinearRGB(gradients[j][i]);
582 }
583 }
584 gradientAverage =
585 convertEntireColorSRGBtoLinearRGB(gradientAverage);
586 }
587 }
588 }
589
590 /** Yet another helper function. This one linearly interpolates between
591 * 2 colors, filling up the output array.
592 *
593 * @param rgb1 the start color
594 * @param rgb2 the end color
595 * @param output the output array of colors... assuming this is not null.
596 *
597 */
598 private void interpolate(int rgb1, int rgb2, int[] output) {
599
600 int a1, r1, g1, b1, da, dr, dg, db; //color components
601
602 //step between interpolated values.
603 float stepSize = 1/(float)output.length;
604
605 //extract color components from packed integer
606 a1 = (rgb1 >> 24) & 0xff;
607 r1 = (rgb1 >> 16) & 0xff;
608 g1 = (rgb1 >> 8) & 0xff;
609 b1 = (rgb1 ) & 0xff;
610 //calculate the total change in alpha, red, green, blue
611 da = ((rgb2 >> 24) & 0xff) - a1;
612 dr = ((rgb2 >> 16) & 0xff) - r1;
613 dg = ((rgb2 >> 8) & 0xff) - g1;
614 db = ((rgb2 ) & 0xff) - b1;
615
616 //for each step in the interval calculate the in-between color by
617 //multiplying the normalized current position by the total color change
618 //(.5 is added to prevent truncation round-off error)
619 for (int i = 0; i < output.length; i++) {
620 output[i] =
621 (((int) ((a1 + i * da * stepSize) + .5) << 24)) |
622 (((int) ((r1 + i * dr * stepSize) + .5) << 16)) |
623 (((int) ((g1 + i * dg * stepSize) + .5) << 8)) |
624 (((int) ((b1 + i * db * stepSize) + .5) ));
625 }
626 }
627
628
629 /** Yet another helper function. This one extracts the color components
630 * of an integer RGB triple, converts them from LinearRGB to SRGB, then
631 * recompacts them into an int.
632 */
633 private int convertEntireColorLinearRGBtoSRGB(int rgb) {
634
635 int a1, r1, g1, b1; //color components
636
637 //extract red, green, blue components
638 a1 = (rgb >> 24) & 0xff;
639 r1 = (rgb >> 16) & 0xff;
640 g1 = (rgb >> 8) & 0xff;
641 b1 = rgb & 0xff;
642
643 //use the lookup table
644 r1 = LinearRGBtoSRGB[r1];
645 g1 = LinearRGBtoSRGB[g1];
646 b1 = LinearRGBtoSRGB[b1];
647
648 //re-compact the components
649 return ((a1 << 24) |
650 (r1 << 16) |
651 (g1 << 8) |
652 b1);
653 }
654
655 /** Yet another helper function. This one extracts the color components
656 * of an integer RGB triple, converts them from LinearRGB to SRGB, then
657 * recompacts them into an int.
658 */
659 private int convertEntireColorSRGBtoLinearRGB(int rgb) {
660
661 int a1, r1, g1, b1; //color components
662
663 //extract red, green, blue components
664 a1 = (rgb >> 24) & 0xff;
665 r1 = (rgb >> 16) & 0xff;
666 g1 = (rgb >> 8) & 0xff;
667 b1 = rgb & 0xff;
668
669 //use the lookup table
670 r1 = SRGBtoLinearRGB[r1];
671 g1 = SRGBtoLinearRGB[g1];
672 b1 = SRGBtoLinearRGB[b1];
673
674 //re-compact the components
675 return ((a1 << 24) |
676 (r1 << 16) |
677 (g1 << 8) |
678 b1);
679 }
680
681
682 /** Helper function to index into the gradients array. This is necessary
683 * because each interval has an array of colors with uniform size 255.
684 * However, the color intervals are not necessarily of uniform length, so
685 * a conversion is required.
686 *
687 * @param position the unmanipulated position. want to map this into the
688 * range 0 to 1
689 *
690 * @returns integer color to display
691 *
692 */
693 protected final int indexIntoGradientsArrays(float position) {
694
695 //first, manipulate position value depending on the cycle method.
696
697 if (cycleMethod == MultipleGradientPaint.NO_CYCLE) {
698
699 if (position >= 1) { //upper bound is 1
700 return gradientOverflow;
701 }
702
703 else if (position <= 0) { //lower bound is 0
704 return gradientUnderflow;
705 }
706 }
707
708 else if (cycleMethod == MultipleGradientPaint.REPEAT) {
709 //get the fractional part
710 //(modulo behavior discards integer component)
711 position = position - (int)position;
712
713 //position now be between -1 and 1
714
715 if (position < 0) {
716 position = position + 1; //force it to be in the range 0-1
717 }
718
719 int w=0, c1=0, c2=0;
720 if (isSimpleLookup) {
721 position *= gradient.length;
722 int idx1 = (int)(position);
723 if (idx1+1 < gradient.length)
724 return gradient[idx1];
725
726 w = (int)((position-idx1)*(1<<16));
727 c1 = gradient[idx1];
728 c2 = gradient[0];
729 } else {
730 //for all the gradient interval arrays
731 for (int i = 0; i < gradientsLength; i++) {
732
733 if (position < fractions[i+1]) { //this is the array we want
734
735 float delta = position - fractions[i];
736
737 delta = ((delta / normalizedIntervals[i]) * GRADIENT_SIZE);
738 //this is the interval we want.
739 int index = (int)delta;
740 if ((index+1<gradients[i].length) ||
741 (i+1 < gradientsLength))
742 return gradients[i][index];
743
744 w = (int)((delta-index)*(1<<16));
745 c1 = gradients[i][index];
746 c2 = gradients[0][0];
747 break;
748 }
749 }
750 }
751
752 return
753 (((( ( (c1>> 8) &0xFF0000)+
754 ((((c2>>>24) )-((c1>>>24) ))*w))&0xFF0000)<< 8) |
755
756 ((( ( (c1 ) &0xFF0000)+
757 ((((c2>> 16)&0xFF)-((c1>> 16)&0xFF))*w))&0xFF0000) ) |
758
759 ((( ( (c1<< 8) &0xFF0000)+
760 ((((c2>> 8)&0xFF)-((c1>> 8)&0xFF))*w))&0xFF0000)>> 8) |
761
762 ((( ( (c1<< 16) &0xFF0000)+
763 ((((c2 )&0xFF)-((c1 )&0xFF))*w))&0xFF0000)>>16));
764
765 // return c1 +
766 // ((( ((((c2>>>24) )-((c1>>>24) ))*w)&0xFF0000)<< 8) |
767 // (( ((((c2>> 16)&0xFF)-((c1>> 16)&0xFF))*w)&0xFF0000) ) |
768 // (( ((((c2>> 8)&0xFF)-((c1>> 8)&0xFF))*w)&0xFF0000)>> 8) |
769 // (( ((((c2 )&0xFF)-((c1 )&0xFF))*w)&0xFF0000)>>16));
770 }
771
772 else { //cycleMethod == MultipleGradientPaint.REFLECT
773
774 if (position < 0) {
775 position = -position; //take absolute value
776 }
777
778 int part = (int)position; //take the integer part
779
780 position = position - part; //get the fractional part
781
782 if ((part & 0x00000001) == 1) { //if integer part is odd
783 position = 1 - position; //want the reflected color instead
784 }
785 }
786
787 //now, get the color based on this 0-1 position:
788
789 if (isSimpleLookup) { //easy to compute: just scale index by array size
790 return gradient[(int)(position * fastGradientArraySize)];
791 }
792
793 else { //more complicated computation, to save space
794
795 //for all the gradient interval arrays
796 for (int i = 0; i < gradientsLength; i++) {
797
798 if (position < fractions[i+1]) { //this is the array we want
799
800 float delta = position - fractions[i];
801
802 //this is the interval we want.
803 int index = (int)((delta / normalizedIntervals[i])
804 * (GRADIENT_SIZE_INDEX));
805
806 return gradients[i][index];
807 }
808 }
809
810 }
811
812 return gradientOverflow;
813 }
814
815
816 /** Helper function to index into the gradients array. This is necessary
817 * because each interval has an array of colors with uniform size 255.
818 * However, the color intervals are not necessarily of uniform length, so
819 * a conversion is required. This version also does anti-aliasing by
820 * averaging the gradient over position+/-(sz/2).
821 *
822 * @param position the unmanipulated position. want to map this into the
823 * range 0 to 1
824 * @param sz the size in gradient space to average.
825 *
826 * @returns ARGB integer color to display
827 */
828 protected final int indexGradientAntiAlias(float position, float sz) {
829 //first, manipulate position value depending on the cycle method.
830 if (cycleMethod == MultipleGradientPaint.NO_CYCLE) {
831 if (DEBUG) System.out.println("NO_CYCLE");
832 float p1 = position-(sz/2);
833 float p2 = position+(sz/2);
834
835 if (p1 >= 1)
836 return gradientOverflow;
837
838 if (p2 <= 0)
839 return gradientUnderflow;
840
841 int interior;
842 float top_weight=0, bottom_weight=0, frac;
843 if (p2 >= 1) {
844 top_weight = (p2-1)/sz;
845 if (p1 <= 0) {
846 bottom_weight = -p1/sz;
847 frac=1;
848 interior = gradientAverage;
849 } else {
850 frac=1-p1;
851 interior = getAntiAlias(p1, true, 1, false, 1-p1, 1);
852 }
853 } else if (p1 <= 0) {
854 bottom_weight = -p1/sz;
855 frac = p2;
856 interior = getAntiAlias(0, true, p2, false, p2, 1);
857 } else
858 return getAntiAlias(p1, true, p2, false, sz, 1);
859
860 int norm = (int)((1<<16)*frac/sz);
861 int pA = (((interior>>>20)&0xFF0)*norm)>>16;
862 int pR = (((interior>> 12)&0xFF0)*norm)>>16;
863 int pG = (((interior>> 4)&0xFF0)*norm)>>16;
864 int pB = (((interior<< 4)&0xFF0)*norm)>>16;
865
866 if (bottom_weight != 0) {
867 int bPix = gradientUnderflow;
868 // System.out.println("ave: " + gradientAverage);
869 norm = (int)((1<<16)*bottom_weight);
870 pA += (((bPix>>>20) & 0xFF0)*norm)>>16;
871 pR += (((bPix>> 12) & 0xFF0)*norm)>>16;
872 pG += (((bPix>> 4) & 0xFF0)*norm)>>16;
873 pB += (((bPix<< 4) & 0xFF0)*norm)>>16;
874 }
875
876 if (top_weight != 0) {
877 int tPix = gradientOverflow;
878
879 norm = (int)((1<<16)*top_weight);
880 pA += (((tPix>>>20) & 0xFF0)*norm)>>16;
881 pR += (((tPix>> 12) & 0xFF0)*norm)>>16;
882 pG += (((tPix>> 4) & 0xFF0)*norm)>>16;
883 pB += (((tPix<< 4) & 0xFF0)*norm)>>16;
884 }
885
886 return (((pA&0xFF0)<<20) |
887 ((pR&0xFF0)<<12) |
888 ((pG&0xFF0)<< 4) |
889 ((pB&0xFF0)>> 4));
890 }
891
892 // See how many times we are going to "wrap around" the gradient,
893 // array.
894 int intSz = (int)sz;
895
896 float weight = 1f;
897 if (intSz != 0) {
898 // We need to make sure that sz is < 1.0 otherwise
899 // p1 and p2 my pass each other which will cause no end of
900 // trouble.
901 sz -= intSz;
902 weight = sz/(intSz+sz);
903 if (weight < 0.1)
904 // The part of the color from the location will be swamped
905 // by the averaged part of the gradient so just use the
906 // average color for the gradient.
907 return gradientAverage;
908 }
909
910 // So close to full gradient just use the average value...
911 if (sz > 0.99)
912 return gradientAverage;
913
914 // Go up and down from position by 1/2 sz.
915 float p1 = position-(sz/2);
916 float p2 = position+(sz/2);
917 if (DEBUG) System.out.println("P1: " + p1 + " P2: " + p2);
918
919 // These indicate the direction to go from p1 and p2 when
920 // averaging...
921 boolean p1_up=true;
922 boolean p2_up=false;
923
924 if (cycleMethod == MultipleGradientPaint.REPEAT) {
925 if (DEBUG) System.out.println("REPEAT");
926
927 // Get positions between -1 and 1
928 p1=p1-(int)p1;
929 p2=p2-(int)p2;
930
931 // force to be in rage 0-1.
932 if (p1 <0) p1 += 1;
933 if (p2 <0) p2 += 1;
934 }
935
936 else { //cycleMethod == MultipleGradientPaint.REFLECT
937 if (DEBUG) System.out.println("REFLECT");
938
939 //take absolute values
940 // Note when we reflect we change sense of p1/2_up.
941 if (p2 < 0) {
942 p1 = -p1; p1_up = !p1_up;
943 p2 = -p2; p2_up = !p2_up;
944 } else if (p1 < 0) {
945 p1 = -p1; p1_up = !p1_up;
946 }
947
948 int part1, part2;
949 part1 = (int)p1; // take the integer part
950 p1 = p1 - part1; // get the fractional part
951
952 part2 = (int)p2; // take the integer part
953 p2 = p2 - part2; // get the fractional part
954
955 // if integer part is odd we want the reflected color instead.
956 // Note when we reflect we change sense of p1/2_up.
957 if ((part1 & 0x01) == 1) {
958 p1 = 1-p1;
959 p1_up = !p1_up;
960 }
961
962 if ((part2 & 0x01) == 1) {
963 p2 = 1-p2;
964 p2_up = !p2_up;
965 }
966
967 // Check if in the end they just got switched around.
968 // this commonly happens if they both end up negative.
969 if ((p1 > p2) && !p1_up && p2_up) {
970 float t = p1;
971 p1 = p2;
972 p2 = t;
973 p1_up = true;
974 p2_up = false;
975 }
976 }
977
978 return getAntiAlias(p1, p1_up, p2, p2_up, sz, weight);
979 }
980
981
982 private final int getAntiAlias(float p1, boolean p1_up,
983 float p2, boolean p2_up,
984 float sz, float weight) {
985
986 // Until the last set of ops these are 28.4 fixed point values.
987 int ach=0, rch=0, gch=0, bch=0;
988 if (isSimpleLookup) {
989 p1 *= fastGradientArraySize;
990 p2 *= fastGradientArraySize;
991
992 int idx1 = (int)p1;
993 int idx2 = (int)p2;
994
995 int i, pix;
996
997 if (p1_up && !p2_up && (idx1 <= idx2)) {
998
999 if (idx1 == idx2)
1000 return gradient[idx1];
1001
1002 // Sum between idx1 and idx2.
1003 for (i=idx1+1; i<idx2; i++) {
1004 pix = gradient[i];
1005 ach += ((pix>>>20)&0xFF0);
1006 rch += ((pix>>>12)&0xFF0);
1007 gch += ((pix>>> 4)&0xFF0);
1008 bch += ((pix<< 4)&0xFF0);
1009 }
1010 } else {
1011 // Do the bulk of the work, all the whole gradient entries
1012 // for idx1 and idx2.
1013 if (p1_up) {
1014 for (i=idx1+1; i<fastGradientArraySize; i++) {
1015 pix = gradient[i];
1016 ach += ((pix>>>20)&0xFF0);
1017 rch += ((pix>>>12)&0xFF0);
1018 gch += ((pix>>> 4)&0xFF0);
1019 bch += ((pix<< 4)&0xFF0);
1020 }
1021 } else {
1022 for (i=0; i<idx1; i++) {
1023 pix = gradient[i];
1024 ach += ((pix>>>20)&0xFF0);
1025 rch += ((pix>>>12)&0xFF0);
1026 gch += ((pix>>> 4)&0xFF0);
1027 bch += ((pix<< 4)&0xFF0);
1028 }
1029 }
1030
1031 if (p2_up) {
1032 for (i=idx2+1; i<fastGradientArraySize; i++) {
1033 pix = gradient[i];
1034 ach += ((pix>>>20)&0xFF0);
1035 rch += ((pix>>>12)&0xFF0);
1036 gch += ((pix>>> 4)&0xFF0);
1037 bch += ((pix<< 4)&0xFF0);
1038 }
1039 } else {
1040 for (i=0; i<idx2; i++) {
1041 pix = gradient[i];
1042 ach += ((pix>>>20)&0xFF0);
1043 rch += ((pix>>>12)&0xFF0);
1044 gch += ((pix>>> 4)&0xFF0);
1045 bch += ((pix<< 4)&0xFF0);
1046 }
1047 }
1048 }
1049
1050 int norm, isz;
1051
1052 // Normalize the summation so far...
1053 isz = (int)((1<<16)/(sz*fastGradientArraySize));
1054 ach = (ach*isz)>>16;
1055 rch = (rch*isz)>>16;
1056 gch = (gch*isz)>>16;
1057 bch = (bch*isz)>>16;
1058
1059 // Clean up with the partial buckets at each end.
1060 if (p1_up) norm = (int)((1-(p1-idx1))*isz);
1061 else norm = (int)( (p1-idx1) *isz);
1062 pix = gradient[idx1];
1063 ach += (((pix>>>20)&0xFF0) *norm)>>16;
1064 rch += (((pix>>>12)&0xFF0) *norm)>>16;
1065 gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1066 bch += (((pix<< 4)&0xFF0) *norm)>>16;
1067
1068 if (p2_up) norm = (int)((1-(p2-idx2))*isz);
1069 else norm = (int)( (p2-idx2) *isz);
1070 pix = gradient[idx2];
1071 ach += (((pix>>>20)&0xFF0) *norm)>>16;
1072 rch += (((pix>>>12)&0xFF0) *norm)>>16;
1073 gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1074 bch += (((pix<< 4)&0xFF0) *norm)>>16;
1075
1076 // Round and drop the 4bits frac.
1077 ach = (ach+0x08)>>4;
1078 rch = (rch+0x08)>>4;
1079 gch = (gch+0x08)>>4;
1080 bch = (bch+0x08)>>4;
1081
1082 } else {
1083 int idx1=0, idx2=0;
1084 int i1=-1, i2=-1;
1085 float f1=0, f2=0;
1086 // Find which gradient interval our points fall into.
1087 for (int i = 0; i < gradientsLength; i++) {
1088 if ((p1 < fractions[i+1]) && (i1 == -1)) {
1089 //this is the array we want
1090 i1 = i;
1091 f1 = p1 - fractions[i];
1092
1093 f1 = ((f1/normalizedIntervals[i])
1094 *GRADIENT_SIZE_INDEX);
1095 //this is the interval we want.
1096 idx1 = (int)f1;
1097 if (i2 != -1) break;
1098 }
1099 if ((p2 < fractions[i+1]) && (i2 == -1)) {
1100 //this is the array we want
1101 i2 = i;
1102 f2 = p2 - fractions[i];
1103
1104 f2 = ((f2/normalizedIntervals[i])
1105 *GRADIENT_SIZE_INDEX);
1106 //this is the interval we want.
1107 idx2 = (int)f2;
1108 if (i1 != -1) break;
1109 }
1110 }
1111
1112 if (i1 == -1) {
1113 i1 = gradients.length - 1;
1114 f1 = idx1 = GRADIENT_SIZE_INDEX;
1115 }
1116
1117 if (i2 == -1) {
1118 i2 = gradients.length - 1;
1119 f2 = idx2 = GRADIENT_SIZE_INDEX;
1120 }
1121
1122 if (DEBUG) System.out.println("I1: " + i1 + " Idx1: " + idx1 +
1123 " I2: " + i2 + " Idx2: " + idx2);
1124
1125 // Simple case within one gradient array (so the average
1126 // of the two idx gives us the true average of colors).
1127 if ((i1 == i2) && (idx1 <= idx2) && p1_up && !p2_up)
1128 return gradients[i1][(idx1+idx2+1)>>1];
1129
1130 // i1 != i2
1131
1132 int pix, norm;
1133 int base = (int)((1<<16)/sz);
1134 if ((i1 < i2) && p1_up && !p2_up) {
1135 norm = (int)((base
1136 *normalizedIntervals[i1]
1137 *(GRADIENT_SIZE_INDEX-f1))
1138 /GRADIENT_SIZE_INDEX);
1139 pix = gradients[i1][(idx1+GRADIENT_SIZE)>>1];
1140 ach += (((pix>>>20)&0xFF0) *norm)>>16;
1141 rch += (((pix>>>12)&0xFF0) *norm)>>16;
1142 gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1143 bch += (((pix<< 4)&0xFF0) *norm)>>16;
1144
1145 for (int i=i1+1; i<i2; i++) {
1146 norm = (int)(base*normalizedIntervals[i]);
1147 pix = gradients[i][GRADIENT_SIZE>>1];
1148
1149 ach += (((pix>>>20)&0xFF0) *norm)>>16;
1150 rch += (((pix>>>12)&0xFF0) *norm)>>16;
1151 gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1152 bch += (((pix<< 4)&0xFF0) *norm)>>16;
1153 }
1154
1155 norm = (int)((base*normalizedIntervals[i2]*f2)
1156 /GRADIENT_SIZE_INDEX);
1157 pix = gradients[i2][(idx2+1)>>1];
1158 ach += (((pix>>>20)&0xFF0) *norm)>>16;
1159 rch += (((pix>>>12)&0xFF0) *norm)>>16;
1160 gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1161 bch += (((pix<< 4)&0xFF0) *norm)>>16;
1162 } else {
1163 if (p1_up) {
1164 norm = (int)((base
1165 *normalizedIntervals[i1]
1166 *(GRADIENT_SIZE_INDEX-f1))
1167 /GRADIENT_SIZE_INDEX);
1168 pix = gradients[i1][(idx1+GRADIENT_SIZE)>>1];
1169 } else {
1170 norm = (int)((base*normalizedIntervals[i1]*f1)
1171 /GRADIENT_SIZE_INDEX);
1172 pix = gradients[i1][(idx1+1)>>1];
1173 }
1174 ach += (((pix>>>20)&0xFF0) *norm)>>16;
1175 rch += (((pix>>>12)&0xFF0) *norm)>>16;
1176 gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1177 bch += (((pix<< 4)&0xFF0) *norm)>>16;
1178
1179 if (p2_up) {
1180 norm = (int)((base
1181 *normalizedIntervals[i2]
1182 *(GRADIENT_SIZE_INDEX-f2))
1183 /GRADIENT_SIZE_INDEX);
1184 pix = gradients[i2][(idx2+GRADIENT_SIZE)>>1];
1185 } else {
1186 norm = (int)((base*normalizedIntervals[i2]*f2)
1187 /GRADIENT_SIZE_INDEX);
1188 pix = gradients[i2][(idx2+1)>>1];
1189 }
1190 ach += (((pix>>>20)&0xFF0) *norm)>>16;
1191 rch += (((pix>>>12)&0xFF0) *norm)>>16;
1192 gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1193 bch += (((pix<< 4)&0xFF0) *norm)>>16;
1194
1195 if (p1_up) {
1196 for (int i=i1+1; i<gradientsLength; i++) {
1197 norm = (int)(base*normalizedIntervals[i]);
1198 pix = gradients[i][GRADIENT_SIZE>>1];
1199
1200 ach += (((pix>>>20)&0xFF0) *norm)>>16;
1201 rch += (((pix>>>12)&0xFF0) *norm)>>16;
1202 gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1203 bch += (((pix<< 4)&0xFF0) *norm)>>16;
1204 }
1205 } else {
1206 for (int i=0; i<i1; i++) {
1207 norm = (int)(base*normalizedIntervals[i]);
1208 pix = gradients[i][GRADIENT_SIZE>>1];
1209
1210 ach += (((pix>>>20)&0xFF0) *norm)>>16;
1211 rch += (((pix>>>12)&0xFF0) *norm)>>16;
1212 gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1213 bch += (((pix<< 4)&0xFF0) *norm)>>16;
1214 }
1215 }
1216
1217 if (p2_up) {
1218 for (int i=i2+1; i<gradientsLength; i++) {
1219 norm = (int)(base*normalizedIntervals[i]);
1220 pix = gradients[i][GRADIENT_SIZE>>1];
1221
1222 ach += (((pix>>>20)&0xFF0) *norm)>>16;
1223 rch += (((pix>>>12)&0xFF0) *norm)>>16;
1224 gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1225 bch += (((pix<< 4)&0xFF0) *norm)>>16;
1226 }
1227 } else {
1228 for (int i=0; i<i2; i++) {
1229 norm = (int)(base*normalizedIntervals[i]);
1230 pix = gradients[i][GRADIENT_SIZE>>1];
1231
1232 ach += (((pix>>>20)&0xFF0) *norm)>>16;
1233 rch += (((pix>>>12)&0xFF0) *norm)>>16;
1234 gch += (((pix>>> 4)&0xFF0) *norm)>>16;
1235 bch += (((pix<< 4)&0xFF0) *norm)>>16;
1236 }
1237 }
1238
1239 }
1240 ach = (ach+0x08)>>4;
1241 rch = (rch+0x08)>>4;
1242 gch = (gch+0x08)>>4;
1243 bch = (bch+0x08)>>4;
1244 if (DEBUG) System.out.println("Pix: [" + ach + ", " + rch +
1245 ", " + gch + ", " + bch + "]");
1246 }
1247
1248 if (weight != 1) {
1249 // System.out.println("ave: " + gradientAverage);
1250 int aveW = (int)((1<<16)*(1-weight));
1251 int aveA = ((gradientAverage>>>24) & 0xFF)*aveW;
1252 int aveR = ((gradientAverage>> 16) & 0xFF)*aveW;
1253 int aveG = ((gradientAverage>> 8) & 0xFF)*aveW;
1254 int aveB = ((gradientAverage ) & 0xFF)*aveW;
1255
1256 int iw = (int)(weight*(1<<16));
1257 ach = ((ach*iw)+aveA)>>16;
1258 rch = ((rch*iw)+aveR)>>16;
1259 gch = ((gch*iw)+aveG)>>16;
1260 bch = ((bch*iw)+aveB)>>16;
1261 }
1262
1263 return ((ach<<24) | (rch<<16) | (gch<<8) | bch);
1264 }
1265
1266
1267 /** Helper function to convert a color component in sRGB space to linear
1268 * RGB space. Used to build a static lookup table.
1269 */
1270 private static int convertSRGBtoLinearRGB(int color) {
1271
1272 float input, output;
1273
1274 input = ((float) color) / 255.0f;
1275 if (input <= 0.04045f) {
1276 output = input / 12.92f;
1277 }
1278 else {
1279 output = (float) Math.pow((input + 0.055) / 1.055, 2.4);
1280 }
1281 int o = Math.round(output * 255.0f);
1282
1283 return o;
1284 }
1285
1286 /** Helper function to convert a color component in linear RGB space to
1287 * SRGB space. Used to build a static lookup table.
1288 */
1289 private static int convertLinearRGBtoSRGB(int color) {
1290
1291 float input, output;
1292
1293 input = ((float) color) / 255.0f;
1294
1295 if (input <= 0.0031308) {
1296 output = input * 12.92f;
1297 }
1298 else {
1299 output = (1.055f *
1300 ((float) Math.pow(input, (1.0 / 2.4)))) - 0.055f;
1301 }
1302
1303 int o = Math.round(output * 255.0f);
1304
1305 return o;
1306 }
1307
1308
1309 /** Superclass getRaster... */
1310 public final Raster getRaster(int x, int y, int w, int h) {
1311 if (w == 0 || h == 0) {
1312 return null;
1313 }
1314
1315 //
1316 // If working raster is big enough, reuse it. Otherwise,
1317 // build a large enough new one.
1318 //
1319 WritableRaster raster = saved;
1320 if (raster == null || raster.getWidth() < w || raster.getHeight() < h)
1321 {
1322 raster = getCachedRaster(dataModel, w, h);
1323 saved = raster;
1324 }
1325
1326 // Access raster internal int array. Because we use a DirectColorModel,
1327 // we know the DataBuffer is of type DataBufferInt and the SampleModel
1328 // is SinglePixelPackedSampleModel.
1329 // Adjust for initial offset in DataBuffer and also for the scanline
1330 // stride.
1331 //
1332 DataBufferInt rasterDB = (DataBufferInt)raster.getDataBuffer();
1333 int[] pixels = rasterDB.getBankData()[0];
1334 int off = rasterDB.getOffset();
1335 int scanlineStride = ((SinglePixelPackedSampleModel)
1336 raster.getSampleModel()).getScanlineStride();
1337 int adjust = scanlineStride - w;
1338
1339 fillRaster(pixels, off, adjust, x, y, w, h); //delegate to subclass.
1340
1341 GraphicsUtil.coerceData(raster, dataModel,
1342 model.isAlphaPremultiplied());
1343
1344
1345 return raster;
1346 }
1347
1348 /** Subclasses should implement this. */
1349 protected abstract void fillRaster(int pixels[], int off, int adjust,
1350 int x, int y, int w, int h);
1351
1352
1353 /** Took this cacheRaster code from GradientPaint. It appears to recycle
1354 * rasters for use by any other instance, as long as they are sufficiently
1355 * large.
1356 */
1357 protected final
1358 static synchronized WritableRaster getCachedRaster
1359 (ColorModel cm, int w, int h) {
1360 if (cm == cachedModel) {
1361 if (cached != null) {
1362 WritableRaster ras = (WritableRaster) cached.get();
1363 if (ras != null &&
1364 ras.getWidth() >= w &&
1365 ras.getHeight() >= h)
1366 {
1367 cached = null;
1368 return ras;
1369 }
1370 }
1371 }
1372 // Don't create rediculously small rasters...
1373 if (w<32) w=32;
1374 if (h<32) h=32;
1375 return cm.createCompatibleWritableRaster(w, h);
1376 }
1377
1378 /** Took this cacheRaster code from GradientPaint. It appears to recycle
1379 * rasters for use by any other instance, as long as they are sufficiently
1380 * large.
1381 */
1382 protected final
1383 static synchronized void putCachedRaster(ColorModel cm,
1384 WritableRaster ras) {
1385 if (cached != null) {
1386 WritableRaster cras = (WritableRaster) cached.get();
1387 if (cras != null) {
1388 int cw = cras.getWidth();
1389 int ch = cras.getHeight();
1390 int iw = ras.getWidth();
1391 int ih = ras.getHeight();
1392 if (cw >= iw && ch >= ih) {
1393 return;
1394 }
1395 if (cw * ch >= iw * ih) {
1396 return;
1397 }
1398 }
1399 }
1400 cachedModel = cm;
1401 cached = new WeakReference(ras);
1402 }
1403
1404 /**
1405 * Release the resources allocated for the operation.
1406 */
1407 public final void dispose() {
1408 if (saved != null) {
1409 putCachedRaster(model, saved);
1410 saved = null;
1411 }
1412 }
1413
1414 /**
1415 * Return the ColorModel of the output.
1416 */
1417 public final ColorModel getColorModel() {
1418 return model;
1419 }
1420}
1421
Note: See TracBrowser for help on using the repository browser.