001/***************************************************************************** 002 * Copyright (C) The Apache Software Foundation. All rights reserved. * 003 * ------------------------------------------------------------------------- * 004 * This software is published under the terms of the Apache Software License * 005 * version 1.1, a copy of which has been included with this distribution in * 006 * the LICENSE file. * 007 *****************************************************************************/ 008 009package com.kitfox.svg.batik; 010 011import com.kitfox.svg.SVGConst; 012import java.awt.Color; 013import java.awt.PaintContext; 014import java.awt.Rectangle; 015import java.awt.RenderingHints; 016import java.awt.geom.AffineTransform; 017import java.awt.geom.NoninvertibleTransformException; 018import java.awt.geom.Point2D; 019import java.awt.geom.Rectangle2D; 020import java.awt.image.ColorModel; 021import java.util.logging.Level; 022import java.util.logging.Logger; 023 024/** 025 * The <code>LinearGradientPaint</code> class provides a way to fill 026 * a {@link java.awt.Shape} with a linear color gradient pattern. The user may 027 * specify 2 or more gradient colors, and this paint will provide an 028 * interpolation between each color. The user also specifies start and end 029 * points which define where in user space the color gradient should begin 030 * and end. 031 * <p> 032 * The user must provide an array of floats specifying how to distribute the 033 * colors along the gradient. These values should range from 0.0 to 1.0 and 034 * act like keyframes along the gradient (they mark where the gradient should 035 * be exactly a particular color). 036 * <p> 037 * For example: 038 * <br> 039 * <code> 040 * <p> 041 * Point2D start = new Point2D.Float(0, 0);<br> 042 * Point2D end = new Point2D.Float(100,100);<br> 043 * float[] dist = {0.0, 0.2, 1.0};<br> 044 * Color[] colors = {Color.red, Color.white, Color.blue};<br> 045 * LinearGradientPaint p = new LinearGradientPaint(start, end, dist, colors); 046 * </code> 047 *<p> 048 * This code will create a LinearGradientPaint which interpolates between 049 * red and white for the first 20% of the gradient and between white and blue 050 * for the remaining 80%. 051 * 052 * <p> In the event that the user does not set the first keyframe value equal 053 * to 0 and the last keyframe value equal to 1, keyframes will be created at 054 * these positions and the first and last colors will be replicated there. 055 * So, if a user specifies the following arrays to construct a gradient:<br> 056 * {Color.blue, Color.red}, {.3, .7}<br> 057 * this will be converted to a gradient with the following keyframes: 058 * {Color.blue, Color.blue, Color.red, Color.red}, {0, .3, .7, 1} 059 * 060 * <p> 061 * The user may also select what action the LinearGradientPaint should take 062 * when filling color outside the start and end points. If no cycle method is 063 * specified, NO_CYCLE will be chosen by default, so the endpoint colors 064 * will be used to fill the remaining area. 065 * 066 * <p> The following image demonstrates the options NO_CYCLE and REFLECT. 067 * 068 * <p> 069 * <img src = "cyclic.jpg"> 070 * 071 * <p> The colorSpace parameter allows the user to specify in which colorspace 072 * the interpolation should be performed, default sRGB or linearized RGB. 073 * 074 * 075 * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans 076 * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a> 077 * @version $Id: LinearGradientPaint.java,v 1.2 2004/09/27 09:27:27 kitfox Exp $ 078 * @see java.awt.Paint 079 * @see java.awt.Graphics2D#setPaint 080 * 081 */ 082 083public final class LinearGradientPaint extends MultipleGradientPaint { 084 085 /** Gradient start and end points. */ 086 private Point2D start, end; 087 088 /**<p> 089 * Constructs an <code>LinearGradientPaint</code> with the default 090 * NO_CYCLE repeating method and SRGB colorspace. 091 * 092 * @param startX the x coordinate of the gradient axis start point 093 * in user space 094 * 095 * @param startY the y coordinate of the gradient axis start point 096 * in user space 097 * 098 * @param endX the x coordinate of the gradient axis end point 099 * in user space 100 * 101 * @param endY the y coordinate of the gradient axis end point 102 * in user space 103 * 104 * @param fractions numbers ranging from 0.0 to 1.0 specifying the 105 * distribution of colors along the gradient 106 * 107 * @param colors array of colors corresponding to each fractional value 108 * 109 * 110 * @throws IllegalArgumentException if start and end points are the 111 * same points, or if fractions.length != colors.length, or if colors 112 * is less than 2 in size. 113 * 114 */ 115 public LinearGradientPaint(float startX, float startY, 116 float endX, float endY, 117 float[] fractions, Color[] colors) { 118 119 this(new Point2D.Float(startX, startY), 120 new Point2D.Float(endX, endY), 121 fractions, 122 colors, 123 NO_CYCLE, 124 SRGB); 125 } 126 127 /**<p> 128 * Constructs an <code>LinearGradientPaint</code> with default SRGB 129 * colorspace. 130 * 131 * @param startX the x coordinate of the gradient axis start point 132 * in user space 133 * 134 * @param startY the y coordinate of the gradient axis start point 135 * in user space 136 * 137 * @param endX the x coordinate of the gradient axis end point 138 * in user space 139 * 140 * @param endY the y coordinate of the gradient axis end point 141 * in user space 142 * 143 * @param fractions numbers ranging from 0.0 to 1.0 specifying the 144 * distribution of colors along the gradient 145 * 146 * @param colors array of colors corresponding to each fractional value 147 * 148 * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT 149 * 150 * @throws IllegalArgumentException if start and end points are the 151 * same points, or if fractions.length != colors.length, or if colors 152 * is less than 2 in size. 153 * 154 */ 155 public LinearGradientPaint(float startX, float startY, 156 float endX, float endY, 157 float[] fractions, Color[] colors, 158 CycleMethodEnum cycleMethod) { 159 this(new Point2D.Float(startX, startY), 160 new Point2D.Float(endX, endY), 161 fractions, 162 colors, 163 cycleMethod, 164 SRGB); 165 } 166 167 /**<p> 168 * Constructs a <code>LinearGradientPaint</code> with the default 169 * NO_CYCLE repeating method and SRGB colorspace. 170 * 171 * @param start the gradient axis start <code>Point</code> in user space 172 * 173 * @param end the gradient axis end <code>Point</code> in user space 174 * 175 * @param fractions numbers ranging from 0.0 to 1.0 specifying the 176 * distribution of colors along the gradient 177 * 178 * @param colors array of colors corresponding to each fractional value 179 * 180 * @throws NullPointerException if one of the points is null 181 * 182 * @throws IllegalArgumentException if start and end points are the 183 * same points, or if fractions.length != colors.length, or if colors 184 * is less than 2 in size. 185 * 186 */ 187 public LinearGradientPaint(Point2D start, Point2D end, float[] fractions, 188 Color[] colors) { 189 190 this(start, end, fractions, colors, NO_CYCLE, SRGB); 191 } 192 193 /**<p> 194 * Constructs a <code>LinearGradientPaint</code>. 195 * 196 * @param start the gradient axis start <code>Point</code> in user space 197 * 198 * @param end the gradient axis end <code>Point</code> in user space 199 * 200 * @param fractions numbers ranging from 0.0 to 1.0 specifying the 201 * distribution of colors along the gradient 202 * 203 * @param colors array of colors corresponding to each fractional value 204 * 205 * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT 206 * 207 * @param colorSpace which colorspace to use for interpolation, 208 * either SRGB or LINEAR_RGB 209 * 210 * @throws NullPointerException if one of the points is null 211 * 212 * @throws IllegalArgumentException if start and end points are the 213 * same points, or if fractions.length != colors.length, or if colors 214 * is less than 2 in size. 215 * 216 */ 217 public LinearGradientPaint(Point2D start, Point2D end, float[] fractions, 218 Color[] colors, 219 CycleMethodEnum cycleMethod, 220 ColorSpaceEnum colorSpace) { 221 222 this(start, end, fractions, colors, cycleMethod, colorSpace, 223 new AffineTransform()); 224 225 } 226 227 /**<p> 228 * Constructs a <code>LinearGradientPaint</code>. 229 * 230 * @param start the gradient axis start <code>Point</code> in user space 231 * 232 * @param end the gradient axis end <code>Point</code> in user space 233 * 234 * @param fractions numbers ranging from 0.0 to 1.0 specifying the 235 * distribution of colors along the gradient 236 * 237 * @param colors array of colors corresponding to each fractional value 238 * 239 * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT 240 * 241 * @param colorSpace which colorspace to use for interpolation, 242 * either SRGB or LINEAR_RGB 243 * 244 * @param gradientTransform transform to apply to the gradient 245 * 246 * @throws NullPointerException if one of the points is null, 247 * or gradientTransform is null 248 * 249 * @throws IllegalArgumentException if start and end points are the 250 * same points, or if fractions.length != colors.length, or if colors 251 * is less than 2 in size. 252 * 253 */ 254 public LinearGradientPaint(Point2D start, Point2D end, float[] fractions, 255 Color[] colors, 256 CycleMethodEnum cycleMethod, 257 ColorSpaceEnum colorSpace, 258 AffineTransform gradientTransform) { 259 super(fractions, colors, cycleMethod, colorSpace, gradientTransform); 260 261 // 262 // Check input parameters 263 // 264 if (start == null || end == null) { 265 throw new NullPointerException("Start and end points must be" + 266 "non-null"); 267 } 268 269 if (start.equals(end)) { 270 throw new IllegalArgumentException("Start point cannot equal" + 271 "endpoint"); 272 } 273 274 //copy the points... 275 this.start = (Point2D)start.clone(); 276 277 this.end = (Point2D)end.clone(); 278 279 } 280 281 /** 282 * Creates and returns a PaintContext used to generate the color pattern, 283 * for use by the internal rendering engine. 284 * 285 * @param cm {@link ColorModel} that receives 286 * the <code>Paint</code> data. This is used only as a hint. 287 * 288 * @param deviceBounds the device space bounding box of the 289 * graphics primitive being rendered 290 * 291 * @param userBounds the user space bounding box of the 292 * graphics primitive being rendered 293 * 294 * @param transform the {@link AffineTransform} from user 295 * space into device space 296 * 297 * @param hints the hints that the context object uses to choose 298 * between rendering alternatives 299 * 300 * @return the {@link PaintContext} that generates color patterns. 301 * 302 * @see PaintContext 303 */ 304 public PaintContext createContext(ColorModel cm, 305 Rectangle deviceBounds, 306 Rectangle2D userBounds, 307 AffineTransform transform, 308 RenderingHints hints) { 309 310 // Can't modify the transform passed in... 311 transform = new AffineTransform(transform); 312 //incorporate the gradient transform 313 transform.concatenate(gradientTransform); 314 315 try { 316 return new LinearGradientPaintContext(cm, 317 deviceBounds, 318 userBounds, 319 transform, 320 hints, 321 start, 322 end, 323 fractions, 324 this.getColors(), 325 cycleMethod, 326 colorSpace); 327 } 328 catch(NoninvertibleTransformException e) 329 { 330 Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, null, e); 331 throw new IllegalArgumentException("transform should be" + 332 "invertible"); 333 } 334 } 335 336 /** 337 * Returns a copy of the start point of the gradient axis 338 * @return a {@link Point2D} object that is a copy of the point 339 * that anchors the first color of this 340 * <code>LinearGradientPaint</code>. 341 */ 342 public Point2D getStartPoint() { 343 return new Point2D.Double(start.getX(), start.getY()); 344 } 345 346 /** Returns a copy of the end point of the gradient axis 347 * @return a {@link Point2D} object that is a copy of the point 348 * that anchors the last color of this 349 * <code>LinearGradientPaint</code>. 350 */ 351 public Point2D getEndPoint() { 352 return new Point2D.Double(end.getX(), end.getY()); 353 } 354 355} 356 357