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