1 /* 2 * $RCSfile: AddOpImage.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 import java.awt.Rectangle; 14 import java.awt.image.DataBuffer; 15 import java.awt.image.Raster; 16 import java.awt.image.RenderedImage; 17 import java.awt.image.SampleModel; 18 import java.awt.image.WritableRaster; 19 import com.lightcrafts.mediax.jai.ImageLayout; 20 import com.lightcrafts.mediax.jai.PointOpImage; 21 import com.lightcrafts.mediax.jai.RasterAccessor; 22 import com.lightcrafts.mediax.jai.RasterFormatTag; 23 import com.lightcrafts.mediax.jai.RasterFactory; 24 import java.util.Map; 25 import com.lightcrafts.media.jai.util.ImageUtil; 26 import com.lightcrafts.media.jai.util.JDKWorkarounds; 27 /// import com.lightcrafts.media.jai.test.OpImageTester; 28 29 /** 30 * An <code>OpImage</code> implementing the "Add" operation as 31 * described in <code>com.lightcrafts.mediax.jai.operator.AddDescriptor</code>. 32 * 33 * <p>This <code>OpImage</code> adds the pixel values of two source 34 * images on a per-band basis. In case the two source images have different 35 * number of bands, the number of bands for the destination image is the 36 * smaller band number of the two source images. That is 37 * <code>dstNumBands = Math.min(src1NumBands, src2NumBands)</code>. 38 * In case the two source images have different data types, the data type 39 * for the destination image is the higher data type of the two source 40 * images. 41 * 42 * <p>The value of the pixel (x, y) in the destination image is defined as: 43 * <pre> 44 * for (b = 0; b < numBands; b++) { 45 * dst[y][x][b] = src1[y][x][b] + src2[y][x][b]; 46 * } 47 * </pre> 48 * 49 * <p>If the result of the addition overflows/underflows the 50 * maximum/minimum value supported by the destination image, then it 51 * will be clamped to the maximum/minimum value respectively. The 52 * data type <code>byte</code> is treated as unsigned, with maximum 53 * value as 255 and minimum value as 0. 54 * 55 * @see com.lightcrafts.mediax.jai.operator.AddDescriptor 56 * @see AddCRIF 57 * 58 */ 59 final class AddOpImage extends PointOpImage { 60 61 /* Source 1 band increment */ 62 private int s1bd = 1; 63 64 /* Source 2 band increment */ 65 private int s2bd = 1; 66 67 /* Bilevel data flag. */ 68 private boolean areBinarySampleModels = false; 69 70 /** 71 * Constructs an <code>AddOpImage</code>. 72 * 73 * <p>The <code>layout</code> parameter may optionally contains the 74 * tile grid layout, sample model, and/or color model. The image 75 * dimension is determined by the intersection of the bounding boxes 76 * of the two source images. 77 * 78 * <p>The image layout of the first source image, <code>source1</code>, 79 * is used as the fall-back for the image layout of the destination 80 * image. Any layout parameters not specified in the <code>layout</code> 81 * argument are set to the same value as that of <code>source1</code>. 82 * 83 * @param source1 The first source image. 84 * @param source2 The second source image. 85 * @param layout The destination image layout. 86 */ AddOpImage(RenderedImage source1, RenderedImage source2, Map config, ImageLayout layout)87 public AddOpImage(RenderedImage source1, 88 RenderedImage source2, 89 Map config, 90 ImageLayout layout) { 91 super(source1, source2, layout, config, true); 92 93 if(ImageUtil.isBinary(getSampleModel()) && 94 ImageUtil.isBinary(source1.getSampleModel()) && 95 ImageUtil.isBinary(source2.getSampleModel())) { 96 // Binary processing case: RasterAccessor 97 areBinarySampleModels = true; 98 } else { 99 // Get the source band counts. 100 int numBands1 = source1.getSampleModel().getNumBands(); 101 int numBands2 = source2.getSampleModel().getNumBands(); 102 103 // Handle the special case of adding a single band image to 104 // each band of a multi-band image. 105 int numBandsDst; 106 if(layout != null && layout.isValid(ImageLayout.SAMPLE_MODEL_MASK)) { 107 SampleModel sm = layout.getSampleModel(null); 108 numBandsDst = sm.getNumBands(); 109 110 // One of the sources must be single-banded and the other must 111 // have at most the number of bands in the SampleModel hint. 112 if(numBandsDst > 1 && 113 ((numBands1 == 1 && numBands2 > 1) || 114 (numBands2 == 1 && numBands1 > 1))) { 115 // Clamp the destination band count to the number of 116 // bands in the multi-band source. 117 numBandsDst = Math.min(Math.max(numBands1, numBands2), 118 numBandsDst); 119 120 // Create a new SampleModel if necessary. 121 if(numBandsDst != sampleModel.getNumBands()) { 122 sampleModel = 123 RasterFactory.createComponentSampleModel( 124 sm, 125 sampleModel.getTransferType(), 126 sampleModel.getWidth(), 127 sampleModel.getHeight(), 128 numBandsDst); 129 130 if(colorModel != null && 131 !JDKWorkarounds.areCompatibleDataModels(sampleModel, 132 colorModel)) { 133 colorModel = 134 ImageUtil.getCompatibleColorModel(sampleModel, 135 config); 136 } 137 } 138 139 // Set the source band increments. 140 s1bd = numBands1 == 1 ? 0 : 1; 141 s2bd = numBands2 == 1 ? 0 : 1; 142 } 143 } 144 } 145 146 // Set flag to permit in-place operation. 147 permitInPlaceOperation(); 148 } 149 150 /** 151 * Adds the pixel values of two source images within a specified 152 * rectangle. 153 * 154 * @param sources Cobbled sources, guaranteed to provide all the 155 * source data necessary for computing the rectangle. 156 * @param dest The tile containing the rectangle to be computed. 157 * @param destRect The rectangle within the tile to be computed. 158 */ computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect)159 protected void computeRect(Raster[] sources, 160 WritableRaster dest, 161 Rectangle destRect) { 162 if(areBinarySampleModels) { 163 // Retrieve format tags. 164 RasterFormatTag[] formatTags = getFormatTags(); 165 166 // For PointOpImage, srcRect = destRect. 167 RasterAccessor s1 = 168 new RasterAccessor(sources[0], destRect, 169 formatTags[0], 170 getSourceImage(0).getColorModel()); 171 RasterAccessor s2 = 172 new RasterAccessor(sources[1], destRect, 173 formatTags[1], 174 getSourceImage(1).getColorModel()); 175 RasterAccessor d = 176 new RasterAccessor(dest, destRect, 177 formatTags[2], getColorModel()); 178 179 if(d.isBinary()) { 180 byte[] src1Bits = s1.getBinaryDataArray(); 181 byte[] src2Bits = s2.getBinaryDataArray(); 182 byte[] dstBits = d.getBinaryDataArray(); 183 184 int length = dstBits.length; 185 for(int i = 0; i < length; i++) { 186 // "Add" is equivalent to "Or" when 1+1 is clamped to 1. 187 dstBits[i] = (byte)(src1Bits[i] | src2Bits[i]); 188 } 189 190 d.copyBinaryDataToRaster(); 191 192 return; 193 } 194 } 195 196 // Retrieve format tags. 197 RasterFormatTag[] formatTags = getFormatTags(); 198 199 RasterAccessor s1 = new RasterAccessor(sources[0], destRect, 200 formatTags[0], 201 getSourceImage(0).getColorModel()); 202 RasterAccessor s2 = new RasterAccessor(sources[1], destRect, 203 formatTags[1], 204 getSourceImage(1).getColorModel()); 205 RasterAccessor d = new RasterAccessor(dest, destRect, 206 formatTags[2], getColorModel()); 207 208 switch (d.getDataType()) { 209 case DataBuffer.TYPE_BYTE: 210 computeRectByte(s1, s2, d); 211 break; 212 case DataBuffer.TYPE_USHORT: 213 computeRectUShort(s1, s2, d); 214 break; 215 case DataBuffer.TYPE_SHORT: 216 computeRectShort(s1, s2, d); 217 break; 218 case DataBuffer.TYPE_INT: 219 computeRectInt(s1, s2, d); 220 break; 221 case DataBuffer.TYPE_FLOAT: 222 computeRectFloat(s1, s2, d); 223 break; 224 case DataBuffer.TYPE_DOUBLE: 225 computeRectDouble(s1, s2, d); 226 break; 227 } 228 229 if (d.needsClamping()) { 230 d.clampDataArrays(); 231 } 232 d.copyDataToRaster(); 233 } 234 computeRectByte(RasterAccessor src1, RasterAccessor src2, RasterAccessor dst)235 private void computeRectByte(RasterAccessor src1, 236 RasterAccessor src2, 237 RasterAccessor dst) { 238 int s1LineStride = src1.getScanlineStride(); 239 int s1PixelStride = src1.getPixelStride(); 240 int[] s1BandOffsets = src1.getBandOffsets(); 241 byte[][] s1Data = src1.getByteDataArrays(); 242 243 int s2LineStride = src2.getScanlineStride(); 244 int s2PixelStride = src2.getPixelStride(); 245 int[] s2BandOffsets = src2.getBandOffsets(); 246 byte[][] s2Data = src2.getByteDataArrays(); 247 248 int dwidth = dst.getWidth(); 249 int dheight = dst.getHeight(); 250 int bands = dst.getNumBands(); 251 int dLineStride = dst.getScanlineStride(); 252 int dPixelStride = dst.getPixelStride(); 253 int[] dBandOffsets = dst.getBandOffsets(); 254 byte[][] dData = dst.getByteDataArrays(); 255 256 for (int b = 0, s1b = 0, s2b = 0; b < bands; 257 b++, s1b += s1bd, s2b += s2bd) { 258 byte[] s1 = s1Data[s1b]; 259 byte[] s2 = s2Data[s2b]; 260 byte[] d = dData[b]; 261 262 int s1LineOffset = s1BandOffsets[s1b]; 263 int s2LineOffset = s2BandOffsets[s2b]; 264 int dLineOffset = dBandOffsets[b]; 265 266 for (int h = 0; h < dheight; h++) { 267 int s1PixelOffset = s1LineOffset; 268 int s2PixelOffset = s2LineOffset; 269 int dPixelOffset = dLineOffset; 270 271 s1LineOffset += s1LineStride; 272 s2LineOffset += s2LineStride; 273 dLineOffset += dLineStride; 274 275 int sum = 0; 276 for (int w = 0; w < dwidth; w++) { 277 // 278 // The next two lines are a fast way to do 279 // an add with saturation on U8 elements. 280 // It eliminates the need to do clamping. 281 // 282 sum = (s1[s1PixelOffset]&0xFF) + (s2[s2PixelOffset]&0xFF); 283 d[dPixelOffset] = (byte)((((sum<<23) >> 31) | sum) & 0xFF); 284 285 s1PixelOffset += s1PixelStride; 286 s2PixelOffset += s2PixelStride; 287 dPixelOffset += dPixelStride; 288 } 289 } 290 } 291 } 292 computeRectUShort(RasterAccessor src1, RasterAccessor src2, RasterAccessor dst)293 private void computeRectUShort(RasterAccessor src1, 294 RasterAccessor src2, 295 RasterAccessor dst) { 296 int s1LineStride = src1.getScanlineStride(); 297 int s1PixelStride = src1.getPixelStride(); 298 int[] s1BandOffsets = src1.getBandOffsets(); 299 short[][] s1Data = src1.getShortDataArrays(); 300 301 int s2LineStride = src2.getScanlineStride(); 302 int s2PixelStride = src2.getPixelStride(); 303 int[] s2BandOffsets = src2.getBandOffsets(); 304 short[][] s2Data = src2.getShortDataArrays(); 305 306 int dwidth = dst.getWidth(); 307 int dheight = dst.getHeight(); 308 int bands = dst.getNumBands(); 309 int dLineStride = dst.getScanlineStride(); 310 int dPixelStride = dst.getPixelStride(); 311 int[] dBandOffsets = dst.getBandOffsets(); 312 short[][] dData = dst.getShortDataArrays(); 313 314 for (int b = 0, s1b = 0, s2b = 0; b < bands; 315 b++, s1b += s1bd, s2b += s2bd) { 316 short[] s1 = s1Data[s1b]; 317 short[] s2 = s2Data[s2b]; 318 short[] d = dData[b]; 319 320 int s1LineOffset = s1BandOffsets[s1b]; 321 int s2LineOffset = s2BandOffsets[s2b]; 322 int dLineOffset = dBandOffsets[b]; 323 324 for (int h = 0; h < dheight; h++) { 325 int s1PixelOffset = s1LineOffset; 326 int s2PixelOffset = s2LineOffset; 327 int dPixelOffset = dLineOffset; 328 329 s1LineOffset += s1LineStride; 330 s2LineOffset += s2LineStride; 331 dLineOffset += dLineStride; 332 333 for (int w = 0; w < dwidth; w++) { 334 d[dPixelOffset] = ImageUtil.clampUShortPositive( 335 (int)(s1[s1PixelOffset]&0xFFFF) + 336 (int)(s2[s2PixelOffset]&0xFFFF)); 337 338 s1PixelOffset += s1PixelStride; 339 s2PixelOffset += s2PixelStride; 340 dPixelOffset += dPixelStride; 341 } 342 } 343 } 344 } 345 computeRectShort(RasterAccessor src1, RasterAccessor src2, RasterAccessor dst)346 private void computeRectShort(RasterAccessor src1, 347 RasterAccessor src2, 348 RasterAccessor dst) { 349 int s1LineStride = src1.getScanlineStride(); 350 int s1PixelStride = src1.getPixelStride(); 351 int[] s1BandOffsets = src1.getBandOffsets(); 352 short[][] s1Data = src1.getShortDataArrays(); 353 354 int s2LineStride = src2.getScanlineStride(); 355 int s2PixelStride = src2.getPixelStride(); 356 int[] s2BandOffsets = src2.getBandOffsets(); 357 short[][] s2Data = src2.getShortDataArrays(); 358 359 int dwidth = dst.getWidth(); 360 int dheight = dst.getHeight(); 361 int bands = dst.getNumBands(); 362 int dLineStride = dst.getScanlineStride(); 363 int dPixelStride = dst.getPixelStride(); 364 int[] dBandOffsets = dst.getBandOffsets(); 365 short[][] dData = dst.getShortDataArrays(); 366 367 for (int b = 0, s1b = 0, s2b = 0; b < bands; 368 b++, s1b += s1bd, s2b += s2bd) { 369 short[] s1 = s1Data[s1b]; 370 short[] s2 = s2Data[s2b]; 371 short[] d = dData[b]; 372 373 int s1LineOffset = s1BandOffsets[s1b]; 374 int s2LineOffset = s2BandOffsets[s2b]; 375 int dLineOffset = dBandOffsets[b]; 376 377 for (int h = 0; h < dheight; h++) { 378 int s1PixelOffset = s1LineOffset; 379 int s2PixelOffset = s2LineOffset; 380 int dPixelOffset = dLineOffset; 381 382 s1LineOffset += s1LineStride; 383 s2LineOffset += s2LineStride; 384 dLineOffset += dLineStride; 385 386 for (int w = 0; w < dwidth; w++) { 387 d[dPixelOffset] = ImageUtil.clampShort((int)s1[s1PixelOffset] + 388 (int)s2[s2PixelOffset]); 389 390 s1PixelOffset += s1PixelStride; 391 s2PixelOffset += s2PixelStride; 392 dPixelOffset += dPixelStride; 393 } 394 } 395 } 396 } 397 computeRectInt(RasterAccessor src1, RasterAccessor src2, RasterAccessor dst)398 private void computeRectInt(RasterAccessor src1, 399 RasterAccessor src2, 400 RasterAccessor dst) { 401 int s1LineStride = src1.getScanlineStride(); 402 int s1PixelStride = src1.getPixelStride(); 403 int[] s1BandOffsets = src1.getBandOffsets(); 404 int[][] s1Data = src1.getIntDataArrays(); 405 406 int s2LineStride = src2.getScanlineStride(); 407 int s2PixelStride = src2.getPixelStride(); 408 int[] s2BandOffsets = src2.getBandOffsets(); 409 int[][] s2Data = src2.getIntDataArrays(); 410 411 int dwidth = dst.getWidth(); 412 int dheight = dst.getHeight(); 413 int bands = dst.getNumBands(); 414 int dLineStride = dst.getScanlineStride(); 415 int dPixelStride = dst.getPixelStride(); 416 int[] dBandOffsets = dst.getBandOffsets(); 417 int[][] dData = dst.getIntDataArrays(); 418 419 /* 420 * The destination data type may be any of the integral data types. 421 * The "clamp" function must clamp to the appropriate range for 422 * that data type. 423 */ 424 switch (sampleModel.getTransferType()) { 425 case DataBuffer.TYPE_BYTE: 426 for (int b = 0, s1b = 0, s2b = 0; b < bands; 427 b++, s1b += s1bd, s2b += s2bd) { 428 int[] s1 = s1Data[s1b]; 429 int[] s2 = s2Data[s2b]; 430 int[] d = dData[b]; 431 432 int s1LineOffset = s1BandOffsets[s1b]; 433 int s2LineOffset = s2BandOffsets[s2b]; 434 int dLineOffset = dBandOffsets[b]; 435 436 for (int h = 0; h < dheight; h++) { 437 int s1PixelOffset = s1LineOffset; 438 int s2PixelOffset = s2LineOffset; 439 int dPixelOffset = dLineOffset; 440 441 s1LineOffset += s1LineStride; 442 s2LineOffset += s2LineStride; 443 dLineOffset += dLineStride; 444 445 int sum = 0; 446 for (int w = 0; w < dwidth; w++) { 447 // 448 // The next two lines are a fast way to do 449 // an add with saturation on U8 elements. 450 // It eliminates the need to do clamping. 451 // 452 sum = (s1[s1PixelOffset]&0xFF) + (s2[s2PixelOffset]&0xFF); 453 d[dPixelOffset] = ((((sum<<23) >> 31) | sum) & 0xFF); 454 455 s1PixelOffset += s1PixelStride; 456 s2PixelOffset += s2PixelStride; 457 dPixelOffset += dPixelStride; 458 } 459 } 460 } 461 break; 462 463 case DataBuffer.TYPE_USHORT: 464 for (int b = 0, s1b = 0, s2b = 0; b < bands; 465 b++, s1b += s1bd, s2b += s2bd) { 466 int[] s1 = s1Data[s1b]; 467 int[] s2 = s2Data[s2b]; 468 int[] d = dData[b]; 469 470 int s1LineOffset = s1BandOffsets[s1b]; 471 int s2LineOffset = s2BandOffsets[s2b]; 472 int dLineOffset = dBandOffsets[b]; 473 474 for (int h = 0; h < dheight; h++) { 475 int s1PixelOffset = s1LineOffset; 476 int s2PixelOffset = s2LineOffset; 477 int dPixelOffset = dLineOffset; 478 479 s1LineOffset += s1LineStride; 480 s2LineOffset += s2LineStride; 481 dLineOffset += dLineStride; 482 483 for (int w = 0; w < dwidth; w++) { 484 d[dPixelOffset] = ImageUtil.clampUShortPositive( 485 (int)(s1[s1PixelOffset]&0xFFFF) + 486 (int)(s2[s2PixelOffset]&0xFFFF)); 487 488 s1PixelOffset += s1PixelStride; 489 s2PixelOffset += s2PixelStride; 490 dPixelOffset += dPixelStride; 491 } 492 } 493 } 494 break; 495 496 case DataBuffer.TYPE_SHORT: 497 for (int b = 0, s1b = 0, s2b = 0; b < bands; 498 b++, s1b += s1bd, s2b += s2bd) { 499 int[] s1 = s1Data[s1b]; 500 int[] s2 = s2Data[s2b]; 501 int[] d = dData[b]; 502 503 int s1LineOffset = s1BandOffsets[s1b]; 504 int s2LineOffset = s2BandOffsets[s2b]; 505 int dLineOffset = dBandOffsets[b]; 506 507 for (int h = 0; h < dheight; h++) { 508 int s1PixelOffset = s1LineOffset; 509 int s2PixelOffset = s2LineOffset; 510 int dPixelOffset = dLineOffset; 511 512 s1LineOffset += s1LineStride; 513 s2LineOffset += s2LineStride; 514 dLineOffset += dLineStride; 515 516 for (int w = 0; w < dwidth; w++) { 517 d[dPixelOffset] = ImageUtil.clampShort((int)s1[s1PixelOffset] + 518 (int)s2[s2PixelOffset]); 519 520 s1PixelOffset += s1PixelStride; 521 s2PixelOffset += s2PixelStride; 522 dPixelOffset += dPixelStride; 523 } 524 } 525 } 526 break; 527 528 case DataBuffer.TYPE_INT: 529 for (int b = 0, s1b = 0, s2b = 0; b < bands; 530 b++, s1b += s1bd, s2b += s2bd) { 531 int[] s1 = s1Data[s1b]; 532 int[] s2 = s2Data[s2b]; 533 int[] d = dData[b]; 534 535 int s1LineOffset = s1BandOffsets[s1b]; 536 int s2LineOffset = s2BandOffsets[s2b]; 537 int dLineOffset = dBandOffsets[b]; 538 539 for (int h = 0; h < dheight; h++) { 540 int s1PixelOffset = s1LineOffset; 541 int s2PixelOffset = s2LineOffset; 542 int dPixelOffset = dLineOffset; 543 544 s1LineOffset += s1LineStride; 545 s2LineOffset += s2LineStride; 546 dLineOffset += dLineStride; 547 548 for (int w = 0; w < dwidth; w++) { 549 d[dPixelOffset] = ImageUtil.clampInt((long)s1[s1PixelOffset] + 550 (long)s2[s2PixelOffset]); 551 552 s1PixelOffset += s1PixelStride; 553 s2PixelOffset += s2PixelStride; 554 dPixelOffset += dPixelStride; 555 } 556 } 557 } 558 break; 559 } 560 } 561 computeRectFloat(RasterAccessor src1, RasterAccessor src2, RasterAccessor dst)562 private void computeRectFloat(RasterAccessor src1, 563 RasterAccessor src2, 564 RasterAccessor dst) { 565 int s1LineStride = src1.getScanlineStride(); 566 int s1PixelStride = src1.getPixelStride(); 567 int[] s1BandOffsets = src1.getBandOffsets(); 568 float[][] s1Data = src1.getFloatDataArrays(); 569 570 int s2LineStride = src2.getScanlineStride(); 571 int s2PixelStride = src2.getPixelStride(); 572 int[] s2BandOffsets = src2.getBandOffsets(); 573 float[][] s2Data = src2.getFloatDataArrays(); 574 575 int dwidth = dst.getWidth(); 576 int dheight = dst.getHeight(); 577 int bands = dst.getNumBands(); 578 int dLineStride = dst.getScanlineStride(); 579 int dPixelStride = dst.getPixelStride(); 580 int[] dBandOffsets = dst.getBandOffsets(); 581 float[][] dData = dst.getFloatDataArrays(); 582 583 for (int b = 0, s1b = 0, s2b = 0; b < bands; 584 b++, s1b += s1bd, s2b += s2bd) { 585 float[] s1 = s1Data[s1b]; 586 float[] s2 = s2Data[s2b]; 587 float[] d = dData[b]; 588 589 int s1LineOffset = s1BandOffsets[s1b]; 590 int s2LineOffset = s2BandOffsets[s2b]; 591 int dLineOffset = dBandOffsets[b]; 592 593 for (int h = 0; h < dheight; h++) { 594 int s1PixelOffset = s1LineOffset; 595 int s2PixelOffset = s2LineOffset; 596 int dPixelOffset = dLineOffset; 597 598 s1LineOffset += s1LineStride; 599 s2LineOffset += s2LineStride; 600 dLineOffset += dLineStride; 601 602 for (int w = 0; w < dwidth; w++) { 603 d[dPixelOffset] = s1[s1PixelOffset] + s2[s2PixelOffset]; 604 605 s1PixelOffset += s1PixelStride; 606 s2PixelOffset += s2PixelStride; 607 dPixelOffset += dPixelStride; 608 } 609 } 610 } 611 } 612 computeRectDouble(RasterAccessor src1, RasterAccessor src2, RasterAccessor dst)613 private void computeRectDouble(RasterAccessor src1, 614 RasterAccessor src2, 615 RasterAccessor dst) { 616 int s1LineStride = src1.getScanlineStride(); 617 int s1PixelStride = src1.getPixelStride(); 618 int[] s1BandOffsets = src1.getBandOffsets(); 619 double[][] s1Data = src1.getDoubleDataArrays(); 620 621 int s2LineStride = src2.getScanlineStride(); 622 int s2PixelStride = src2.getPixelStride(); 623 int[] s2BandOffsets = src2.getBandOffsets(); 624 double[][] s2Data = src2.getDoubleDataArrays(); 625 626 int dwidth = dst.getWidth(); 627 int dheight = dst.getHeight(); 628 int bands = dst.getNumBands(); 629 int dLineStride = dst.getScanlineStride(); 630 int dPixelStride = dst.getPixelStride(); 631 int[] dBandOffsets = dst.getBandOffsets(); 632 double[][] dData = dst.getDoubleDataArrays(); 633 634 for (int b = 0, s1b = 0, s2b = 0; b < bands; 635 b++, s1b += s1bd, s2b += s2bd) { 636 double[] s1 = s1Data[s1b]; 637 double[] s2 = s2Data[s2b]; 638 double[] d = dData[b]; 639 640 int s1LineOffset = s1BandOffsets[s1b]; 641 int s2LineOffset = s2BandOffsets[s2b]; 642 int dLineOffset = dBandOffsets[b]; 643 644 for (int h = 0; h < dheight; h++) { 645 int s1PixelOffset = s1LineOffset; 646 int s2PixelOffset = s2LineOffset; 647 int dPixelOffset = dLineOffset; 648 649 s1LineOffset += s1LineStride; 650 s2LineOffset += s2LineStride; 651 dLineOffset += dLineStride; 652 653 for (int w = 0; w < dwidth; w++) { 654 d[dPixelOffset] = s1[s1PixelOffset] + s2[s2PixelOffset]; 655 656 s1PixelOffset += s1PixelStride; 657 s2PixelOffset += s2PixelStride; 658 dPixelOffset += dPixelStride; 659 } 660 } 661 } 662 } 663 664 // public static void main(String args[]) { 665 // System.out.println("AddOpImage Test"); 666 // ImageLayout layout; 667 // OpImage src1, src2, dst; 668 // Rectangle rect = new Rectangle(0, 0, 5, 5); 669 670 // System.out.println("1. PixelInterleaved byte 3-band"); 671 // layout = OpImageTester.createImageLayout( 672 // 0, 0, 800, 800, 0, 0, 200, 200, DataBuffer.TYPE_BYTE, 3, false); 673 // src1 = OpImageTester.createRandomOpImage(layout); 674 // src2 = OpImageTester.createRandomOpImage(layout); 675 // dst = new AddOpImage(src1, src2, null, null); 676 // OpImageTester.testOpImage(dst, rect); 677 // OpImageTester.timeOpImage(dst, 10); 678 679 // System.out.println("2. Banded byte 3-band"); 680 // layout = OpImageTester.createImageLayout( 681 // 0, 0, 800, 800, 0, 0, 200, 200, DataBuffer.TYPE_BYTE, 3, true); 682 // src1 = OpImageTester.createRandomOpImage(layout); 683 // src2 = OpImageTester.createRandomOpImage(layout); 684 // dst = new AddOpImage(src1, src2, null, null); 685 // OpImageTester.testOpImage(dst, rect); 686 // OpImageTester.timeOpImage(dst, 10); 687 688 // System.out.println("3. PixelInterleaved int 3-band"); 689 // layout = OpImageTester.createImageLayout( 690 // 0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_INT, 3, false); 691 // src1 = OpImageTester.createRandomOpImage(layout); 692 // src2 = OpImageTester.createRandomOpImage(layout); 693 // dst = new AddOpImage(src1, src2, null, null); 694 // OpImageTester.testOpImage(dst, rect); 695 // OpImageTester.timeOpImage(dst, 10); 696 697 // System.out.println("4. Banded int 3-band"); 698 // layout = OpImageTester.createImageLayout( 699 // 0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_INT, 3, true); 700 // src1 = OpImageTester.createRandomOpImage(layout); 701 // src2 = OpImageTester.createRandomOpImage(layout); 702 // dst = new AddOpImage(src1, src2, null, null); 703 // OpImageTester.testOpImage(dst, rect); 704 // OpImageTester.timeOpImage(dst, 10); 705 706 // System.out.println("5. PixelInterleaved float 3-band"); 707 // layout = OpImageTester.createImageLayout( 708 // 0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_FLOAT, 3, false); 709 // src1 = OpImageTester.createRandomOpImage(layout); 710 // src2 = OpImageTester.createRandomOpImage(layout); 711 // dst = new AddOpImage(src1, src2, null, null); 712 // OpImageTester.testOpImage(dst, rect); 713 // OpImageTester.timeOpImage(dst, 10); 714 715 // System.out.println("6. Banded float 3-band"); 716 // layout = OpImageTester.createImageLayout( 717 // 0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_FLOAT, 3, true); 718 // src1 = OpImageTester.createRandomOpImage(layout); 719 // src2 = OpImageTester.createRandomOpImage(layout); 720 // dst = new AddOpImage(src1, src2, null, null); 721 // OpImageTester.testOpImage(dst, rect); 722 // OpImageTester.timeOpImage(dst, 10); 723 724 // System.out.println("7. PixelInterleaved double 3-band"); 725 // layout = OpImageTester.createImageLayout( 726 // 0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_DOUBLE, 3, false); 727 // src1 = OpImageTester.createRandomOpImage(layout); 728 // src2 = OpImageTester.createRandomOpImage(layout); 729 // dst = new AddOpImage(src1, src2, null, null); 730 // OpImageTester.testOpImage(dst, rect); 731 // OpImageTester.timeOpImage(dst, 10); 732 733 // System.out.println("8. Banded double 3-band"); 734 // layout = OpImageTester.createImageLayout( 735 // 0, 0, 512, 512, 0, 0, 200, 200, DataBuffer.TYPE_DOUBLE, 3, true); 736 // src1 = OpImageTester.createRandomOpImage(layout); 737 // src2 = OpImageTester.createRandomOpImage(layout); 738 // dst = new AddOpImage(src1, src2, null, null); 739 // OpImageTester.testOpImage(dst, rect); 740 // OpImageTester.timeOpImage(dst, 10); 741 // } 742 } 743