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