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