1 /* 2 * $RCSfile: AddConstOpImage.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:12 $ 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 // import com.lightcrafts.media.jai.test.OpImageTester; 26 27 /** 28 * An <code>OpImage</code> implementing the "AddConst" operation. 29 * 30 * <p>This <code>OpImage</code> adds a set of constants, one for each 31 * band of the source image, to the pixels of a rendered image. 32 * The destination pixel values are calculated as: 33 * <pre> 34 * for (int h = 0; h < dstHeight; h++) { 35 * for (int w = 0; w < dstWidth; w++) { 36 * for (int b = 0; b < dstNumBands; b++) { 37 * if (constants.length < dstNumBands) { 38 * dst[h][w][b] = srcs[h][w][b] + constants[0]; 39 * } else { 40 * dst[h][w][b] = srcs[h][w][b] + constants[b]; 41 * } 42 * } 43 * } 44 * } 45 * </pre> 46 * 47 * @see com.lightcrafts.mediax.jai.operator.AddConstDescriptor 48 * @see AddConstCRIF 49 * 50 */ 51 final class AddConstOpImage extends ColormapOpImage { 52 53 /** The constants to be added, one for each band. */ 54 protected double[] constants; 55 private byte[][] byteTable = null; 56 initByteTable()57 private synchronized void initByteTable() { 58 59 if (byteTable != null) { 60 return; 61 } 62 63 int nbands = constants.length; 64 65 byteTable = new byte[nbands][256]; 66 67 // Initialize table which implements AddConst 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 sum = i + k; 73 if (sum < 0) { 74 t[i] = (byte)0; 75 } else if (sum > 255) { 76 t[i] = (byte)255; 77 } else { 78 t[i] = (byte)sum; 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 added, stored as reference. 90 */ AddConstOpImage(RenderedImage source, Map config, ImageLayout layout, double[] constants)91 public AddConstOpImage(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 /** 134 * Adds a constant to the pixel values within a specified rectangle. 135 * 136 * @param sources Cobbled sources, guaranteed to provide all the 137 * source data necessary for computing the rectangle. 138 * @param dest The tile containing the rectangle to be computed. 139 * @param destRect The rectangle within the tile to be computed. 140 */ computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)141 protected void computeRect(Raster[] sources, 142 WritableRaster dest, 143 Rectangle destRect) { 144 // Retrieve format tags. 145 RasterFormatTag[] formatTags = getFormatTags(); 146 147 Rectangle srcRect = mapDestRect(destRect, 0); 148 149 RasterAccessor dst = new RasterAccessor(dest, destRect, 150 formatTags[1], getColorModel()); 151 RasterAccessor src = new RasterAccessor(sources[0], srcRect, 152 formatTags[0], 153 getSourceImage(0).getColorModel()); 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 byte[] d = dstData[b]; 202 byte[] s = srcData[b]; 203 byte[] clamp = byteTable[b]; 204 205 int dstLineOffset = dstBandOffsets[b]; 206 int srcLineOffset = srcBandOffsets[b]; 207 208 for (int h = 0; h < dstHeight; h++) { 209 int dstPixelOffset = dstLineOffset; 210 int srcPixelOffset = srcLineOffset; 211 212 dstLineOffset += dstLineStride; 213 srcLineOffset += srcLineStride; 214 215 int dstEnd = dstPixelOffset + dstWidth*dstPixelStride; 216 while(dstPixelOffset < dstEnd) { 217 d[dstPixelOffset] = clamp[s[srcPixelOffset] & 0xFF]; 218 219 dstPixelOffset += dstPixelStride; 220 srcPixelOffset += srcPixelStride; 221 } 222 } 223 } 224 } 225 computeRectUShort(RasterAccessor src, RasterAccessor dst)226 private void computeRectUShort(RasterAccessor src, 227 RasterAccessor dst) { 228 int dstWidth = dst.getWidth(); 229 int dstHeight = dst.getHeight(); 230 int dstBands = dst.getNumBands(); 231 232 int dstLineStride = dst.getScanlineStride(); 233 int dstPixelStride = dst.getPixelStride(); 234 int[] dstBandOffsets = dst.getBandOffsets(); 235 short[][] dstData = dst.getShortDataArrays(); 236 237 int srcLineStride = src.getScanlineStride(); 238 int srcPixelStride = src.getPixelStride(); 239 int[] srcBandOffsets = src.getBandOffsets(); 240 short[][] srcData = src.getShortDataArrays(); 241 242 for (int b = 0; b < dstBands; b++) { 243 int c = ImageUtil.clampRoundInt(constants[b]); 244 short[] d = dstData[b]; 245 short[] s = srcData[b]; 246 247 int dstLineOffset = dstBandOffsets[b]; 248 int srcLineOffset = srcBandOffsets[b]; 249 250 for (int h = 0; h < dstHeight; h++) { 251 int dstPixelOffset = dstLineOffset; 252 int srcPixelOffset = srcLineOffset; 253 254 dstLineOffset += dstLineStride; 255 srcLineOffset += srcLineStride; 256 257 for (int w = 0; w < dstWidth; w++) { 258 d[dstPixelOffset] = ImageUtil.clampUShort( 259 (s[srcPixelOffset] & 0xFFFF) + c); 260 261 dstPixelOffset += dstPixelStride; 262 srcPixelOffset += srcPixelStride; 263 } 264 } 265 } 266 } 267 computeRectShort(RasterAccessor src, RasterAccessor dst)268 private void computeRectShort(RasterAccessor src, 269 RasterAccessor dst) { 270 int dstWidth = dst.getWidth(); 271 int dstHeight = dst.getHeight(); 272 int dstBands = dst.getNumBands(); 273 274 int dstLineStride = dst.getScanlineStride(); 275 int dstPixelStride = dst.getPixelStride(); 276 int[] dstBandOffsets = dst.getBandOffsets(); 277 short[][] dstData = dst.getShortDataArrays(); 278 279 int srcLineStride = src.getScanlineStride(); 280 int srcPixelStride = src.getPixelStride(); 281 int[] srcBandOffsets = src.getBandOffsets(); 282 short[][] srcData = src.getShortDataArrays(); 283 284 for (int b = 0; b < dstBands; b++) { 285 int c = ImageUtil.clampRoundInt(constants[b]); 286 short[] d = dstData[b]; 287 short[] s = srcData[b]; 288 289 int dstLineOffset = dstBandOffsets[b]; 290 int srcLineOffset = srcBandOffsets[b]; 291 292 for (int h = 0; h < dstHeight; h++) { 293 int dstPixelOffset = dstLineOffset; 294 int srcPixelOffset = srcLineOffset; 295 296 dstLineOffset += dstLineStride; 297 srcLineOffset += srcLineStride; 298 299 for (int w = 0; w < dstWidth; w++) { 300 d[dstPixelOffset] = ImageUtil.clampShort(s[srcPixelOffset] + c); 301 302 dstPixelOffset += dstPixelStride; 303 srcPixelOffset += srcPixelStride; 304 } 305 } 306 } 307 } 308 computeRectInt(RasterAccessor src, RasterAccessor dst)309 private void computeRectInt(RasterAccessor src, 310 RasterAccessor dst) { 311 int dstWidth = dst.getWidth(); 312 int dstHeight = dst.getHeight(); 313 int dstBands = dst.getNumBands(); 314 315 int dstLineStride = dst.getScanlineStride(); 316 int dstPixelStride = dst.getPixelStride(); 317 int[] dstBandOffsets = dst.getBandOffsets(); 318 int[][] dstData = dst.getIntDataArrays(); 319 320 int srcLineStride = src.getScanlineStride(); 321 int srcPixelStride = src.getPixelStride(); 322 int[] srcBandOffsets = src.getBandOffsets(); 323 int[][] srcData = src.getIntDataArrays(); 324 325 for (int b = 0; b < dstBands; b++) { 326 long c = ImageUtil.clampRoundInt(constants[b]); 327 int[] d = dstData[b]; 328 int[] s = srcData[b]; 329 330 int dstLineOffset = dstBandOffsets[b]; 331 int srcLineOffset = srcBandOffsets[b]; 332 333 for (int h = 0; h < dstHeight; h++) { 334 int dstPixelOffset = dstLineOffset; 335 int srcPixelOffset = srcLineOffset; 336 337 dstLineOffset += dstLineStride; 338 srcLineOffset += srcLineStride; 339 340 for (int w = 0; w < dstWidth; w++) { 341 d[dstPixelOffset] = ImageUtil.clampInt(s[srcPixelOffset] + c); 342 343 dstPixelOffset += dstPixelStride; 344 srcPixelOffset += srcPixelStride; 345 } 346 } 347 } 348 } 349 computeRectFloat(RasterAccessor src, RasterAccessor dst)350 private void computeRectFloat(RasterAccessor src, 351 RasterAccessor dst) { 352 int dstWidth = dst.getWidth(); 353 int dstHeight = dst.getHeight(); 354 int dstBands = dst.getNumBands(); 355 356 int dstLineStride = dst.getScanlineStride(); 357 int dstPixelStride = dst.getPixelStride(); 358 int[] dstBandOffsets = dst.getBandOffsets(); 359 float[][] dstData = dst.getFloatDataArrays(); 360 361 int srcLineStride = src.getScanlineStride(); 362 int srcPixelStride = src.getPixelStride(); 363 int[] srcBandOffsets = src.getBandOffsets(); 364 float[][] srcData = src.getFloatDataArrays(); 365 366 for (int b = 0; b < dstBands; b++) { 367 double c = constants[b]; 368 float[] d = dstData[b]; 369 float[] s = srcData[b]; 370 371 int dstLineOffset = dstBandOffsets[b]; 372 int srcLineOffset = srcBandOffsets[b]; 373 374 for (int h = 0; h < dstHeight; h++) { 375 int dstPixelOffset = dstLineOffset; 376 int srcPixelOffset = srcLineOffset; 377 378 dstLineOffset += dstLineStride; 379 srcLineOffset += srcLineStride; 380 381 for (int w = 0; w < dstWidth; w++) { 382 d[dstPixelOffset] = ImageUtil.clampFloat(s[srcPixelOffset] + c); 383 384 dstPixelOffset += dstPixelStride; 385 srcPixelOffset += srcPixelStride; 386 } 387 } 388 } 389 } 390 computeRectDouble(RasterAccessor src, RasterAccessor dst)391 private void computeRectDouble(RasterAccessor src, 392 RasterAccessor dst) { 393 int dstWidth = dst.getWidth(); 394 int dstHeight = dst.getHeight(); 395 int dstBands = dst.getNumBands(); 396 397 int dstLineStride = dst.getScanlineStride(); 398 int dstPixelStride = dst.getPixelStride(); 399 int[] dstBandOffsets = dst.getBandOffsets(); 400 double[][] dstData = dst.getDoubleDataArrays(); 401 402 int srcLineStride = src.getScanlineStride(); 403 int srcPixelStride = src.getPixelStride(); 404 int[] srcBandOffsets = src.getBandOffsets(); 405 double[][] srcData = src.getDoubleDataArrays(); 406 407 for (int b = 0; b < dstBands; b++) { 408 double c = constants[b]; 409 double[] d = dstData[b]; 410 double[] s = srcData[b]; 411 412 int dstLineOffset = dstBandOffsets[b]; 413 int srcLineOffset = srcBandOffsets[b]; 414 415 for (int h = 0; h < dstHeight; h++) { 416 int dstPixelOffset = dstLineOffset; 417 int srcPixelOffset = srcLineOffset; 418 419 dstLineOffset += dstLineStride; 420 srcLineOffset += srcLineStride; 421 422 for (int w = 0; w < dstWidth; w++) { 423 d[dstPixelOffset] = s[srcPixelOffset] + c; 424 425 dstPixelOffset += dstPixelStride; 426 srcPixelOffset += srcPixelStride; 427 } 428 } 429 } 430 } 431 432 // public static void main(String args[]) { 433 // System.out.println("AddConstOpImage Test"); 434 435 // ImageLayout layout; 436 // OpImage src, dst; 437 // Rectangle rect = new Rectangle(0, 0, 5, 5); 438 439 // double[] constants = new double[3]; 440 // constants[0] = 10.0; 441 // constants[1] = 20.0; 442 // constants[2] = 30.0; 443 444 // System.out.println("1. PixelInterleaved byte 3-band"); 445 // layout = OpImageTester.createImageLayout( 446 // 0, 0, 800, 800, 0, 0, 200, 200, DataBuffer.TYPE_BYTE, 3, false); 447 // src = OpImageTester.createRandomOpImage(layout); 448 // dst = new AddConstOpImage(src, null, null, constants); 449 // OpImageTester.testOpImage(dst, rect); 450 // OpImageTester.timeOpImage(dst, 10); 451 452 // System.out.println("3. PixelInterleaved int 3-band"); 453 // layout = OpImageTester.createImageLayout( 454 // 0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_INT, 3, false); 455 // src = OpImageTester.createRandomOpImage(layout); 456 // dst = new AddConstOpImage(src, null, null, constants); 457 // OpImageTester.testOpImage(dst, rect); 458 // OpImageTester.timeOpImage(dst, 10); 459 // } 460 } 461