1 /* 2 * $RCSfile: ExpOpImage.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:25 $ 10 * $State: Exp $ 11 */ 12 package com.lightcrafts.media.jai.opimage; 13 14 import com.lightcrafts.mediax.jai.ColormapOpImage; 15 import java.awt.Rectangle; 16 import java.awt.image.DataBuffer; 17 import java.awt.image.Raster; 18 import java.awt.image.RenderedImage; 19 import java.awt.image.WritableRaster; 20 import com.lightcrafts.mediax.jai.ImageLayout; 21 import com.lightcrafts.mediax.jai.RasterAccessor; 22 import com.lightcrafts.mediax.jai.RasterFormatTag; 23 import java.util.Map; 24 import com.lightcrafts.media.jai.util.ImageUtil; 25 26 /** 27 * An <code>OpImage</code> implementing the "Exp" operation as 28 * described in <code>com.lightcrafts.mediax.jai.operator.ExpDescriptor</code>. 29 * 30 * The result is rounded to the closest integer for intergral data types. 31 * <p> This <code>OpImage</code> takes the natural exponential of the pixel 32 * values of an image. The operation is done on a per-pixel, per-band 33 * basis. 34 * 35 * @see com.lightcrafts.mediax.jai.operator.ExpDescriptor 36 * @see ExpCRIF 37 * 38 * @since EA2 39 * 40 */ 41 final class ExpOpImage extends ColormapOpImage { 42 43 /** A lookup table for byte data type. */ 44 private byte[] byteTable = null; 45 46 /** 47 * The largest unsigned short to get a non-overflowed exponential result. 48 * i.e. cloeset to 65536. 49 * exp(11) = 59874.14171, exp(12) = 162754.7914 50 */ 51 private static int USHORT_UP_BOUND = 11; 52 53 /** 54 * The largest short to get a non-overflowed exponential result. 55 * i.e. closest to 32767. 56 * exp(10) = 22026.46579, exp(11) = 59874.14171 57 */ 58 private static int SHORT_UP_BOUND = 10; 59 60 /** 61 * The largest int to get a non-overflown exponential result. 62 * i.e. cloeset to 2**31-1 = 2147483647. 63 * exp(21) = 1318815734, exp(22) = 3584912846. 64 */ 65 private static int INT_UP_BOUND = 21; 66 67 /** 68 * The smallest integer to get a non-zero exponential result is 69 * 0. i.e. exp(0) = 1; exp(-1) = 0.367879441, which will be stored as 0. 70 * all other negative values will result in 0. 71 */ 72 private static int LOW_BOUND = 0; 73 74 /** 75 * Constructor. 76 * 77 * <p> The layout of the source is used as the fall-back for 78 * the layout of the destination. Any layout parameters not 79 * specified in the <code>layout</code> argument are set to 80 * the same value as that of the source. 81 * 82 * @param source The source image. 83 84 * @param layout The destination image layout. 85 */ ExpOpImage(RenderedImage source, Map config, ImageLayout layout)86 public ExpOpImage(RenderedImage source, 87 Map config, 88 ImageLayout layout) { 89 super(source, layout, config, true); 90 91 /* Set flag to permit in-place operation. */ 92 permitInPlaceOperation(); 93 94 // Initialize the colormap if necessary. 95 initializeColormapOperation(); 96 } 97 98 /** 99 * Transform the colormap according to the rescaling parameters. 100 */ transformColormap(byte[][] colormap)101 protected void transformColormap(byte[][] colormap) { 102 initByteTable(); 103 104 for(int b = 0; b < 3; b++) { 105 byte[] map = colormap[b]; 106 int mapSize = map.length; 107 108 for(int i = 0; i < mapSize; i++) { 109 map[i] = byteTable[(map[i] & 0xFF)]; 110 } 111 } 112 } 113 114 /** 115 * Map the pixels inside a specified rectangle whose value is within a 116 * range to a constant on a per-band basis. 117 * 118 * @param sources Cobbled sources, guaranteed to provide all the 119 * source data necessary for computing the rectangle. 120 * @param dest The tile containing the rectangle to be computed. 121 * @param destRect The rectangle within the tile to be computed. 122 */ computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)123 protected void computeRect(Raster[] sources, 124 WritableRaster dest, 125 Rectangle destRect) { 126 /* Retrieve format tags. */ 127 RasterFormatTag[] formatTags = getFormatTags(); 128 129 /* No need to mapSourceRect for PointOps. */ 130 RasterAccessor s = new RasterAccessor(sources[0], 131 destRect, 132 formatTags[0], 133 getSourceImage(0).getColorModel()); 134 RasterAccessor d = new RasterAccessor(dest, 135 destRect, 136 formatTags[1], 137 getColorModel()); 138 139 switch (d.getDataType()) { 140 case DataBuffer.TYPE_BYTE: 141 computeRectByte(s, d); 142 break; 143 case DataBuffer.TYPE_USHORT: 144 computeRectUShort(s, d); 145 break; 146 case DataBuffer.TYPE_SHORT: 147 computeRectShort(s, d); 148 break; 149 case DataBuffer.TYPE_INT: 150 computeRectInt(s, d); 151 break; 152 case DataBuffer.TYPE_FLOAT: 153 computeRectFloat(s, d); 154 break; 155 case DataBuffer.TYPE_DOUBLE: 156 computeRectDouble(s, d); 157 break; 158 } 159 160 if (d.needsClamping()) { 161 d.clampDataArrays(); 162 } 163 d.copyDataToRaster(); 164 } 165 computeRectByte(RasterAccessor src, RasterAccessor dst)166 private void computeRectByte(RasterAccessor src, 167 RasterAccessor dst) { 168 initByteTable(); 169 170 int srcLineStride = src.getScanlineStride(); 171 int srcPixelStride = src.getPixelStride(); 172 int[] srcBandOffsets = src.getBandOffsets(); 173 byte[][] srcData = src.getByteDataArrays(); 174 175 int dstLineStride = dst.getScanlineStride(); 176 int dstPixelStride = dst.getPixelStride(); 177 int[] dstBandOffsets = dst.getBandOffsets(); 178 byte[][] dstData = dst.getByteDataArrays(); 179 180 int dstWidth = dst.getWidth(); 181 int dstHeight = dst.getHeight(); 182 int dstBands = dst.getNumBands(); 183 184 for (int b = 0; b < dstBands; b++) { 185 byte[] s = srcData[b]; 186 byte[] d = dstData[b]; 187 188 int srcLineOffset = srcBandOffsets[b]; 189 int dstLineOffset = dstBandOffsets[b]; 190 191 for (int h = 0; h < dstHeight; h++) { 192 int srcPixelOffset = srcLineOffset; 193 int dstPixelOffset = dstLineOffset; 194 195 srcLineOffset += srcLineStride; 196 dstLineOffset += dstLineStride; 197 198 for (int w = 0; w < dstWidth; w++) { 199 d[dstPixelOffset] = byteTable[s[srcPixelOffset] & ImageUtil.BYTE_MASK]; 200 201 srcPixelOffset += srcPixelStride; 202 dstPixelOffset += dstPixelStride; 203 } 204 } 205 } 206 } 207 computeRectUShort(RasterAccessor src, RasterAccessor dst)208 private void computeRectUShort(RasterAccessor src, 209 RasterAccessor dst) { 210 211 int srcLineStride = src.getScanlineStride(); 212 int srcPixelStride = src.getPixelStride(); 213 int[] srcBandOffsets = src.getBandOffsets(); 214 short[][] srcData = src.getShortDataArrays(); 215 216 int dstLineStride = dst.getScanlineStride(); 217 int dstPixelStride = dst.getPixelStride(); 218 int[] dstBandOffsets = dst.getBandOffsets(); 219 short[][] dstData = dst.getShortDataArrays(); 220 221 int dstWidth = dst.getWidth(); 222 int dstHeight = dst.getHeight(); 223 int dstBands = dst.getNumBands(); 224 225 short max = (short)ImageUtil.USHORT_MASK; 226 227 for (int b = 0; b < dstBands; b++) { 228 short[] s = srcData[b]; 229 short[] d = dstData[b]; 230 231 int srcLineOffset = srcBandOffsets[b]; 232 int dstLineOffset = dstBandOffsets[b]; 233 234 for (int h = 0; h < dstHeight; h++) { 235 int srcPixelOffset = srcLineOffset; 236 int dstPixelOffset = dstLineOffset; 237 238 srcLineOffset += srcLineStride; 239 dstLineOffset += dstLineStride; 240 241 for (int w = 0; w < dstWidth; w++) { 242 double p = s[srcPixelOffset] & ImageUtil.USHORT_MASK; 243 if (p == 0) { 244 d[dstPixelOffset] = 1; 245 } else if (p > USHORT_UP_BOUND) { 246 d[dstPixelOffset] = max; 247 } else { 248 d[dstPixelOffset] = (short)(Math.exp(p) + 0.5); 249 } 250 251 srcPixelOffset += srcPixelStride; 252 dstPixelOffset += dstPixelStride; 253 } 254 } 255 } 256 } 257 computeRectShort(RasterAccessor src, RasterAccessor dst)258 private void computeRectShort(RasterAccessor src, 259 RasterAccessor dst) { 260 261 int srcLineStride = src.getScanlineStride(); 262 int srcPixelStride = src.getPixelStride(); 263 int[] srcBandOffsets = src.getBandOffsets(); 264 short[][] srcData = src.getShortDataArrays(); 265 266 int dstLineStride = dst.getScanlineStride(); 267 int dstPixelStride = dst.getPixelStride(); 268 int[] dstBandOffsets = dst.getBandOffsets(); 269 short[][] dstData = dst.getShortDataArrays(); 270 271 int dstWidth = dst.getWidth(); 272 int dstHeight = dst.getHeight(); 273 int dstBands = dst.getNumBands(); 274 275 for (int b = 0; b < dstBands; b++) { 276 short[] s = srcData[b]; 277 short[] d = dstData[b]; 278 279 int srcLineOffset = srcBandOffsets[b]; 280 int dstLineOffset = dstBandOffsets[b]; 281 282 for (int h = 0; h < dstHeight; h++) { 283 int srcPixelOffset = srcLineOffset; 284 int dstPixelOffset = dstLineOffset; 285 286 srcLineOffset += srcLineStride; 287 dstLineOffset += dstLineStride; 288 289 for (int w = 0; w < dstWidth; w++) { 290 double p = s[srcPixelOffset]; 291 if (p < LOW_BOUND) { 292 d[dstPixelOffset] = 0; 293 } else if (p == 0) { 294 d[dstPixelOffset] = 1; 295 } else if (p > SHORT_UP_BOUND) { 296 d[dstPixelOffset] = Short.MAX_VALUE; 297 } else { 298 d[dstPixelOffset] = (short)(Math.exp(p) + 0.5); 299 } 300 301 srcPixelOffset += srcPixelStride; 302 dstPixelOffset += dstPixelStride; 303 } 304 } 305 } 306 } 307 computeRectInt(RasterAccessor src, RasterAccessor dst)308 private void computeRectInt(RasterAccessor src, 309 RasterAccessor dst) { 310 311 int srcLineStride = src.getScanlineStride(); 312 int srcPixelStride = src.getPixelStride(); 313 int[] srcBandOffsets = src.getBandOffsets(); 314 int[][] srcData = src.getIntDataArrays(); 315 316 int dstLineStride = dst.getScanlineStride(); 317 int dstPixelStride = dst.getPixelStride(); 318 int[] dstBandOffsets = dst.getBandOffsets(); 319 int[][] dstData = dst.getIntDataArrays(); 320 321 int dstWidth = dst.getWidth(); 322 int dstHeight = dst.getHeight(); 323 int dstBands = dst.getNumBands(); 324 325 for (int b = 0; b < dstBands; b++) { 326 int[] s = srcData[b]; 327 int[] d = dstData[b]; 328 329 int srcLineOffset = srcBandOffsets[b]; 330 int dstLineOffset = dstBandOffsets[b]; 331 332 for (int h = 0; h < dstHeight; h++) { 333 int srcPixelOffset = srcLineOffset; 334 int dstPixelOffset = dstLineOffset; 335 336 srcLineOffset += srcLineStride; 337 dstLineOffset += dstLineStride; 338 339 for (int w = 0; w < dstWidth; w++) { 340 double p = s[srcPixelOffset]; 341 if (p < LOW_BOUND) { 342 d[dstPixelOffset] = 0; 343 } else if (p == 0) { 344 d[dstPixelOffset] = 1; 345 } else if (p > INT_UP_BOUND) { 346 d[dstPixelOffset] = Integer.MAX_VALUE; 347 } else { 348 d[dstPixelOffset] = (int)(Math.exp(p) + 0.5); 349 } 350 351 srcPixelOffset += srcPixelStride; 352 dstPixelOffset += dstPixelStride; 353 } 354 } 355 } 356 } 357 computeRectFloat(RasterAccessor src, RasterAccessor dst)358 private void computeRectFloat(RasterAccessor src, 359 RasterAccessor dst) { 360 361 int srcLineStride = src.getScanlineStride(); 362 int srcPixelStride = src.getPixelStride(); 363 int[] srcBandOffsets = src.getBandOffsets(); 364 float[][] srcData = src.getFloatDataArrays(); 365 366 int dstLineStride = dst.getScanlineStride(); 367 int dstPixelStride = dst.getPixelStride(); 368 int[] dstBandOffsets = dst.getBandOffsets(); 369 float[][] dstData = dst.getFloatDataArrays(); 370 371 int dstWidth = dst.getWidth(); 372 int dstHeight = dst.getHeight(); 373 int dstBands = dst.getNumBands(); 374 375 for (int b = 0; b < dstBands; b++) { 376 float[] s = srcData[b]; 377 float[] d = dstData[b]; 378 379 int srcLineOffset = srcBandOffsets[b]; 380 int dstLineOffset = dstBandOffsets[b]; 381 382 for (int h = 0; h < dstHeight; h++) { 383 int srcPixelOffset = srcLineOffset; 384 int dstPixelOffset = dstLineOffset; 385 386 srcLineOffset += srcLineStride; 387 dstLineOffset += dstLineStride; 388 389 for (int w = 0; w < dstWidth; w++) { 390 d[dstPixelOffset] = (float)Math.exp(s[srcPixelOffset]); 391 392 srcPixelOffset += srcPixelStride; 393 dstPixelOffset += dstPixelStride; 394 } 395 } 396 } 397 } 398 computeRectDouble(RasterAccessor src, RasterAccessor dst)399 private void computeRectDouble(RasterAccessor src, 400 RasterAccessor dst) { 401 402 int srcLineStride = src.getScanlineStride(); 403 int srcPixelStride = src.getPixelStride(); 404 int[] srcBandOffsets = src.getBandOffsets(); 405 double[][] srcData = src.getDoubleDataArrays(); 406 407 int dstLineStride = dst.getScanlineStride(); 408 int dstPixelStride = dst.getPixelStride(); 409 int[] dstBandOffsets = dst.getBandOffsets(); 410 double[][] dstData = dst.getDoubleDataArrays(); 411 412 int dstWidth = dst.getWidth(); 413 int dstHeight = dst.getHeight(); 414 int dstBands = dst.getNumBands(); 415 416 for (int b = 0; b < dstBands; b++) { 417 double[] s = srcData[b]; 418 double[] d = dstData[b]; 419 420 int srcLineOffset = srcBandOffsets[b]; 421 int dstLineOffset = dstBandOffsets[b]; 422 423 for (int h = 0; h < dstHeight; h++) { 424 int srcPixelOffset = srcLineOffset; 425 int dstPixelOffset = dstLineOffset; 426 427 srcLineOffset += srcLineStride; 428 dstLineOffset += dstLineStride; 429 430 for (int w = 0; w < dstWidth; w++) { 431 d[dstPixelOffset] = Math.exp(s[srcPixelOffset]); 432 433 srcPixelOffset += srcPixelStride; 434 dstPixelOffset += dstPixelStride; 435 } 436 } 437 } 438 } 439 initByteTable()440 private synchronized void initByteTable() { 441 442 if (byteTable != null) 443 return; 444 445 byteTable = new byte[0x100]; 446 447 /* 448 * exp(5) = 148.4131591... 449 * exp(6) = 403.4287935... 450 * Calculate up to 5 and set the rest to the maximum value. 451 */ 452 byteTable[0] = 1; 453 454 for (int i = 1; i < 6; i++) { 455 byteTable[i] = (byte)(Math.exp(i) + 0.5); 456 } 457 458 for (int i = 6; i < 0x100; i++) { 459 byteTable[i] = (byte)ImageUtil.BYTE_MASK; 460 } 461 } 462 } 463