Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/arranger/jarl/trait/base/GradientColor.java


1   package com.arranger.jarl.trait.base;
2   
3   import com.jhlabs.image.Gradient;
4   import sun.awt.image.IntegerComponentRaster;
5   
6   import java.awt.*;
7   import java.awt.geom.AffineTransform;
8   import java.awt.geom.NoninvertibleTransformException;
9   import java.awt.geom.Point2D;
10  import java.awt.geom.Rectangle2D;
11  import java.awt.image.ColorModel;
12  import java.awt.image.Raster;
13  import java.lang.ref.WeakReference;
14  
15  /**
16   * GradientColor
17   * Note: This is heavily based on java.awt.GradientPaintContext & java.awt.GradientPaint
18   */
19  public class GradientColor implements Paint {
20  
21      protected Gradient m_gradient;
22  
23      public GradientColor(Gradient gradient) {
24          m_gradient = gradient;
25      }
26  
27      public PaintContext createContext(ColorModel cm,
28                                        Rectangle deviceBounds,
29                                        Rectangle2D userBounds,
30                                        AffineTransform xform,
31                                        RenderingHints hints) {
32  
33          Point2D point1 = new Point2D.Double(userBounds.getX(), userBounds.getY());
34          Point2D point2 = new Point2D.Double(userBounds.getX() + userBounds.getWidth(), userBounds.getY() + userBounds.getHeight());
35          return new GradientPaintContext(point1, point2, xform, m_gradient.getMap());
36      }
37  
38      public int getTransparency() {
39          return Transparency.OPAQUE;
40      }
41  
42      public Gradient getGradient() {
43          return m_gradient;
44      }
45  
46      static ColorModel cachedModel;
47      static WeakReference cached;
48  
49      static synchronized Raster getCachedRaster(ColorModel cm, int w, int h) {
50          if (cm == cachedModel) {
51              if (cached != null) {
52                  Raster ras = (Raster) cached.get();
53                  if (ras != null &&
54                          ras.getWidth() >= w &&
55                          ras.getHeight() >= h) {
56                      cached = null;
57                      return ras;
58                  }
59              }
60          }
61          return cm.createCompatibleWritableRaster(w, h);
62      }
63  
64      static synchronized void putCachedRaster(ColorModel cm, Raster ras) {
65          if (cached != null) {
66              Raster cras = (Raster) cached.get();
67              if (cras != null) {
68                  int cw = cras.getWidth();
69                  int ch = cras.getHeight();
70                  int iw = ras.getWidth();
71                  int ih = ras.getHeight();
72                  if (cw >= iw && ch >= ih) {
73                      return;
74                  }
75                  if (cw * ch >= iw * ih) {
76                      return;
77                  }
78              }
79          }
80          cachedModel = cm;
81          cached = new WeakReference(ras);
82      }
83  
84      protected static class GradientPaintContext implements PaintContext {
85  
86          double x1;
87          double y1;
88          double dx;
89          double dy;
90          int interp[];
91          Raster saved;
92          ColorModel model;
93  
94          public GradientPaintContext(Point2D p1, Point2D p2, AffineTransform xform,
95                                      int[] map) {
96              // First calculate the distance moved in user space when
97              // we move a single unit along the X & Y axes in device space.
98              Point2D xvec = new Point2D.Double(1, 0);
99              Point2D yvec = new Point2D.Double(0, 1);
100             try {
101                 AffineTransform inverse = xform.createInverse();
102                 inverse.deltaTransform(xvec, xvec);
103                 inverse.deltaTransform(yvec, yvec);
104             } catch (NoninvertibleTransformException e) {
105                 xvec.setLocation(0, 0);
106                 yvec.setLocation(0, 0);
107             }
108 
109             // Now calculate the (square of the) user space distance
110             // between the anchor points. This value equals:
111             //     (UserVec . UserVec)
112             double udx = p2.getX() - p1.getX();
113             double udy = p2.getY() - p1.getY();
114             double ulenSq = udx * udx + udy * udy;
115 
116             if (ulenSq <= Double.MIN_VALUE) {
117                 dx = 0;
118                 dy = 0;
119             } else {
120                 // Now calculate the proportional distance moved along the
121                 // vector from p1 to p2 when we move a unit along X & Y in
122                 // device space.
123                 //
124                 // The length of the projection of the Device Axis Vector is
125                 // its dot product with the Unit User Vector:
126                 //     (DevAxisVec . (UserVec / Len(UserVec))
127                 //
128                 // The "proportional" length is that length divided again
129                 // by the length of the User Vector:
130                 //     (DevAxisVec . (UserVec / Len(UserVec))) / Len(UserVec)
131                 // which simplifies to:
132                 //     ((DevAxisVec . UserVec) / Len(UserVec)) / Len(UserVec)
133                 // which simplifies to:
134                 //     (DevAxisVec . UserVec) / LenSquared(UserVec)
135                 dx = (xvec.getX() * udx + xvec.getY() * udy) / ulenSq;
136                 dy = (yvec.getX() * udx + yvec.getY() * udy) / ulenSq;
137 
138 
139                 // We are acyclic
140                 if (dx < 0) {
141                     // If we are using the acyclic form below, we need
142                     // dx to be non-negative for simplicity of scanning
143                     // across the scan lines for the transition points.
144                     // To ensure that constraint, we negate the dx/dy
145                     // values and swap the points and colors.
146                     Point2D p = p1;
147                     p1 = p2;
148                     p2 = p;
149                     dx = -dx;
150                     dy = -dy;
151                 }
152             }
153 
154             Point2D dp1 = xform.transform(p1, null);
155             this.x1 = dp1.getX();
156             this.y1 = dp1.getY();
157 
158             model = ColorModel.getRGBdefault();
159             interp = map;
160         }
161 
162         /**
163          * Release the resources allocated for the operation.
164          */
165         public void dispose() {
166             if (saved != null) {
167                 putCachedRaster(model, saved);
168                 saved = null;
169             }
170         }
171 
172         /**
173          * Return the ColorModel of the output.
174          */
175         public ColorModel getColorModel() {
176             return model;
177         }
178 
179         /**
180          * Return a Raster containing the colors generated for the graphics
181          * operation.
182          */
183         public Raster getRaster(int x, int y, int w, int h) {
184             double rowrel = (x - x1) * dx + (y - y1) * dy;
185 
186             Raster rast = saved;
187             if (rast == null || rast.getWidth() < w || rast.getHeight() < h) {
188                 rast = getCachedRaster(model, w, h);
189                 saved = rast;
190             }
191             IntegerComponentRaster irast = (IntegerComponentRaster) rast;
192             int off = irast.getDataOffset(0);
193             int adjust = irast.getScanlineStride() - w;
194             int[] pixels = irast.getDataStorage();
195 
196             clipFillRaster(pixels, off, adjust, w, h, rowrel, dx, dy);
197 
198             return rast;
199         }
200 
201         void cycleFillRaster(int[] pixels, int off, int adjust, int w, int h,
202                              double rowrel, double dx, double dy) {
203             rowrel = rowrel % 2.0;
204             int irowrel = ((int) (rowrel * (1 << 30))) << 1;
205             int idx = (int) (-dx * (1 << 31));
206             int idy = (int) (-dy * (1 << 31));
207             while (--h >= 0) {
208                 int icolrel = irowrel;
209                 for (int j = w; j > 0; j--) {
210                     pixels[off++] = interp[icolrel >>> 23];
211                     icolrel += idx;
212                 }
213 
214                 off += adjust;
215                 irowrel += idy;
216             }
217         }
218 
219         void clipFillRaster(int[] pixels, int off, int adjust, int w, int h,
220                             double rowrel, double dx, double dy) {
221             while (--h >= 0) {
222                 double colrel = rowrel;
223                 int j = w;
224                 if (colrel <= 0.0) {
225                     int rgb = interp[0];
226                     do {
227                         pixels[off++] = rgb;
228                         colrel += dx;
229                     } while (--j > 0 && colrel <= 0.0);
230                 }
231                 while (colrel < 1.0 && --j >= 0) {
232                     pixels[off++] = interp[(int) (colrel * (interp.length - 1))];
233                     colrel += dx;
234                 }
235                 if (j > 0) {
236                     int rgb = interp[(interp.length - 1)];
237                     do {
238                         pixels[off++] = rgb;
239                     } while (--j > 0);
240                 }
241 
242                 off += adjust;
243                 rowrel += dy;
244             }
245         }
246     };
247 }