| 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 |
|
|---|
| 9 | package com.kitfox.svg.batik;
|
|---|
| 10 |
|
|---|
| 11 | import java.awt.Color;
|
|---|
| 12 | import java.awt.PaintContext;
|
|---|
| 13 | import java.awt.Rectangle;
|
|---|
| 14 | import java.awt.RenderingHints;
|
|---|
| 15 | import java.awt.color.ColorSpace;
|
|---|
| 16 | import java.awt.geom.AffineTransform;
|
|---|
| 17 | import java.awt.geom.NoninvertibleTransformException;
|
|---|
| 18 | import java.awt.geom.Rectangle2D;
|
|---|
| 19 | import java.awt.image.ColorModel;
|
|---|
| 20 | import java.awt.image.DataBuffer;
|
|---|
| 21 | import java.awt.image.DataBufferInt;
|
|---|
| 22 | import java.awt.image.DirectColorModel;
|
|---|
| 23 | import java.awt.image.Raster;
|
|---|
| 24 | import java.awt.image.SinglePixelPackedSampleModel;
|
|---|
| 25 | import java.awt.image.WritableRaster;
|
|---|
| 26 | import 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 | */
|
|---|
| 40 | abstract 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 |
|
|---|