1 /*
2  * $RCSfile: ScaleCRIF.java,v $
3  *
4  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
5  *
6  * Use is subject to license terms.
7  *
8  * $Revision: 1.1 $
9  * $Date: 2005/02/11 04:56:42 $
10  * $State: Exp $
11  */
12 package com.lightcrafts.media.jai.opimage;
13 import java.awt.RenderingHints;
14 import java.awt.geom.AffineTransform;
15 import java.awt.geom.Rectangle2D;
16 import java.awt.image.DataBuffer;
17 import java.awt.image.MultiPixelPackedSampleModel;
18 import java.awt.image.RenderedImage;
19 import java.awt.image.SampleModel;
20 import java.awt.image.renderable.RenderContext;
21 import java.awt.image.renderable.ParameterBlock;
22 import java.awt.image.renderable.RenderableImage;
23 import com.lightcrafts.mediax.jai.BorderExtender;
24 import com.lightcrafts.mediax.jai.ImageLayout;
25 import com.lightcrafts.mediax.jai.Interpolation;
26 import com.lightcrafts.mediax.jai.InterpolationNearest;
27 import com.lightcrafts.mediax.jai.InterpolationBilinear;
28 import com.lightcrafts.mediax.jai.InterpolationBicubic;
29 import com.lightcrafts.mediax.jai.InterpolationBicubic2;
30 import com.lightcrafts.mediax.jai.TileCache;
31 import com.lightcrafts.mediax.jai.CRIFImpl;
32 
33 
34 /**
35  * @see ScaleOpImage
36  */
37 public class ScaleCRIF extends CRIFImpl {
38 
39     private static final float TOLERANCE = 0.01F;
40 
41     /** Constructor. */
ScaleCRIF()42     public ScaleCRIF() {
43         super("scale");
44     }
45 
46     /**
47      * Creates a new instance of ScaleOpImage in the rendered layer.
48      * This method satisfies the implementation of RIF.
49      *
50      * @param paramBlock  The source image, the X and Y scale factor,
51      *                    and the interpolation method for resampling.
52      */
create(ParameterBlock paramBlock, RenderingHints renderHints)53     public RenderedImage create(ParameterBlock paramBlock,
54                                 RenderingHints renderHints) {
55 
56         // Get ImageLayout from renderHints if any.
57         ImageLayout layout = RIFUtil.getImageLayoutHint(renderHints);
58 
59         // Get TileCache from renderHints if any.
60         TileCache cache = RIFUtil.getTileCacheHint(renderHints);
61 
62         // Get BorderExtender from renderHints if any.
63         BorderExtender extender = RIFUtil.getBorderExtenderHint(renderHints);
64 
65         RenderedImage source = paramBlock.getRenderedSource(0);
66         float xScale = paramBlock.getFloatParameter(0);
67         float yScale = paramBlock.getFloatParameter(1);
68         float xTrans = paramBlock.getFloatParameter(2);
69         float yTrans = paramBlock.getFloatParameter(3);
70         Interpolation interp = (Interpolation)paramBlock.getObjectParameter(4);
71 
72 	// Check and see if we are scaling by 1.0 in both x and y and no
73         // translations. If so call the copy operation.
74 
75 	if (xScale == 1.0F && yScale == 1.0F &&
76 	    xTrans == 0.0F && yTrans == 0.0F) {
77 	    return new CopyOpImage(source, renderHints, layout);
78 	}
79 
80 
81 	// Check to see whether the operation specified is a pure
82 	// integer translation. If so call translate
83 	// If the hints contain an ImageLayout hint, then we can't use
84 	// TranslateIntOpImage since that can't deal with the ImageLayout hint
85 	if (xScale == 1.0F && yScale == 1.0F &&
86 	    (Math.abs(xTrans - (int)xTrans) < TOLERANCE) &&
87 	    (Math.abs(yTrans - (int)yTrans) < TOLERANCE) &&
88 	    layout == null) {
89 	    // It's an integer translate.
90             return new TranslateIntOpImage(source,
91 					   renderHints,
92 					   (int)xTrans,
93 					   (int)yTrans);
94 	}
95 
96         if (interp instanceof InterpolationNearest)  {
97             //
98             // Special case -- if the image is represented using
99             // a MultiPixelPackedSampleModel and a byte, ushort,
100             // or int DataBuffer we can access the pixel data directly.
101             // Note that there is a potential loophole that has not been
102             // resolved by Java2D as to whether the underlying DataBuffer
103             // must be of one of the standard types.  Here we make the
104             // assumption that it will be -- we can't check without
105             // forcing an actual tile to be computed.
106             //
107             SampleModel sm = source.getSampleModel();
108             if ((sm instanceof MultiPixelPackedSampleModel) &&
109                 (sm.getSampleSize(0) == 1) &&
110                 (sm.getDataType() == DataBuffer.TYPE_BYTE ||
111                  sm.getDataType() == DataBuffer.TYPE_USHORT ||
112                  sm.getDataType() == DataBuffer.TYPE_INT)) {
113                 return new ScaleNearestBinaryOpImage(source,
114                                                       extender,
115                                                       renderHints,
116                                                       layout,
117                                                       xScale,
118                                                       yScale,
119                                                       xTrans,
120                                                       yTrans,
121                                                       interp);
122             } else {
123 	      return new ScaleNearestOpImage(source,
124 					     extender,
125 					     renderHints,
126 					     layout,
127 					     xScale, yScale,
128 					     xTrans, yTrans,
129 					     interp);
130             }
131         }
132 	else
133 	  if (interp instanceof InterpolationBilinear)
134 	  {
135 	    SampleModel sm = source.getSampleModel();
136             if ((sm instanceof MultiPixelPackedSampleModel) &&
137                 (sm.getSampleSize(0) == 1) &&
138                 (sm.getDataType() == DataBuffer.TYPE_BYTE ||
139                  sm.getDataType() == DataBuffer.TYPE_USHORT ||
140                  sm.getDataType() == DataBuffer.TYPE_INT))
141 	    {
142 	      return new ScaleBilinearBinaryOpImage(source,
143 						    extender,
144 						    renderHints,
145 						    layout,
146 						    xScale,
147 						    yScale,
148 						    xTrans,
149 						    yTrans,
150 						    interp);
151             }
152 	    else
153 	    {
154 	      return new ScaleBilinearOpImage(source, extender,
155 					      renderHints,
156 					      layout,
157 					      xScale, yScale,
158 					      xTrans, yTrans,
159 					      interp);
160 	    }
161         } else if ((interp instanceof InterpolationBicubic) ||
162 		   (interp instanceof InterpolationBicubic2)) {
163 	    return new ScaleBicubicOpImage(source, extender,
164 					   renderHints,
165                                            layout,
166                                            xScale, yScale,
167                                            xTrans, yTrans,
168                                            interp);
169 	} else {
170 	    return new ScaleGeneralOpImage(source, extender,
171 					   renderHints,
172 					   layout,
173 					   xScale, yScale,
174 					   xTrans, yTrans,
175 					   interp);
176         }
177     }
178 
179     /**
180      * Creates a new instance of <code>AffineOpImage</code>
181      * in the renderable layer. This method satisfies the
182      * implementation of CRIF.
183      */
create(RenderContext renderContext, ParameterBlock paramBlock)184     public RenderedImage create(RenderContext renderContext,
185                                 ParameterBlock paramBlock) {
186         return paramBlock.getRenderedSource(0);
187     }
188 
189     /**
190      * Maps the output RenderContext into the RenderContext for the ith
191      * source.
192      * This method satisfies the implementation of CRIF.
193      *
194      * @param i               The index of the source image.
195      * @param renderContext   The renderContext being applied to the operation.
196      * @param paramBlock      The ParameterBlock containing the sources
197      *                        and the translation factors.
198      * @param image           The RenderableImageOp from which this method
199      *                        was called.
200      */
mapRenderContext(int i, RenderContext renderContext, ParameterBlock paramBlock, RenderableImage image)201     public RenderContext mapRenderContext(int i,
202                                           RenderContext renderContext,
203 					  ParameterBlock paramBlock,
204 					  RenderableImage image) {
205 
206 	float scale_x = paramBlock.getFloatParameter(0);
207         float scale_y = paramBlock.getFloatParameter(1);
208         float trans_x = paramBlock.getFloatParameter(2);
209         float trans_y = paramBlock.getFloatParameter(3);
210 
211         AffineTransform scale = new AffineTransform(scale_x, 0.0, 0.0, scale_y,
212                                                     trans_x, trans_y);
213 
214         RenderContext RC = (RenderContext)renderContext.clone();
215         AffineTransform usr2dev = RC.getTransform();
216         usr2dev.concatenate(scale);
217 	RC.setTransform(usr2dev);
218 	return RC;
219     }
220 
221     /**
222      * Gets the bounding box for the output of <code>ScaleOpImage</code>.
223      * This method satisfies the implementation of CRIF.
224      */
getBounds2D(ParameterBlock paramBlock)225     public Rectangle2D getBounds2D(ParameterBlock paramBlock) {
226 
227         RenderableImage source = paramBlock.getRenderableSource(0);
228 
229         float scale_x = paramBlock.getFloatParameter(0);
230         float scale_y = paramBlock.getFloatParameter(1);
231         float trans_x = paramBlock.getFloatParameter(2);
232         float trans_y = paramBlock.getFloatParameter(3);
233         Interpolation interp = (Interpolation)paramBlock.getObjectParameter(4);
234 
235 	// Get the source dimensions
236 	float x0 = (float)source.getMinX();
237 	float y0 = (float)source.getMinY() ;
238 	float w = (float)source.getWidth();
239 	float h = (float)source.getHeight();
240 
241 	// Forward map the source using x0, y0, w and h
242 	float d_x0 = x0 * scale_x + trans_x;
243 	float d_y0 = y0 * scale_y + trans_y;
244 	float d_w = w * scale_x;
245 	float d_h = h * scale_y;
246 
247 	return new Rectangle2D.Float(d_x0, d_y0, d_w, d_h);
248     }
249 
250 }
251