1 /* 2 * $RCSfile: RasterAccessor.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:57:18 $ 10 * $State: Exp $ 11 */ 12 package com.lightcrafts.mediax.jai; 13 import java.awt.image.SampleModel; 14 import java.awt.image.ComponentSampleModel; 15 import java.awt.image.DataBuffer; 16 import java.awt.image.DataBufferByte; 17 import java.awt.image.DataBufferUShort; 18 import java.awt.image.DataBufferShort; 19 import java.awt.image.DataBufferInt; 20 import java.awt.image.Raster; 21 import java.awt.image.WritableRaster; 22 import java.awt.Rectangle; 23 import java.awt.image.RenderedImage; 24 import java.awt.image.ColorModel; 25 import java.awt.image.IndexColorModel; 26 import java.awt.image.ComponentColorModel; 27 import com.lightcrafts.media.jai.util.DataBufferUtils; 28 import com.lightcrafts.media.jai.util.ImageUtil; 29 30 /** 31 * An adapter class for presenting non-binary image data in a 32 * <code>ComponentSampleModel</code> format and binary image data in 33 * a zero-offset byte array format even when the original data are not 34 * so stored. <code>RasterAccessor</code> is meant to make the common 35 * (<code>ComponentSampleModel</code>) case fast and other formats 36 * possible without forcing the <code>OpImage</code> writer to cover more 37 * than one case per non-binary data type. 38 * 39 * <p>When constructing a <code>RasterAccessor</code> with a source(s) that 40 * has an IndexColorModel and a destination that has a 41 * non-<code>IndexColorModel</code>, <code>RasterAccessor</code> will 42 * perform expansion of the source pixels. If the source(s) and the 43 * destination have an IndexColorModel, then <code>RasterAccessor</code> 44 * will assume that the operation can correctly process an IndexColorModel 45 * source and will not expand the source pixels (colormap indices) into 46 * color components. Refer to {@link JAI#KEY_REPLACE_INDEX_COLOR_MODEL} 47 * for a mechanism by which the destination image's <code>ColorModel</code> 48 * is set to a non-<code>IndexColorModel</code> to cause 49 * <code>RasterAccessor</code> to expand the source's 50 * <code>IndexColorModel</code>. 51 * 52 * <p> Binary data are handled as a special case. In general image data 53 * are considered to be binary when the image has a single-banded 54 * <code>MultiPixelPackedSampleModel</code> with one bit per pixel. This 55 * may be verified by invoking the <code>isBinary()</code> method. For this 56 * case the methods <code>getBinaryDataArray()</code> and 57 * <code>copyBinaryDataToRaster()</code> should be used to access and set, 58 * respectively, the binary data in packed form. If the binary data are 59 * to be accessed in expanded form, i.e., as bytes, then the usual byte 60 * methods <code>getByteDataArray()</code>, <code>getByteDataArrays()</code>, 61 * and <code>copyDataToRaster()</code> should be used. 62 * 63 */ 64 public class RasterAccessor { 65 66 /** 67 * Value indicating how far COPY_MASK info is shifted to avoid 68 * interfering with the data type info. 69 */ 70 private static final int COPY_MASK_SHIFT = 7; 71 72 /* Value indicating how many bits the COPY_MASK is */ 73 private static final int COPY_MASK_SIZE = 2; 74 75 /** The bits of a FormatTag associated with how dataArrays are obtained. */ 76 public static final int COPY_MASK = 77 ((1 << COPY_MASK_SIZE) - 1) << COPY_MASK_SHIFT; 78 79 /** Flag indicating data is raster's data. */ 80 public static final int UNCOPIED = 0x0 << COPY_MASK_SHIFT; 81 82 /** Flag indicating data is a copy of the raster's data. */ 83 public static final int COPIED = 0x1 << COPY_MASK_SHIFT; 84 85 /** 86 * Value indicating how far EXPANSION_MASK info is shifted to avoid 87 * interfering with the data type info. 88 */ 89 private static final int EXPANSION_MASK_SHIFT = 90 COPY_MASK_SHIFT+COPY_MASK_SIZE; 91 92 /** Value indicating how many bits the EXPANSION_MASK is */ 93 private static final int EXPANSION_MASK_SIZE = 2; 94 95 /** The bits of a FormatTag associated with how ColorModels are used. */ 96 public static final int EXPANSION_MASK = 97 ((1 << EXPANSION_MASK_SIZE) - 1) << EXPANSION_MASK_SHIFT; 98 99 /** Flag indicating ColorModel data should be used only in copied case */ 100 public static final int DEFAULTEXPANSION = 0x0 << EXPANSION_MASK_SHIFT; 101 102 /** Flag indicating ColorModel data should be interpreted. */ 103 public static final int EXPANDED = 0x1 << EXPANSION_MASK_SHIFT; 104 105 /** Flag indicating ColorModel info should be ignored */ 106 public static final int UNEXPANDED = 0x02 << EXPANSION_MASK_SHIFT; 107 108 /** The bits of a FormatTagID associated with pixel datatype. */ 109 public static final int DATATYPE_MASK = (0x1 << COPY_MASK_SHIFT) - 1; 110 111 /** FormatTagID indicating data in byte arrays and uncopied. */ 112 public static final int 113 TAG_BYTE_UNCOPIED = DataBuffer.TYPE_BYTE | UNCOPIED; 114 115 /** FormatTagID indicating data in unsigned short arrays and uncopied. */ 116 public static final int 117 TAG_USHORT_UNCOPIED = DataBuffer.TYPE_USHORT | UNCOPIED; 118 119 /** FormatTagID indicating data in short arrays and uncopied. */ 120 public static final int 121 TAG_SHORT_UNCOPIED = DataBuffer.TYPE_SHORT | UNCOPIED; 122 123 /** FormatTagID indicating data in int arrays and uncopied. */ 124 public static final int 125 TAG_INT_UNCOPIED = DataBuffer.TYPE_INT | UNCOPIED; 126 127 /** FormatTagID indicating data in float arrays and uncopied. */ 128 public static final int 129 TAG_FLOAT_UNCOPIED = DataBuffer.TYPE_FLOAT | UNCOPIED; 130 131 /** FormatTagID indicating data in double arrays and uncopied. */ 132 public static final int 133 TAG_DOUBLE_UNCOPIED = DataBuffer.TYPE_DOUBLE | UNCOPIED; 134 135 /** FormatTagID indicating data in int arrays and copied. */ 136 public static final int 137 TAG_INT_COPIED = DataBuffer.TYPE_INT | COPIED; 138 139 /** FormatTagID indicating data in float arrays and copied. */ 140 public static final int 141 TAG_FLOAT_COPIED = DataBuffer.TYPE_FLOAT | COPIED; 142 143 /** FormatTagID indicating data in double arrays and copied. */ 144 public static final int 145 TAG_DOUBLE_COPIED = DataBuffer.TYPE_DOUBLE | COPIED; 146 147 /** FormatTagID indicating data in byte arrays and expanded. */ 148 public static final int 149 TAG_BYTE_EXPANDED = DataBuffer.TYPE_BYTE | EXPANDED; 150 151 /** 152 * FormatTagID corresponding to the binary case. This occurs when 153 * the image has a <code>MultiPixelPackedSampleModel</code> with a 154 * single band and one bit per pixel. 155 */ 156 private static final int TAG_BINARY = 157 DataBuffer.TYPE_BYTE | COPIED | UNEXPANDED; 158 159 /** The raster that is the source of pixel data. */ 160 protected Raster raster; 161 162 /** The width of the rectangle this RasterAccessor addresses. */ 163 protected int rectWidth; 164 165 /** The height of the rectangle this RasterAccessor addresses. */ 166 protected int rectHeight; 167 168 /** The x coordinate of upper-left corner of the rectangle this 169 * RasterAccessor addresses. 170 */ 171 protected int rectX; 172 173 /** The y coordinate of upper-left corner of the rectangle this 174 * RasterAccessor addresses. 175 */ 176 protected int rectY; 177 178 /** Tag indicating the data type of the data and whether it's copied */ 179 protected int formatTagID; 180 181 /** 182 * The image data for the binary case. The data will be packed as 183 * eight bits per byte with no bit offset, i.e., the first bit in each 184 * image line will be the left-most bit of the first byte of the line. 185 * The line stride in bytes will be <code>(int)((rectWidth+7)/8)</code>. 186 * The length of the array will be <code>rectHeight</code> multiplied 187 * by the line stride. 188 * 189 * @since JAI 1.1 190 */ 191 protected byte binaryDataArray[] = null; 192 193 /** 194 * The image data in a two-dimensional byte array. This 195 * value will be non-null only if getDataType() returns 196 * DataBuffer.TYPE_BYTE. byteDataArrays.length will equal 197 * numBands. Note that often the numBands subArrays will all 198 * point to the same place in memory. 199 * 200 * <p> For the case of binary data this variable will not be initialized 201 * until <code>getByteDataArrays()</code> or 202 * <code>getByteDataArray(int b)</code> is invoked. 203 */ 204 protected byte byteDataArrays[][] = null; 205 206 /** 207 * The image data in a two-dimensional short array. This 208 * value will be non-null only if getDataType() returns 209 * DataBuffer.TYPE_USHORT or DataBuffer.TYPE_SHORT. 210 * shortDataArrays.length will equal 211 * numBands. Note that often the numBands subArrays will all 212 * point to the same place in memory. 213 */ 214 protected short shortDataArrays[][] = null; 215 216 /** 217 * The image data in a two-dimensional int array. This 218 * value will be non-null only if getDataType() returns 219 * DataBuffer.TYPE_INT. intDataArrays.length will equal 220 * numBands. Note that often the numBands subArrays will all 221 * point to the same place in memory. 222 */ 223 protected int intDataArrays[][] = null; 224 225 /** 226 * The image data in a two-dimensional float array. This 227 * value will be non-null only if getDataType() returns 228 * DataBuffer.TYPE_FLOAT. floatDataArrays.length will equal 229 * numBands. Note that often the numBand subArrays will all 230 * point to the same place in memory. 231 */ 232 protected float floatDataArrays[][] = null; 233 234 /** 235 * The image data in a two-dimensional double array. This 236 * value will be non-null only if getDataType() returns 237 * DataBuffer.TYPE_DOUBLE. doubleDataArrays.length will equal 238 * numBands. Note that often the numBand subArrays will all 239 * point to the same place in memory. 240 */ 241 protected double doubleDataArrays[][] = null; 242 243 /** 244 * The bandOffset + subRasterOffset + DataBufferOffset into each of 245 * the numBand data arrays 246 */ 247 protected int bandDataOffsets[]; 248 249 /** Offset from a pixel's offset to a band of that pixel */ 250 protected int bandOffsets[]; 251 252 /** The number of bands per pixel in the data array. */ 253 protected int numBands; 254 255 /** The scanline stride of the image data in each data array */ 256 protected int scanlineStride; 257 258 /** The pixel stride of the image data in each data array */ 259 protected int pixelStride; 260 261 /** 262 * Finds the appropriate tags for the constructor, based on the 263 * SampleModel and ColorModel of all the source and destination. 264 * 265 * @param srcs The operations sources; may be <code>null</code> which 266 * is taken to be equivalent to zero sources. 267 * @param dst The operation destination. 268 * @return An array containing <code>RasterFormatTag</code>s for the 269 * sources in the first src.length elements and a 270 * <code>RasterFormatTag</code> for the destination in the last element. 271 * @throws NullPointerException if <code>dst</code> is <code>null</code>. 272 */ 273 public static findCompatibleTags(RenderedImage srcs[], RenderedImage dst)274 RasterFormatTag[] findCompatibleTags(RenderedImage srcs[], 275 RenderedImage dst) { 276 int tagIDs[]; 277 if (srcs != null) { 278 tagIDs = new int[srcs.length + 1]; 279 } else { 280 tagIDs = new int[1]; 281 } 282 SampleModel dstSampleModel = dst.getSampleModel(); 283 int dstDataType = dstSampleModel.getTransferType(); 284 285 int defaultDataType = dstDataType; 286 boolean binaryDst = ImageUtil.isBinary(dstSampleModel); 287 if (binaryDst) { 288 defaultDataType = DataBuffer.TYPE_BYTE; 289 } else if((dstDataType == DataBuffer.TYPE_BYTE) || 290 (dstDataType == DataBuffer.TYPE_USHORT) || 291 (dstDataType == DataBuffer.TYPE_SHORT)) { 292 defaultDataType = DataBuffer.TYPE_INT; 293 } 294 295 // use highest precision datatype of all srcs & dst 296 if (srcs != null) { 297 int numSources = srcs.length; 298 int i; 299 for (i = 0; i < numSources; i++) { 300 SampleModel srcSampleModel = srcs[i].getSampleModel(); 301 int srcDataType = srcSampleModel.getTransferType(); 302 if (!(binaryDst && ImageUtil.isBinary(srcSampleModel)) && 303 srcDataType > defaultDataType) { 304 defaultDataType = srcDataType; 305 } 306 } 307 } 308 309 // Set the tag. For binary data at this point this should 310 // equal DataBuffer.TYPE_BYTE | COPIED. 311 int tagID = defaultDataType | COPIED; 312 313 if (dstSampleModel instanceof ComponentSampleModel) { 314 if (srcs != null) { 315 int numSources = srcs.length; 316 int i; 317 for (i = 0; i < numSources; i++) { 318 SampleModel srcSampleModel = srcs[i].getSampleModel(); 319 int srcDataType = srcSampleModel.getTransferType(); 320 if (!(srcSampleModel instanceof ComponentSampleModel) || 321 (srcDataType != dstDataType)) { 322 break; 323 } 324 } 325 if (i == numSources) { 326 tagID = dstDataType | UNCOPIED; 327 } 328 } else { 329 tagID = dstDataType | UNCOPIED; 330 } 331 } 332 333 // If the source has an IndexColorModel but the dest does not, 334 // perform expansion of the source pixels. If both have an 335 // IndexColorModel, assume the operation knows what it is doing. 336 RasterFormatTag rft[] = new RasterFormatTag[tagIDs.length]; 337 if (srcs != null) { 338 for (int i = 0; i < srcs.length; i++) { 339 // dst can't be EXPANDED 340 if ((srcs[i].getColorModel() instanceof IndexColorModel)) { 341 if (dst.getColorModel() instanceof IndexColorModel) { 342 tagIDs[i] = tagID | UNEXPANDED; 343 } else { 344 tagIDs[i] = tagID | EXPANDED; 345 } 346 } else if (srcs[i].getColorModel() instanceof 347 ComponentColorModel || 348 (binaryDst && 349 ImageUtil.isBinary(srcs[i].getSampleModel()))){ 350 tagIDs[i] = tagID | UNEXPANDED; 351 } else { 352 tagIDs[i] = tagID | DEFAULTEXPANSION; 353 } 354 } 355 tagIDs[srcs.length] = tagID | UNEXPANDED; 356 357 for (int i = 0; i < srcs.length; i++) { 358 rft[i] = 359 new RasterFormatTag(srcs[i].getSampleModel(), tagIDs[i]); 360 } 361 // get the dest 362 rft[srcs.length] = 363 new RasterFormatTag(dstSampleModel,tagIDs[srcs.length]); 364 } else { // no sources, dest only 365 rft[0] = new RasterFormatTag(dstSampleModel, tagID | UNEXPANDED); 366 } 367 368 return rft; 369 } 370 371 /** 372 * Returns the most efficient FormatTagID that is compatible with 373 * the destination SampleModel and all source SampleModels. 374 * Since there is no <code>ColorModel</code> associated with 375 * a <code>SampleModel</code>, this method does not expand the data 376 * buffer as it has no access to the Raster's ColorModel. 377 */ findCompatibleTag(SampleModel[] srcSampleModels, SampleModel dstSampleModel)378 public static int findCompatibleTag(SampleModel[] srcSampleModels, 379 SampleModel dstSampleModel) { 380 int dstDataType = dstSampleModel.getTransferType(); 381 382 int tag = dstDataType | COPIED; 383 if (ImageUtil.isBinary(dstSampleModel)) { 384 tag = DataBuffer.TYPE_BYTE | COPIED; 385 } else if (dstDataType == DataBuffer.TYPE_BYTE || 386 dstDataType == DataBuffer.TYPE_USHORT || 387 dstDataType == DataBuffer.TYPE_SHORT) { 388 tag = TAG_INT_COPIED; 389 } 390 391 if (dstSampleModel instanceof ComponentSampleModel) { 392 if (srcSampleModels != null) { 393 int numSources = srcSampleModels.length; 394 int i; 395 for (i = 0; i < numSources; i++) { 396 int srcDataType = srcSampleModels[i].getTransferType(); 397 398 if (!(srcSampleModels[i] instanceof ComponentSampleModel) || 399 srcDataType != dstDataType) { 400 break; 401 } 402 } 403 if (i == numSources) { 404 tag = dstDataType | UNCOPIED; 405 } 406 } else { 407 tag = dstDataType | UNCOPIED; 408 } 409 } 410 return tag | UNEXPANDED; // only called when colormodel not around 411 // so never expand 412 } 413 414 415 /** 416 * Constructs a RasterAccessor object out of a Raster, Rectangle 417 * and formatTagID returned from RasterFormat.findCompatibleTag(). 418 * 419 * <p> The <code>RasterFormatTag</code> must agree with the raster's 420 * <code>SampleModel</code> and <code>ColorModel</code>. It is best 421 * to obtain the correct tag using the <code>findCompatibleTags</code> 422 * static method. 423 * 424 * @param raster The raster to be accessed 425 * @param rect A <code>Rectangle</code> from the raster to be accessed 426 * @param rft The <code>RasterFormatTag</code> associated with the Raster 427 * @param theColorModel The <code>ColorModel</code> for color components 428 * 429 * @throws ClassCastException if the data type of 430 * <code>RasterFormatTag</code> does not agree with the actual 431 * data type of the <code>Raster</code>. 432 * @throws IllegalArgumentException if <code>raster</code>, 433 * <code>rect</code>, or <code>rft</code> is <code>null</code>. 434 * @throws IllegalArgumentException if the <code>Rectangle</code> 435 * is not contained within <code>Raster</code>'s bounds. 436 */ RasterAccessor(Raster raster, Rectangle rect, RasterFormatTag rft, ColorModel theColorModel)437 public RasterAccessor(Raster raster, 438 Rectangle rect, 439 RasterFormatTag rft, 440 ColorModel theColorModel) { 441 442 if(raster == null || rect == null || rft == null) { 443 throw new IllegalArgumentException(JaiI18N.getString("Generic0")); 444 } 445 446 // If requesting a region that lies outside the bounds, 447 // throw an exception. 448 if (!raster.getBounds().contains(rect)) { 449 throw new IllegalArgumentException( 450 JaiI18N.getString("RasterAccessor2")); 451 } 452 453 this.raster = raster; 454 this.rectX = rect.x; 455 this.rectY = rect.y; 456 this.rectWidth = rect.width; 457 this.rectHeight = rect.height; 458 this.formatTagID = rft.getFormatTagID(); 459 if ((formatTagID & COPY_MASK) == UNCOPIED) { 460 461 this.numBands = rft.getNumBands(); 462 this.pixelStride = rft.getPixelStride(); 463 464 ComponentSampleModel csm = 465 (ComponentSampleModel)raster.getSampleModel(); 466 this.scanlineStride = csm.getScanlineStride(); 467 468 int bankIndices[] = null; 469 470 // if the rft isPixelSequential we can rely on it's 471 // version of bandOffsets and bankIndicies. If it's 472 // not the SampleModel passed in might not completely 473 // match the one that was passed to the the 474 // RasterFormatTag constructor so we have to get them 475 // from the passed in Raster/SampleModel 476 if (rft.isPixelSequential()) { 477 this.bandOffsets = rft.getBandOffsets(); 478 bankIndices = rft.getBankIndices(); 479 } else { 480 this.bandOffsets = csm.getBandOffsets(); 481 bankIndices = csm.getBankIndices(); 482 } 483 484 this.bandDataOffsets = new int[numBands]; 485 486 int dataBufferOffsets[] = raster.getDataBuffer().getOffsets(); 487 488 int subRasterOffset = 489 (rectY-raster.getSampleModelTranslateY())*scanlineStride+ 490 (rectX-raster.getSampleModelTranslateX())*pixelStride; 491 492 if (dataBufferOffsets.length == 1) { 493 int theDataBufferOffset = dataBufferOffsets[0]; 494 for (int i = 0; i < numBands; i++) { 495 bandDataOffsets[i] = bandOffsets[i] + 496 theDataBufferOffset + subRasterOffset; 497 } 498 } else if (dataBufferOffsets.length == bandDataOffsets.length) { 499 for (int i = 0; i < numBands; i++) { 500 bandDataOffsets[i] = bandOffsets[i] + 501 dataBufferOffsets[i] + subRasterOffset; 502 } 503 } else { 504 throw new RuntimeException(JaiI18N.getString("RasterAccessor0")); 505 } 506 507 switch (formatTagID & DATATYPE_MASK) { 508 case DataBuffer.TYPE_BYTE: 509 DataBufferByte dbb = (DataBufferByte)raster.getDataBuffer(); 510 byteDataArrays = new byte[numBands][]; 511 for (int i = 0; i < numBands; i++) { 512 byteDataArrays[i] = dbb.getData(bankIndices[i]); 513 } 514 break; 515 516 case DataBuffer.TYPE_USHORT: 517 DataBufferUShort dbus = 518 (DataBufferUShort)raster.getDataBuffer(); 519 shortDataArrays = new short[numBands][]; 520 for (int i = 0; i < numBands; i++) { 521 shortDataArrays[i] = dbus.getData(bankIndices[i]); 522 } 523 break; 524 525 case DataBuffer.TYPE_SHORT: 526 DataBufferShort dbs = (DataBufferShort)raster.getDataBuffer(); 527 shortDataArrays = new short[numBands][]; 528 for (int i = 0; i < numBands; i++) { 529 shortDataArrays[i] = dbs.getData(bankIndices[i]); 530 } 531 break; 532 533 case DataBuffer.TYPE_INT: 534 DataBufferInt dbi = (DataBufferInt)raster.getDataBuffer(); 535 intDataArrays = new int[numBands][]; 536 for (int i = 0; i < numBands; i++) { 537 intDataArrays[i] = dbi.getData(bankIndices[i]); 538 } 539 break; 540 541 case DataBuffer.TYPE_FLOAT: 542 DataBuffer dbf = (DataBuffer)raster.getDataBuffer(); 543 floatDataArrays = new float[numBands][]; 544 for (int i = 0; i < numBands; i++) { 545 floatDataArrays[i] = 546 DataBufferUtils.getDataFloat(dbf, bankIndices[i]); 547 } 548 break; 549 550 case DataBuffer.TYPE_DOUBLE: 551 DataBuffer dbd = (DataBuffer)raster.getDataBuffer(); 552 doubleDataArrays = new double[numBands][]; 553 for (int i = 0; i < numBands; i++) { 554 doubleDataArrays[i] = 555 DataBufferUtils.getDataDouble(dbd, bankIndices[i]); 556 } 557 break; 558 } 559 // only do this if not copied and expanded 560 if ((formatTagID & EXPANSION_MASK) == EXPANDED && 561 theColorModel instanceof IndexColorModel) { 562 IndexColorModel icm = (IndexColorModel)theColorModel; 563 564 int newNumBands = icm.getNumComponents(); 565 566 int mapSize = icm.getMapSize(); 567 int newBandDataOffsets[] = new int[newNumBands]; 568 int newScanlineStride = rectWidth*newNumBands; 569 int newPixelStride = newNumBands; 570 byte ctable[][] = new byte[newNumBands][mapSize]; 571 572 icm.getReds(ctable[0]); 573 icm.getGreens(ctable[1]); 574 icm.getBlues(ctable[2]); 575 byte rtable[] = ctable[0]; 576 byte gtable[] = ctable[1]; 577 byte btable[] = ctable[2]; 578 579 byte atable[] = null; 580 if (newNumBands == 4) { 581 icm.getAlphas(ctable[3]); 582 atable = ctable[3]; 583 } 584 585 for (int i = 0; i < newNumBands; i++) { 586 newBandDataOffsets[i] = i; 587 } 588 589 switch (formatTagID & DATATYPE_MASK) { 590 case DataBuffer.TYPE_BYTE: { 591 byte newBArray[] = 592 new byte[rectWidth*rectHeight*newNumBands]; 593 byte byteDataArray[] = byteDataArrays[0]; 594 int scanlineOffset = bandDataOffsets[0]; 595 int newScanlineOffset = 0; 596 for (int j = 0; j < rectHeight; j++) { 597 int pixelOffset = scanlineOffset; 598 int newPixelOffset = newScanlineOffset; 599 for (int i = 0; i < rectWidth; i++) { 600 int index = byteDataArray[pixelOffset] & 0xff; 601 for (int k = 0; k < newNumBands; k++) { 602 newBArray[newPixelOffset+k] = 603 ctable[k][index]; 604 } 605 pixelOffset += pixelStride; 606 newPixelOffset += newPixelStride; 607 } 608 scanlineOffset += scanlineStride; 609 newScanlineOffset += newScanlineStride; 610 } 611 byteDataArrays = new byte[newNumBands][]; 612 for (int i = 0; i < newNumBands; i++) { 613 byteDataArrays[i] = newBArray; 614 } 615 } 616 break; 617 618 case DataBuffer.TYPE_USHORT: { 619 short newIArray[] = 620 new short[rectWidth*rectHeight*newNumBands]; 621 short shortDataArray[] = shortDataArrays[0]; 622 int scanlineOffset = bandDataOffsets[0]; 623 int newScanlineOffset = 0; 624 for (int j = 0; j < rectHeight; j++) { 625 int pixelOffset = scanlineOffset; 626 int newPixelOffset = newScanlineOffset; 627 for (int i = 0; i < rectWidth; i++) { 628 int index = (shortDataArray[pixelOffset] & 0xffff); 629 for (int k = 0; k < newNumBands; k++) { 630 newIArray[newPixelOffset+k] = 631 (short)(ctable[k][index] & 0xff); 632 } 633 pixelOffset += pixelStride; 634 newPixelOffset += newPixelStride; 635 } 636 scanlineOffset += scanlineStride; 637 newScanlineOffset += newScanlineStride; 638 } 639 640 shortDataArrays = new short[newNumBands][]; 641 for (int i = 0; i < newNumBands; i++) { 642 shortDataArrays[i] = newIArray; 643 } 644 } 645 break; 646 647 case DataBuffer.TYPE_SHORT: { 648 short newIArray[] = 649 new short[rectWidth*rectHeight*newNumBands]; 650 short shortDataArray[] = shortDataArrays[0]; 651 int scanlineOffset = bandDataOffsets[0]; 652 int newScanlineOffset = 0; 653 for (int j = 0; j < rectHeight; j++) { 654 int pixelOffset = scanlineOffset; 655 int newPixelOffset = newScanlineOffset; 656 for (int i = 0; i < rectWidth; i++) { 657 int index = shortDataArray[pixelOffset]; 658 for (int k = 0; k < newNumBands; k++) { 659 newIArray[newPixelOffset+k] = 660 (short)(ctable[k][index] & 0xff); 661 } 662 pixelOffset += pixelStride; 663 newPixelOffset += newPixelStride; 664 } 665 scanlineOffset += scanlineStride; 666 newScanlineOffset += newScanlineStride; 667 } 668 669 shortDataArrays = new short[newNumBands][]; 670 for (int i = 0; i < newNumBands; i++) { 671 shortDataArrays[i] = newIArray; 672 } 673 } 674 break; 675 676 case DataBuffer.TYPE_INT: { 677 int newIArray[] = 678 new int[rectWidth*rectHeight*newNumBands]; 679 int intDataArray[] = intDataArrays[0]; 680 int scanlineOffset = bandDataOffsets[0]; 681 int newScanlineOffset = 0; 682 for (int j = 0; j < rectHeight; j++) { 683 int pixelOffset = scanlineOffset; 684 int newPixelOffset = newScanlineOffset; 685 for (int i = 0; i < rectWidth; i++) { 686 int index = intDataArray[pixelOffset]; 687 for (int k = 0; k < newNumBands; k++) { 688 newIArray[newPixelOffset+k] = 689 (ctable[k][index] & 0xff); 690 } 691 pixelOffset += pixelStride; 692 newPixelOffset += newPixelStride; 693 } 694 scanlineOffset += scanlineStride; 695 newScanlineOffset += newScanlineStride; 696 } 697 698 intDataArrays = new int[newNumBands][]; 699 for (int i = 0; i < newNumBands; i++) { 700 intDataArrays[i] = newIArray; 701 } 702 } 703 break; 704 705 case DataBuffer.TYPE_FLOAT: { 706 float newFArray[] = 707 new float[rectWidth*rectHeight*newNumBands]; 708 float floatDataArray[] = floatDataArrays[0]; 709 int scanlineOffset = bandDataOffsets[0]; 710 int newScanlineOffset = 0; 711 for (int j = 0; j < rectHeight; j++) { 712 int pixelOffset = scanlineOffset; 713 int newPixelOffset = newScanlineOffset; 714 for (int i = 0; i < rectWidth; i++) { 715 int index = (int)floatDataArray[pixelOffset]; 716 for (int k = 0; k < newNumBands; k++) { 717 newFArray[newPixelOffset+k] = 718 (ctable[k][index] & 0xff); 719 } 720 pixelOffset += pixelStride; 721 newPixelOffset += newPixelStride; 722 } 723 scanlineOffset += scanlineStride; 724 newScanlineOffset += newScanlineStride; 725 } 726 floatDataArrays = new float[newNumBands][]; 727 for (int i = 0; i < newNumBands; i++) { 728 floatDataArrays[i] = newFArray; 729 } 730 } 731 break; 732 733 case DataBuffer.TYPE_DOUBLE: { 734 double newDArray[] = 735 new double[rectWidth*rectHeight*newNumBands]; 736 double doubleDataArray[] = doubleDataArrays[0]; 737 int scanlineOffset = bandDataOffsets[0]; 738 int newScanlineOffset = 0; 739 for (int j = 0; j < rectHeight; j++) { 740 int pixelOffset = scanlineOffset; 741 int newPixelOffset = newScanlineOffset; 742 for (int i = 0; i < rectWidth; i++) { 743 int index = (int)doubleDataArray[pixelOffset]; 744 for (int k = 0; k < newNumBands; k++) { 745 newDArray[newPixelOffset+k] = 746 (ctable[k][index] & 0xff); 747 } 748 pixelOffset += pixelStride; 749 newPixelOffset += newPixelStride; 750 } 751 scanlineOffset += scanlineStride; 752 newScanlineOffset += newScanlineStride; 753 } 754 doubleDataArrays = new double[newNumBands][]; 755 for (int i = 0; i < newNumBands; i++) { 756 doubleDataArrays[i] = newDArray; 757 } 758 } 759 break; 760 } 761 this.numBands = newNumBands; 762 this.pixelStride = newPixelStride; 763 this.scanlineStride = newScanlineStride; 764 this.bandDataOffsets = newBandDataOffsets; 765 this.bandOffsets = newBandDataOffsets; 766 } 767 } else if ((formatTagID & COPY_MASK) == COPIED && 768 (formatTagID & EXPANSION_MASK) != UNEXPANDED && 769 theColorModel != null) { 770 this.numBands = theColorModel instanceof IndexColorModel ? 771 theColorModel.getNumComponents() : 772 raster.getSampleModel().getNumBands(); 773 this.pixelStride = this.numBands; 774 this.scanlineStride = rectWidth*numBands; 775 this.bandOffsets = new int[numBands]; 776 777 for (int i = 0; i < numBands; i++) { 778 bandOffsets[i] = i; 779 } 780 this.bandDataOffsets = bandOffsets; 781 782 Object odata = null; 783 int offset = 0; 784 785 int[] components = new int[theColorModel.getNumComponents()]; 786 787 switch (formatTagID & DATATYPE_MASK) { 788 789 case DataBuffer.TYPE_INT: 790 int idata[] = new int[rectWidth*rectHeight*numBands]; 791 intDataArrays = new int[numBands][]; 792 for (int i = 0; i < numBands; i++) { 793 intDataArrays[i] = idata; 794 } 795 796 odata = raster.getDataElements(rectX, rectY, null); 797 offset = 0; 798 799 for (int j = rectY; j < rectY+rectHeight; j++) { 800 for (int i = rectX; i < rectX+rectWidth; i++) { 801 raster.getDataElements(i,j,odata); 802 803 theColorModel.getComponents(odata, components, 0); 804 805 idata[offset] = components[0]; 806 idata[offset+1] = components[1]; 807 idata[offset+2] = components[2]; 808 if (numBands > 3) { 809 idata[offset+3] = components[3]; 810 } 811 812 offset += pixelStride; 813 } 814 } 815 break; 816 817 case DataBuffer.TYPE_FLOAT: 818 float fdata[] = new float[rectWidth*rectHeight*numBands]; 819 floatDataArrays = new float[numBands][]; 820 for (int i = 0; i < numBands; i++) { 821 floatDataArrays[i] = fdata; 822 } 823 odata = null; 824 offset = 0; 825 for (int j = rectY; j < rectY+rectHeight; j++) { 826 for (int i = rectX; i < rectX+rectWidth; i++) { 827 odata = raster.getDataElements(i,j,odata); 828 829 theColorModel.getComponents(odata, components, 0); 830 831 fdata[offset] = components[0]; 832 fdata[offset+1] = components[1]; 833 fdata[offset+2] = components[2]; 834 if (numBands > 3) { 835 fdata[offset+3] = components[3]; 836 } 837 offset += pixelStride; 838 } 839 } 840 break; 841 842 case DataBuffer.TYPE_DOUBLE: 843 double ddata[] = new double[rectWidth*rectHeight*numBands]; 844 doubleDataArrays = new double[numBands][]; 845 for (int i = 0; i < numBands; i++) { 846 doubleDataArrays[i] = ddata; 847 } 848 odata = null; 849 offset = 0; 850 for (int j = rectY; j < rectY+rectHeight; j++) { 851 for (int i = rectX; i < rectX+rectWidth; i++) { 852 odata = raster.getDataElements(i,j,odata); 853 854 theColorModel.getComponents(odata, components, 0); 855 856 ddata[offset] = components[0]; 857 ddata[offset+1] = components[1]; 858 ddata[offset+2] = components[2]; 859 if (numBands > 3) { 860 ddata[offset+3] = components[3]; 861 } 862 offset += pixelStride; 863 } 864 } 865 break; 866 } 867 } else { 868 // if ((formatTagID & COPY_MASK) == COPIED && 869 // (formatTagID & EXPANSION_MASK) == UNEXPANDED) { 870 // this has become a catchall case. Specifically for 871 // Rasters with null colormodels. So we take out the 872 // if as the boolean clause will get way complicated 873 // otherwise. 874 this.numBands = rft.getNumBands(); 875 this.pixelStride = this.numBands; 876 this.scanlineStride = rectWidth*numBands; 877 this.bandDataOffsets = rft.getBandOffsets(); 878 this.bandOffsets = this.bandDataOffsets; 879 880 switch (formatTagID & DATATYPE_MASK) { 881 case DataBuffer.TYPE_INT: 882 int idata[] = raster.getPixels(rectX,rectY, 883 rectWidth,rectHeight, 884 (int[])null); 885 intDataArrays = new int[numBands][]; 886 for (int i = 0; i < numBands; i++) { 887 intDataArrays[i] = idata; 888 } 889 break; 890 891 case DataBuffer.TYPE_FLOAT: 892 float fdata[] = raster.getPixels(rectX,rectY, 893 rectWidth,rectHeight, 894 (float[])null); 895 floatDataArrays = new float[numBands][]; 896 for (int i = 0; i < numBands; i++) { 897 floatDataArrays[i] = fdata; 898 } 899 break; 900 901 case DataBuffer.TYPE_DOUBLE: 902 double ddata[] = raster.getPixels(rectX,rectY, 903 rectWidth,rectHeight, 904 (double[])null); 905 doubleDataArrays = new double[numBands][]; 906 for (int i = 0; i < numBands; i++) { 907 doubleDataArrays[i] = ddata; 908 } 909 break; 910 } 911 } 912 } 913 914 /** 915 * Returns the x coordinate of the upper-left corner of the 916 * RasterAccessor's accessible area. 917 */ getX()918 public int getX() { 919 return rectX; 920 } 921 922 /** 923 * Returns the y coordinate of the upper-left corner of the 924 * RasterAccessor's accessible area. 925 */ getY()926 public int getY() { 927 return rectY; 928 } 929 930 /** Returns the width of the 931 * RasterAccessor's accessible area. 932 */ getWidth()933 public int getWidth() { 934 return rectWidth; 935 } 936 937 /** Returns the height of the 938 * RasterAccessor's accessible area. 939 */ getHeight()940 public int getHeight() { 941 return rectHeight; 942 } 943 944 /** Returns the numBands of the presented area. */ getNumBands()945 public int getNumBands() { 946 return numBands; 947 } 948 949 950 /** 951 * Whether the <code>RasterAccessor</code> represents binary data. 952 * This occurs when the <code>Raster</code> has a 953 * <code>MultiPixelPackedSampleModel</code> with a single band and 954 * one bit per pixel. 955 * 956 * @since JAI 1.1 957 */ isBinary()958 public boolean isBinary() { 959 return (formatTagID & TAG_BINARY) == TAG_BINARY && 960 ImageUtil.isBinary(raster.getSampleModel()); 961 } 962 963 /** 964 * For the case of binary data (<code>isBinary()</code> returns 965 * <code>true</code>), return the binary data as a packed byte array. 966 * The data will be packed as eight bits per byte with no bit offset, 967 * i.e., the first bit in each image line will be the left-most of the 968 * first byte of the line. The line stride in bytes will be 969 * <code>(int)((getWidth()+7)/8)</code>. The length of the returned 970 * array will be the line stride multiplied by <code>getHeight()</code> 971 * 972 * @return the binary data as a packed array of bytes with zero offset 973 * of <code>null</code> if the data are not binary. 974 * 975 * @since JAI 1.1 976 */ getBinaryDataArray()977 public byte[] getBinaryDataArray() { 978 if(binaryDataArray == null && isBinary()) { 979 binaryDataArray = 980 ImageUtil.getPackedBinaryData(raster, new Rectangle(rectX, rectY, 981 rectWidth, 982 rectHeight)); 983 } 984 return binaryDataArray; 985 } 986 987 /** 988 * Returns the image data as a byte array. Non-null only if 989 * getDataType = DataBuffer.TYPE_BYTE. 990 * 991 * <p> For the case of binary data the corresponding instance variable 992 * <code>byteDataArrays</code> will not be initialized until this 993 * method or <code>getByteDataArray(int b)</code> is invoked. The 994 * binary data will be returned as bytes with value 0 or 1. 995 */ getByteDataArrays()996 public byte[][] getByteDataArrays() { 997 if(byteDataArrays == null && isBinary()) { 998 byte[] bdata = 999 ImageUtil.getUnpackedBinaryData(raster, 1000 new Rectangle(rectX, rectY, 1001 rectWidth, 1002 rectHeight)); 1003 byteDataArrays = new byte[][] {bdata}; 1004 } 1005 return byteDataArrays; 1006 } 1007 1008 /** 1009 * Returns the image data as a byte array for a specific band. 1010 * Non-null only if getDataType = DataBuffer.TYPE_BYTE. 1011 */ getByteDataArray(int b)1012 public byte[] getByteDataArray(int b) { 1013 byte[][] bda = getByteDataArrays(); 1014 return (bda == null ? null : bda[b]); 1015 } 1016 1017 /** 1018 * Returns the image data as a short array. Non-null only if 1019 * getDataType = DataBuffer.TYPE_USHORT or DataBuffer.TYPE_SHORT. 1020 */ getShortDataArrays()1021 public short[][] getShortDataArrays() { 1022 return shortDataArrays; 1023 } 1024 1025 /** 1026 * Returns the image data as a short array for a specific band. 1027 * Non-null only if getDataType = DataBuffer.TYPE_USHORT or 1028 * DataBuffer.TYPE_SHORT. 1029 */ getShortDataArray(int b)1030 public short[] getShortDataArray(int b) { 1031 return (shortDataArrays == null ? null : shortDataArrays[b]); 1032 } 1033 1034 /** 1035 * Returns the image data as an int array. Non-null only if 1036 * getDataType = DataBuffer.TYPE_INT. 1037 */ getIntDataArrays()1038 public int[][] getIntDataArrays() { 1039 return intDataArrays; 1040 } 1041 1042 /** 1043 * Returns the image data as an int array for a specific band. 1044 * Non-null only if getDataType = DataBuffer.TYPE_INT. 1045 */ getIntDataArray(int b)1046 public int[] getIntDataArray(int b) { 1047 return (intDataArrays == null ? null : intDataArrays[b]); 1048 } 1049 1050 /** 1051 * Returns the image data as a float array. Non-null only if 1052 * getDataType = DataBuffer.TYPE_FLOAT. 1053 */ getFloatDataArrays()1054 public float[][] getFloatDataArrays() { 1055 return floatDataArrays; 1056 } 1057 1058 /** 1059 * Returns the image data as a float array for a specific band. 1060 * Non-null only if getDataType = DataBuffer.TYPE_FLOAT. 1061 */ getFloatDataArray(int b)1062 public float[] getFloatDataArray(int b) { 1063 return (floatDataArrays == null ? null : floatDataArrays[b]); 1064 } 1065 1066 /** 1067 * Returns the image data as a double array. Non-null only if 1068 * getDataType = DataBuffer.TYPE_DOUBLE 1069 */ getDoubleDataArrays()1070 public double[][] getDoubleDataArrays() { 1071 return doubleDataArrays; 1072 } 1073 1074 /** 1075 * Returns the image data as a double array for a specific band. 1076 * Non-null only if getDataType = DataBuffer.TYPE_DOUBLE 1077 */ getDoubleDataArray(int b)1078 public double[] getDoubleDataArray(int b) { 1079 return (doubleDataArrays == null ? null : doubleDataArrays[b]); 1080 } 1081 1082 /** 1083 * Returns the image data as an Object for a specific band. 1084 * 1085 * @param b The index of the image band of interest. 1086 */ getDataArray(int b)1087 public Object getDataArray(int b) { 1088 Object dataArray = null; 1089 switch(getDataType()) { 1090 case DataBuffer.TYPE_BYTE: 1091 dataArray = getByteDataArray(b); 1092 break; 1093 1094 case DataBuffer.TYPE_SHORT: 1095 case DataBuffer.TYPE_USHORT: 1096 dataArray = getShortDataArray(b); 1097 break; 1098 1099 case DataBuffer.TYPE_INT: 1100 dataArray = getIntDataArray(b); 1101 break; 1102 1103 case DataBuffer.TYPE_FLOAT: 1104 dataArray = getFloatDataArray(b); 1105 break; 1106 1107 case DataBuffer.TYPE_DOUBLE: 1108 dataArray = getDoubleDataArray(b); 1109 break; 1110 1111 default: 1112 dataArray = null; 1113 } 1114 1115 return dataArray; 1116 } 1117 1118 /** Returns the bandDataOffsets into the dataArrays. */ getBandOffsets()1119 public int[] getBandOffsets() { 1120 return bandDataOffsets; 1121 } 1122 1123 /** 1124 * Returns the offset of all band's samples from any 1125 * pixel offset. 1126 */ getOffsetsForBands()1127 public int[] getOffsetsForBands() { 1128 return bandOffsets; 1129 } 1130 1131 /** 1132 * Returns the offset of a specific band's first sample into the 1133 * DataBuffer including the DataBuffer's offset. 1134 */ getBandOffset(int b)1135 public int getBandOffset(int b) { 1136 return bandDataOffsets[b]; 1137 } 1138 1139 /** 1140 * Returns the offset of a specified band's sample from any 1141 * pixel offset. 1142 */ getOffsetForBand(int b)1143 public int getOffsetForBand(int b) { 1144 return bandOffsets[b]; 1145 } 1146 1147 /** 1148 * Returns the scanlineStride for the image data. 1149 * 1150 * <p> For binary data this stride is applies to the arrays returned by 1151 * <code>getByteDataArray()</code> and <code>getByteDataArrays()</code> 1152 * if the data are accessed as bytes; it does not apply to the array 1153 * returned by <code>getBinaryDataArray()</code> when the data are 1154 * accessed as bits packed into bytes. 1155 */ getScanlineStride()1156 public int getScanlineStride() { 1157 return scanlineStride; 1158 } 1159 1160 /** Returns the pixelStride for the image data. */ getPixelStride()1161 public int getPixelStride() { 1162 return pixelStride; 1163 } 1164 1165 /** 1166 * Returns the data type of the RasterAccessor object. Note that 1167 * this datatype is not necessarily the same data type as the 1168 * underlying raster. 1169 */ getDataType()1170 public int getDataType() { 1171 return formatTagID & DATATYPE_MASK; 1172 } 1173 1174 /** 1175 * Returns true if the RasterAccessors's data is copied from it's 1176 * raster. 1177 */ isDataCopy()1178 public boolean isDataCopy() { 1179 return ((formatTagID & COPY_MASK) == COPIED); 1180 } 1181 1182 1183 /** 1184 * For the case of binary data (<code>isBinary()</code> returns 1185 * <code>true</code>), copy the binary data back into the 1186 * <code>Raster</code> of the <code>RasterAccessor</code>. If 1187 * this method is invoked in the non-binary case it does nothing. 1188 * Any bit offset in the original <code>SampleModel</code> will be 1189 * accounted for. 1190 * 1191 * @since JAI 1.1 1192 */ 1193 // Note: ALL branches of this method have been tested. (bpb 10 May 2000) copyBinaryDataToRaster()1194 public void copyBinaryDataToRaster() { 1195 if(binaryDataArray == null || !isBinary()) { 1196 return; 1197 } 1198 1199 ImageUtil.setPackedBinaryData(binaryDataArray, 1200 (WritableRaster)raster, 1201 new Rectangle(rectX, rectY, 1202 rectWidth, rectHeight)); 1203 } 1204 1205 /** 1206 * Copies data back into the RasterAccessor's raster. Note that 1207 * the data is cast from the intermediate data format to 1208 * the raster's format. If clamping is needed, the call 1209 * clampDataArrays() method needs to be called before 1210 * calling the copyDataToRaster() method. 1211 * Note: the raster is expected to be writable - typically a 1212 * destination raster - otherwise, a run-time exception will occur. 1213 * 1214 * <p> If the data are binary, then the target bit will be set if 1215 * and only if the corresponding byte is non-zero. 1216 */ copyDataToRaster()1217 public void copyDataToRaster() { 1218 if (isDataCopy()) { 1219 1220 // Writeback should only be necessary on destRasters which 1221 // should be writable so this cast should succeed. 1222 WritableRaster wr = (WritableRaster)raster; 1223 switch (getDataType()) { 1224 case DataBuffer.TYPE_BYTE: 1225 // Note: ALL branches of this case have been tested. 1226 // (bpb 10 May 2000) 1227 if(!isBinary()) { 1228 // If this exception occurs then there is a logic 1229 // error within this accessor since the only case 1230 // wherein byte data should be COPIED is when the 1231 // data set is binary. 1232 throw new RuntimeException(JaiI18N.getString("RasterAccessor1")); 1233 } 1234 1235 // This case only occurs for binary src and dst. 1236 1237 ImageUtil.setUnpackedBinaryData(byteDataArrays[0], 1238 wr, 1239 new Rectangle(rectX, rectY, 1240 rectWidth, 1241 rectHeight)); 1242 break; 1243 case DataBuffer.TYPE_INT: 1244 wr.setPixels(rectX,rectY, 1245 rectWidth,rectHeight, 1246 intDataArrays[0]); 1247 break; 1248 1249 case DataBuffer.TYPE_FLOAT: 1250 wr.setPixels(rectX,rectY, 1251 rectWidth,rectHeight, 1252 floatDataArrays[0]); 1253 break; 1254 1255 case DataBuffer.TYPE_DOUBLE: 1256 wr.setPixels(rectX,rectY, 1257 rectWidth,rectHeight, 1258 doubleDataArrays[0]); 1259 break; 1260 } 1261 } 1262 } 1263 1264 /** 1265 * Indicates if the RasterAccessor has a larger dynamic range than 1266 * the underlying Raster. Except in special cases, where the op 1267 * knows something special, this call will determine whether or 1268 * not clampDataArrays() needs to be called. 1269 */ needsClamping()1270 public boolean needsClamping() { 1271 int bits[] = raster.getSampleModel().getSampleSize(); 1272 1273 // Do we even need a clamp? We do if there's any band 1274 // of the source image stored in that's less than 32 bits 1275 // and is stored in a byte, short or int format. (The automatic 1276 // casts between floats/doubles and 32-bit ints in setPixel() 1277 // do what we want.) 1278 1279 for (int i = 0; i < bits.length; i++) { 1280 if (bits[i] < 32) { 1281 return true; 1282 } 1283 } 1284 return false; 1285 } 1286 1287 /** 1288 * Clamps data array values to a range that the underlying raster 1289 * can deal with. For example, if the underlying raster stores 1290 * data as bytes, but the samples are unpacked into integer arrays by 1291 * the RasterAccessor for an operation, the operation will 1292 * need to call clampDataArrays() so that the data in the int 1293 * arrays is restricted to the range 0..255 before a setPixels() 1294 * call is made on the underlying raster. Note that some 1295 * operations (for example, lookup) can guarantee that their 1296 * results don't need clamping so they can call 1297 * RasterAccessor.copyDataToRaster() without first calling this 1298 * function. 1299 */ clampDataArrays()1300 public void clampDataArrays () { 1301 int bits[] = raster.getSampleModel().getSampleSize(); 1302 1303 // Do we even need a clamp? We do if there's any band 1304 // of the source image stored in that's less than 32 bits 1305 // and is stored in a byte, short or int format. (The automatic 1306 // casts between floats/doubles and 32-bit ints in setPixel() 1307 // do what we want.) 1308 1309 boolean needClamp = false; 1310 boolean uniformBitSize = true; 1311 int bitSize = bits[0]; 1312 for (int i = 0; i < bits.length; i++) { 1313 if (bits[i] < 32) { 1314 needClamp = true; 1315 } 1316 if (bits[i] != bitSize) { 1317 uniformBitSize = false; 1318 } 1319 } 1320 if (!needClamp) { 1321 return; 1322 } 1323 1324 int dataType = raster.getDataBuffer().getDataType(); 1325 double hiVals[] = new double[bits.length]; 1326 double loVals[] = new double[bits.length]; 1327 1328 if (dataType == DataBuffer.TYPE_USHORT && 1329 uniformBitSize && bits[0] == 16) { 1330 for (int i = 0; i < bits.length; i++) { 1331 hiVals[i] = (double)0xFFFF; 1332 loVals[i] = (double)0; 1333 } 1334 } else if (dataType == DataBuffer.TYPE_SHORT && 1335 uniformBitSize && bits[0] == 16) { 1336 for (int i = 0; i < bits.length; i++) { 1337 hiVals[i] = (double)Short.MAX_VALUE; 1338 loVals[i] = (double)Short.MIN_VALUE; 1339 } 1340 } else if (dataType == DataBuffer.TYPE_INT && 1341 uniformBitSize && bits[0] == 32) { 1342 for (int i = 0; i < bits.length; i++) { 1343 hiVals[i] = (double)Integer.MAX_VALUE; 1344 loVals[i] = (double)Integer.MIN_VALUE; 1345 } 1346 } else { 1347 for (int i = 0; i < bits.length; i++) { 1348 hiVals[i] = (double)((1 << bits[i]) - 1); 1349 loVals[i] = (double)0; 1350 } 1351 } 1352 clampDataArray(hiVals,loVals); 1353 } 1354 clampDataArray(double hiVals[], double loVals[])1355 private void clampDataArray(double hiVals[], double loVals[]) { 1356 switch (getDataType()) { 1357 case DataBuffer.TYPE_INT: 1358 clampIntArrays(toIntArray(hiVals),toIntArray(loVals)); 1359 break; 1360 1361 case DataBuffer.TYPE_FLOAT: 1362 clampFloatArrays(toFloatArray(hiVals),toFloatArray(loVals)); 1363 break; 1364 1365 case DataBuffer.TYPE_DOUBLE: 1366 clampDoubleArrays(hiVals,loVals); 1367 break; 1368 } 1369 } 1370 toIntArray(double vals[])1371 private int[] toIntArray(double vals[]) { 1372 int returnVals[] = new int[vals.length]; 1373 for (int i = 0; i < vals.length; i++) { 1374 returnVals[i] = (int)vals[i]; 1375 } 1376 return returnVals; 1377 } 1378 toFloatArray(double vals[])1379 private float[] toFloatArray(double vals[]) { 1380 float returnVals[] = new float[vals.length]; 1381 for (int i = 0; i < vals.length; i++) { 1382 returnVals[i] = (float)vals[i]; 1383 } 1384 return returnVals; 1385 } 1386 clampIntArrays(int hiVals[], int loVals[])1387 private void clampIntArrays(int hiVals[], int loVals[]) { 1388 int width = rectWidth; 1389 int height = rectHeight; 1390 for (int k = 0; k < numBands; k++) { 1391 int data[] = intDataArrays[k]; 1392 int scanlineOffset = bandDataOffsets[k]; 1393 int hiVal = hiVals[k]; 1394 int loVal = loVals[k]; 1395 for (int j = 0; j < height; j++) { 1396 int pixelOffset = scanlineOffset; 1397 for (int i = 0; i < width; i++) { 1398 int tmp = data[pixelOffset]; 1399 if (tmp < loVal) { 1400 data[pixelOffset] = loVal; 1401 } else if (tmp > hiVal) { 1402 data[pixelOffset] = hiVal; 1403 } 1404 pixelOffset += pixelStride; 1405 } 1406 scanlineOffset += scanlineStride; 1407 } 1408 } 1409 } 1410 clampFloatArrays(float hiVals[], float loVals[])1411 private void clampFloatArrays(float hiVals[], float loVals[]) { 1412 int width = rectWidth; 1413 int height = rectHeight; 1414 for (int k = 0; k < numBands; k++) { 1415 float data[] = floatDataArrays[k]; 1416 int scanlineOffset = bandDataOffsets[k]; 1417 float hiVal = hiVals[k]; 1418 float loVal = loVals[k]; 1419 for (int j = 0; j < height; j++) { 1420 int pixelOffset = scanlineOffset; 1421 for (int i = 0; i < width; i++) { 1422 float tmp = data[pixelOffset]; 1423 if (tmp < loVal) { 1424 data[pixelOffset] = loVal; 1425 } else if (tmp > hiVal) { 1426 data[pixelOffset] = hiVal; 1427 } 1428 pixelOffset += pixelStride; 1429 } 1430 scanlineOffset += scanlineStride; 1431 } 1432 } 1433 } 1434 clampDoubleArrays(double hiVals[], double loVals[])1435 private void clampDoubleArrays(double hiVals[], double loVals[]) { 1436 int width = rectWidth; 1437 int height = rectHeight; 1438 for (int k = 0; k < numBands; k++) { 1439 double data[] = doubleDataArrays[k]; 1440 int scanlineOffset = bandDataOffsets[k]; 1441 double hiVal = hiVals[k]; 1442 double loVal = loVals[k]; 1443 for (int j = 0; j < height; j++) { 1444 int pixelOffset = scanlineOffset; 1445 for (int i = 0; i < width; i++) { 1446 double tmp = data[pixelOffset]; 1447 if (tmp < loVal) { 1448 data[pixelOffset] = loVal; 1449 } else if (tmp > hiVal) { 1450 data[pixelOffset] = hiVal; 1451 } 1452 pixelOffset += pixelStride; 1453 } 1454 scanlineOffset += scanlineStride; 1455 } 1456 } 1457 } 1458 } 1459