001/* 002 * $RCSfile: RawImageWriter.java,v $ 003 * 004 * 005 * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without 008 * modification, are permitted provided that the following conditions 009 * are met: 010 * 011 * - Redistribution of source code must retain the above copyright 012 * notice, this list of conditions and the following disclaimer. 013 * 014 * - Redistribution in binary form must reproduce the above copyright 015 * notice, this list of conditions and the following disclaimer in 016 * the documentation and/or other materials provided with the 017 * distribution. 018 * 019 * Neither the name of Sun Microsystems, Inc. or the names of 020 * contributors may be used to endorse or promote products derived 021 * from this software without specific prior written permission. 022 * 023 * This software is provided "AS IS," without a warranty of any 024 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 025 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 026 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY 027 * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 028 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 029 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 030 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 031 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, 032 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND 033 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR 034 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE 035 * POSSIBILITY OF SUCH DAMAGES. 036 * 037 * You acknowledge that this software is not designed or intended for 038 * use in the design, construction, operation or maintenance of any 039 * nuclear facility. 040 * 041 * $Revision: 1.1 $ 042 * $Date: 2005/02/11 05:01:42 $ 043 * $State: Exp $ 044 */ 045package com.github.jaiimageio.impl.plugins.raw; 046 047import java.awt.Point; 048import java.awt.Rectangle; 049import java.awt.image.BandedSampleModel; 050import java.awt.image.ColorModel; 051import java.awt.image.ComponentSampleModel; 052import java.awt.image.DataBuffer; 053import java.awt.image.DataBufferByte; 054import java.awt.image.DataBufferDouble; 055import java.awt.image.DataBufferFloat; 056import java.awt.image.DataBufferInt; 057import java.awt.image.DataBufferShort; 058import java.awt.image.DataBufferUShort; 059import java.awt.image.MultiPixelPackedSampleModel; 060import java.awt.image.Raster; 061import java.awt.image.RenderedImage; 062import java.awt.image.SampleModel; 063import java.awt.image.SinglePixelPackedSampleModel; 064import java.awt.image.WritableRaster; 065import java.io.IOException; 066 067import javax.imageio.IIOImage; 068import javax.imageio.ImageTypeSpecifier; 069import javax.imageio.ImageWriteParam; 070import javax.imageio.ImageWriter; 071import javax.imageio.metadata.IIOMetadata; 072import javax.imageio.spi.ImageWriterSpi; 073import javax.imageio.stream.ImageOutputStream; 074 075import com.github.jaiimageio.impl.common.ImageUtil; 076 077/** 078 * The Java Image IO plugin writer for encoding a binary RenderedImage into 079 * a Raw format. 080 * 081 * <p> The encoding process may clip, subsample or select bands using the 082 * parameters specified in the <code>ImageWriteParam</code>. 083 * 084 * Thus, when read this raw image the proper image data type 085 * should be provided. 086 * 087 * @see com.github.jaiimageio.plugins.RawImageWriteParam 088 */ 089 090 // <p> If the destination data is packed packed, the data is written in the 091 // order defined by the sample model. That the data is packed is defined as 092 // (1) if the sample model is <code>SingleSamplePackedSampleModel</code> or 093 // <code>BandedSampleModel</code>; or (2) the pixel stride or sanline stride 094 // equals to the band number; or (3) the pixel stride equals to the band 095 // number multiply the tile height; or (4) the scanline stride equals to the 096 // band number multiply the tile width; or (5) the data for a band is stored 097 // in a separate data bank. 098 // 099 // <p> Otherwise, the data is reordered in a packed pixel interleaved format, 100 // and then written into the stream. In this case the data order may be change. 101 // For example, the original image data is in the order of 102 // <pre> 103 // RRRRRRRRRRRRRRRRRRRR 104 // GGGGGGGGGGGGGGGGGGGG 105 // BBBBBBBBBBBBBBBBBBBB 106 // RRRRRRRRRRRRRRRRRRRR 107 // GGGGGGGGGGGGGGGGGGGG 108 // BBBBBBBBBBBBBBBBBBBB 109 // </pre> 110 // 111 // , and only the G and B bands are written in the stream. So the data in the 112 // stream will be in the order of 113 // <pre> 114 // GBGBGBGBGBGBGB 115 // </pre>. 116public class RawImageWriter extends ImageWriter { 117 /** The output stream to write into */ 118 private ImageOutputStream stream = null; 119 120 /** The image index in this stream. */ 121 private int imageIndex; 122 123 /** The tile width for encoding */ 124 private int tileWidth; 125 126 /** The tile height for encoding */ 127 private int tileHeight; 128 129 /** The tile grid offset for encoding */ 130 private int tileXOffset, tileYOffset; 131 132 /** The source -> destination transformation */ 133 private int scaleX, scaleY, xOffset, yOffset; 134 135 /** The source bands to be encoded. */ 136 private int[] sourceBands = null; 137 138 /** The number of components in the image */ 139 private int numBands; 140 141 /** The source raster if write raster. */ 142 private RenderedImage input; 143 144 /** The input source raster. */ 145 private Raster inputRaster; 146 147 private Rectangle destinationRegion = null; 148 149 private SampleModel sampleModel; 150 151 /** Coordinate transform or sub selection is needed before encoding. */ 152 private boolean noTransform = true; 153 private boolean noSubband = true; 154 155 /** Indicates a <code>raster</code> rather than a <code>RenderedImage</code> 156 * to be encoded. 157 */ 158 private boolean writeRaster = false; 159 160 /** Whether can write optimally. */ 161 private boolean optimal = false; 162 163 /** The strides for pixel, band, and scanline. */ 164 private int pxlStride, lineStride, bandStride; 165 166 /** Constructs <code>RawImageWriter</code> based on the provided 167 * <code>ImageWriterSpi</code>. 168 */ 169 public RawImageWriter(ImageWriterSpi originator) { 170 super(originator); 171 } 172 173 public void setOutput(Object output) { 174 super.setOutput(output); // validates output 175 if (output != null) { 176 if (!(output instanceof ImageOutputStream)) 177 throw new IllegalArgumentException(I18N.getString("RawImageWriter0")); 178 this.stream = (ImageOutputStream)output; 179 } else 180 this.stream = null; 181 } 182 183 public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) { 184 return null; 185 } 186 187 public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, 188 ImageWriteParam param) { 189 return null; 190 } 191 192 public IIOMetadata convertStreamMetadata(IIOMetadata inData, 193 ImageWriteParam param) { 194 return null; 195 } 196 197 public IIOMetadata convertImageMetadata(IIOMetadata metadata, 198 ImageTypeSpecifier type, 199 ImageWriteParam param) { 200 return null; 201 } 202 203 public boolean canWriteRasters() { 204 return true; 205 } 206 207 public ImageWriteParam getDefaultWriteParam() { 208 return new RawImageWriteParam(getLocale()); 209 } 210 211 public void write(IIOMetadata streamMetadata, 212 IIOImage image, 213 ImageWriteParam param) throws IOException { 214 clearAbortRequest(); 215 processImageStarted(imageIndex++); 216 217 if (param == null) 218 param = getDefaultWriteParam(); 219 220 writeRaster = image.hasRaster(); 221 Rectangle sourceRegion = param.getSourceRegion(); 222 ColorModel colorModel = null; 223 Rectangle originalRegion = null; 224 225 if (writeRaster) { 226 inputRaster = image.getRaster(); 227 sampleModel = inputRaster.getSampleModel(); 228 originalRegion = inputRaster.getBounds(); 229 } else { 230 input = image.getRenderedImage(); 231 sampleModel = input.getSampleModel(); 232 233 originalRegion = new Rectangle(input.getMinX(), input.getMinY(), 234 input.getWidth(), input.getHeight()); 235 236 colorModel = input.getColorModel(); 237 } 238 239 if (sourceRegion == null) 240 sourceRegion = (Rectangle)originalRegion.clone(); 241 else 242 sourceRegion = sourceRegion.intersection(originalRegion); 243 244 if (sourceRegion.isEmpty()) 245 throw new RuntimeException(I18N.getString("RawImageWriter1")); 246 247 scaleX = param.getSourceXSubsampling(); 248 scaleY = param.getSourceYSubsampling(); 249 xOffset = param.getSubsamplingXOffset(); 250 yOffset = param.getSubsamplingYOffset(); 251 252 sourceRegion.translate(xOffset, yOffset); 253 sourceRegion.width -= xOffset; 254 sourceRegion.height -= yOffset; 255 256 xOffset = sourceRegion.x % scaleX; 257 yOffset = sourceRegion.y % scaleY; 258 259 int minX = sourceRegion.x / scaleX; 260 int minY = sourceRegion.y / scaleY; 261 int w = (sourceRegion.width + scaleX - 1) / scaleX; 262 int h = (sourceRegion.height + scaleY - 1) / scaleY; 263 264 destinationRegion = new Rectangle(minX, minY, w, h); 265 noTransform = destinationRegion.equals(originalRegion); 266 267 tileHeight = sampleModel.getHeight(); 268 tileWidth = sampleModel.getWidth(); 269 if (noTransform) { 270 if (writeRaster) { 271 tileXOffset = inputRaster.getMinX(); 272 tileYOffset = inputRaster.getMinY(); 273 } else { 274 tileXOffset = input.getTileGridXOffset(); 275 tileYOffset = input.getTileGridYOffset(); 276 } 277 } else { 278 tileXOffset = destinationRegion.x; 279 tileYOffset = destinationRegion.y; 280 } 281 282 sourceBands = param.getSourceBands(); 283 boolean noSubband = true; 284 numBands = sampleModel.getNumBands(); 285 286 if (sourceBands != null) { 287 sampleModel = sampleModel.createSubsetSampleModel(sourceBands); 288 colorModel = null; 289 noSubband = false; 290 numBands = sampleModel.getNumBands(); 291 } else { 292 sourceBands = new int[numBands]; 293 for (int i = 0; i < numBands; i++) 294 sourceBands[i] = i; 295 } 296 297 if (sampleModel instanceof ComponentSampleModel) { 298 ComponentSampleModel csm = (ComponentSampleModel)sampleModel; 299 int[] bandOffsets = csm.getBandOffsets(); 300 301 bandStride = bandOffsets[0]; 302 303 for (int i = 1; i < bandOffsets.length; i++) 304 if (bandStride > bandOffsets[i]) 305 bandStride = bandOffsets[i]; 306 307 int[] bankIndices = csm.getBankIndices(); 308 int numBank = bankIndices[0]; 309 for (int i = 1; i < bankIndices.length; i++) 310 if (numBank > bankIndices[i]) 311 numBank = bankIndices[i]; 312 313 pxlStride = csm.getPixelStride(); 314 lineStride = csm.getScanlineStride(); 315 316 optimal = bandStride == 0 || 317 (pxlStride < lineStride && pxlStride == numBands) || 318 (lineStride < pxlStride && lineStride == numBands) || 319 (pxlStride < lineStride && 320 lineStride == numBands * csm.getWidth()) || 321 (lineStride < pxlStride && 322 pxlStride == numBands * csm.getHeight()) || 323 csm instanceof BandedSampleModel; 324 } else if (sampleModel instanceof SinglePixelPackedSampleModel || 325 sampleModel instanceof MultiPixelPackedSampleModel) { 326 optimal = true; 327 } 328 329 int numXTiles = getMaxTileX() - getMinTileX() + 1; 330 int totalTiles = numXTiles * (getMaxTileY() - getMinTileY() + 1); 331 332 for (int y = getMinTileY(); y <= getMaxTileY(); y++) { 333 for (int x = getMinTileX(); x <= getMaxTileX(); x++) { 334 writeRaster(getTile(x, y)); 335 336 float percentage = (x + y * numXTiles + 1.0F) / totalTiles; 337 processImageProgress(percentage * 100.0F); 338 } 339 } 340 341 stream.flush(); 342 if (abortRequested()) 343 processWriteAborted(); 344 else 345 processImageComplete(); 346 } 347 348 //XXX: just for test 349 public int getWidth() { 350 return destinationRegion.width; 351 } 352 353 public int getHeight() { 354 return destinationRegion.height; 355 } 356 357 private void writeRaster(Raster raster) throws IOException { 358 int numBank = 0; 359 int bandStride = 0; 360 int[] bankIndices = null; 361 int[] bandOffsets = null; 362 int bandSize = 0; 363 int numBand = sampleModel.getNumBands(); 364 int type = sampleModel.getDataType(); 365 366 if (sampleModel instanceof ComponentSampleModel) { 367 ComponentSampleModel csm = (ComponentSampleModel)sampleModel; 368 369 bandOffsets = csm.getBandOffsets(); 370 for (int i = 0; i < numBand; i++) 371 if (bandStride < bandOffsets[i]) 372 bandStride = bandOffsets[i]; 373 374 bankIndices = csm.getBankIndices(); 375 for (int i = 0; i < numBand; i++) 376 if (numBank < bankIndices[i]) 377 numBank = bankIndices[i]; 378 379 bandSize = (int)ImageUtil.getBandSize(sampleModel) ; 380 } 381 382 byte[] bdata = null; 383 short[] sdata = null; 384 int[] idata = null; 385 float[] fdata = null; 386 double[] ddata = null; 387 388 if (raster.getParent() != null && 389 !sampleModel.equals(raster.getParent().getSampleModel())) { 390 WritableRaster ras = 391 Raster.createWritableRaster(sampleModel, 392 new Point(raster.getMinX(), 393 raster.getMinY())); 394 ras.setRect(raster); 395 raster = ras; 396 } 397 398 DataBuffer data = raster.getDataBuffer(); 399 400 if (optimal) { 401 if (numBank > 0) { //multiple data bank 402 for (int i = 0; i < numBands; i++) { 403 int bank = bankIndices[sourceBands[i]]; 404 switch (type) { 405 case DataBuffer.TYPE_BYTE: 406 bdata = ((DataBufferByte)data).getData(bank); 407 stream.write(bdata, 0, bdata.length); 408 break; 409 case DataBuffer.TYPE_SHORT: 410 sdata = ((DataBufferShort)data).getData(bank); 411 stream.writeShorts(sdata, 0, sdata.length); 412 break; 413 case DataBuffer.TYPE_USHORT: 414 sdata = ((DataBufferUShort)data).getData(bank); 415 stream.writeShorts(sdata, 0, sdata.length); 416 break; 417 case DataBuffer.TYPE_INT: 418 idata = ((DataBufferInt)data).getData(bank); 419 stream.writeInts(idata, 0, idata.length); 420 break; 421 case DataBuffer.TYPE_FLOAT: 422 fdata = ((DataBufferFloat)data).getData(bank); 423 stream.writeFloats(fdata, 0, fdata.length); 424 break; 425 case DataBuffer.TYPE_DOUBLE: 426 ddata = ((DataBufferDouble)data).getData(bank); 427 stream.writeDoubles(ddata, 0, ddata.length); 428 break; 429 } 430 } 431 } else { // Single data bank 432 switch (type) { 433 case DataBuffer.TYPE_BYTE: 434 bdata = ((DataBufferByte)data).getData(); 435 break; 436 case DataBuffer.TYPE_SHORT: 437 sdata = ((DataBufferShort)data).getData(); 438 break; 439 case DataBuffer.TYPE_USHORT: 440 sdata = ((DataBufferUShort)data).getData(); 441 break; 442 case DataBuffer.TYPE_INT: 443 idata = ((DataBufferInt)data).getData(); 444 break; 445 case DataBuffer.TYPE_FLOAT: 446 fdata = ((DataBufferFloat)data).getData(); 447 break; 448 case DataBuffer.TYPE_DOUBLE: 449 ddata = ((DataBufferDouble)data).getData(); 450 break; 451 } 452 453 if (!noSubband && 454 bandStride >= raster.getWidth() * 455 raster.getHeight() * (numBands-1)) { 456 457 for (int i = 0; i < numBands; i++) { 458 int offset = bandOffsets[sourceBands[i]]; 459 switch (type) { 460 case DataBuffer.TYPE_BYTE: 461 stream.write(bdata, offset, bandSize); 462 break; 463 case DataBuffer.TYPE_SHORT: 464 case DataBuffer.TYPE_USHORT: 465 stream.writeShorts(sdata, offset, bandSize); 466 break; 467 case DataBuffer.TYPE_INT: 468 stream.writeInts(idata, offset, bandSize); 469 break; 470 case DataBuffer.TYPE_FLOAT: 471 stream.writeFloats(fdata, offset, bandSize); 472 break; 473 case DataBuffer.TYPE_DOUBLE: 474 stream.writeDoubles(ddata, offset, bandSize); 475 break; 476 } 477 } 478 } else { 479 switch (type) { 480 case DataBuffer.TYPE_BYTE: 481 stream.write(bdata, 0, bdata.length); 482 break; 483 case DataBuffer.TYPE_SHORT: 484 case DataBuffer.TYPE_USHORT: 485 stream.writeShorts(sdata, 0, sdata.length); 486 break; 487 case DataBuffer.TYPE_INT: 488 stream.writeInts(idata, 0, idata.length); 489 break; 490 case DataBuffer.TYPE_FLOAT: 491 stream.writeFloats(fdata, 0, fdata.length); 492 break; 493 case DataBuffer.TYPE_DOUBLE: 494 stream.writeDoubles(ddata, 0, ddata.length); 495 break; 496 } 497 } 498 } 499 } else if (sampleModel instanceof ComponentSampleModel) { 500 // The others, must be a ComponentSampleModel 501 switch (type) { 502 case DataBuffer.TYPE_BYTE: 503 bdata = ((DataBufferByte)data).getData(); 504 break; 505 case DataBuffer.TYPE_SHORT: 506 sdata = ((DataBufferShort)data).getData(); 507 break; 508 case DataBuffer.TYPE_USHORT: 509 sdata = ((DataBufferUShort)data).getData(); 510 break; 511 case DataBuffer.TYPE_INT: 512 idata = ((DataBufferInt)data).getData(); 513 break; 514 case DataBuffer.TYPE_FLOAT: 515 fdata = ((DataBufferFloat)data).getData(); 516 break; 517 case DataBuffer.TYPE_DOUBLE: 518 ddata = ((DataBufferDouble)data).getData(); 519 break; 520 } 521 522 ComponentSampleModel csm = (ComponentSampleModel)sampleModel; 523 int offset = 524 csm.getOffset(raster.getMinX()-raster.getSampleModelTranslateX(), 525 raster.getMinY()-raster.getSampleModelTranslateY()) 526 - bandOffsets[0]; 527 528 int srcSkip = pxlStride; 529 int copyLength = 1; 530 int innerStep = pxlStride; 531 532 int width = raster.getWidth(); 533 int height = raster.getHeight(); 534 535 int innerBound = width; 536 int outerBound = height; 537 538 if (srcSkip < lineStride) { 539 if (bandStride > pxlStride) 540 copyLength = width; 541 srcSkip = lineStride; 542 } else { 543 if (bandStride > lineStride) 544 copyLength = height; 545 innerStep = lineStride; 546 innerBound = height; 547 outerBound = width; 548 } 549 550 int writeLength = innerBound * numBands; 551 byte[] destBBuf = null; 552 short[] destSBuf = null; 553 int[] destIBuf = null; 554 float[] destFBuf = null; 555 double[] destDBuf = null; 556 Object srcBuf = null; 557 Object dstBuf = null; 558 559 switch (type) { 560 case DataBuffer.TYPE_BYTE: 561 srcBuf = bdata; 562 dstBuf = destBBuf = new byte[writeLength]; 563 break; 564 case DataBuffer.TYPE_SHORT: 565 case DataBuffer.TYPE_USHORT: 566 srcBuf = sdata; 567 dstBuf = destSBuf = new short[writeLength]; 568 break; 569 case DataBuffer.TYPE_INT: 570 srcBuf = idata; 571 dstBuf = destIBuf = new int[writeLength]; 572 break; 573 case DataBuffer.TYPE_FLOAT: 574 srcBuf = fdata; 575 dstBuf = destFBuf = new float[writeLength]; 576 break; 577 case DataBuffer.TYPE_DOUBLE: 578 srcBuf = ddata; 579 dstBuf = destDBuf = new double[writeLength]; 580 break; 581 } 582 583 if (copyLength > 1) { 584 for (int i = 0; i < outerBound; i++) { 585 for (int b = 0; b < numBands; b++) { 586 int bandOffset = bandOffsets[b]; 587 588 System.arraycopy(srcBuf, offset + bandOffset, 589 dstBuf, b * innerBound, innerBound); 590 } 591 592 switch (type) { 593 case DataBuffer.TYPE_BYTE: 594 stream.write((byte[])dstBuf, 0, writeLength); 595 break; 596 case DataBuffer.TYPE_SHORT: 597 case DataBuffer.TYPE_USHORT: 598 stream.writeShorts((short[])dstBuf, 0, writeLength); 599 break; 600 case DataBuffer.TYPE_INT: 601 stream.writeInts((int[])dstBuf, 0, writeLength); 602 break; 603 case DataBuffer.TYPE_FLOAT: 604 stream.writeFloats((float[])dstBuf, 0, writeLength); 605 break; 606 case DataBuffer.TYPE_DOUBLE: 607 stream.writeDoubles((double[])dstBuf, 0, writeLength); 608 break; 609 } 610 offset += srcSkip; 611 } 612 } else { 613 switch (type) { 614 case DataBuffer.TYPE_BYTE: { 615 for (int i = 0; i < outerBound; i++) { 616 for (int b = 0, k = 0; b < numBands; b++) { 617 int bandOffset = bandOffsets[b]; 618 619 for (int j = 0, m = offset; j < innerBound; 620 j++, m += innerStep) 621 // copy one sample to the destination buffer 622 destBBuf[k++] = bdata[m + bandOffset]; 623 } 624 625 stream.write(destBBuf, 0, writeLength); 626 offset += srcSkip; 627 } 628 } 629 break; 630 case DataBuffer.TYPE_SHORT: 631 case DataBuffer.TYPE_USHORT: { 632 for (int i = 0; i < outerBound; i++) { 633 for (int b = 0, k = 0; b < numBands; b++) { 634 int bandOffset = bandOffsets[b]; 635 636 for (int j = 0, m = offset; j < innerBound; 637 j++, m += innerStep) 638 // copy one sample to the destination buffer 639 destSBuf[k++] = sdata[m + bandOffset]; 640 } 641 642 stream.writeShorts(destSBuf, 0, writeLength); 643 offset += srcSkip; 644 } 645 } 646 break; 647 case DataBuffer.TYPE_INT: { 648 for (int i = 0; i < outerBound; i++) { 649 for (int b = 0, k = 0; b < numBands; b++) { 650 int bandOffset = bandOffsets[b]; 651 652 for (int j = 0, m = offset; j < innerBound; 653 j++, m += innerStep) 654 // copy one sample to the destination buffer 655 destIBuf[k++] = idata[m + bandOffset]; 656 } 657 658 stream.writeInts(destIBuf, 0, writeLength); 659 offset += srcSkip; 660 } 661 } 662 break; 663 case DataBuffer.TYPE_FLOAT: { 664 for (int i = 0; i < outerBound; i++) { 665 for (int b = 0, k = 0; b < numBands; b++) { 666 int bandOffset = bandOffsets[b]; 667 668 for (int j = 0, m = offset; j < innerBound; 669 j++, m += innerStep) 670 // copy one sample to the destination buffer 671 destFBuf[k++] = fdata[m + bandOffset]; 672 } 673 674 stream.writeFloats(destFBuf, 0, writeLength); 675 offset += srcSkip; 676 } 677 } 678 break; 679 case DataBuffer.TYPE_DOUBLE: { 680 for (int i = 0; i < outerBound; i++) { 681 for (int b = 0, k = 0; b < numBands; b++) { 682 int bandOffset = bandOffsets[b]; 683 684 for (int j = 0, m = offset; j < innerBound; 685 j++, m += innerStep) 686 // copy one sample to the destination buffer 687 destDBuf[k++] = ddata[m + bandOffset]; 688 } 689 690 stream.writeDoubles(destDBuf, 0, writeLength); 691 offset += srcSkip; 692 } 693 } 694 break; 695 } 696 } 697 } 698 } 699 700 private Raster getTile(int tileX, int tileY) { 701 int sx = tileXOffset + tileX * tileWidth; 702 int sy = tileYOffset + tileY * tileHeight; 703 Rectangle bounds = new Rectangle(sx, sy, tileWidth, tileHeight); 704 705 if (writeRaster) { 706 bounds = bounds.intersection(destinationRegion); 707 if (noTransform) { 708 return inputRaster.createChild(bounds.x, bounds.y, 709 bounds.width, bounds.height, 710 bounds.x, bounds.y, sourceBands); 711 } 712 713 sx = bounds.x; 714 sy = bounds.y; 715 716 WritableRaster ras = 717 Raster.createWritableRaster(sampleModel, new Point(sx, sy)); 718 719 int x = mapToSourceX(sx); 720 int y = mapToSourceY(sy); 721 722 int minY = inputRaster.getMinY(); 723 int maxY = inputRaster.getMinY() + inputRaster.getHeight(); 724 725 int cTileWidth = bounds.width; 726 727 int length = (cTileWidth - 1) * scaleX + 1; 728 729 for (int j = 0; j < bounds.height; j++, sy++, y += scaleY) { 730 if (y < minY || y >= maxY) 731 continue; 732 Raster source = 733 inputRaster.createChild(x, y, length, 1, 734 x, y, null); 735 int tempX = sx; 736 for (int i = 0, offset = x; i < cTileWidth; 737 i++, tempX++, offset += scaleX) { 738 for (int k = 0; k < numBands; k++) { 739 int p = source.getSample(offset, y, sourceBands[k]); 740 ras.setSample(tempX, sy, k, p); 741 } 742 } 743 } 744 745 return ras; 746 747 } else { 748 if (noTransform) { 749 Raster ras = input.getTile(tileX, tileY); 750 if (destinationRegion.contains(bounds) && noSubband) 751 return ras; 752 else { 753 bounds = bounds.intersection(destinationRegion); 754 return ras.createChild(bounds.x, bounds.y, 755 bounds.width, bounds.height, 756 bounds.x, bounds.y, sourceBands); 757 } 758 } 759 760 bounds = bounds.intersection(destinationRegion); 761 sx = bounds.x; 762 sy = bounds.y; 763 764 WritableRaster ras = 765 Raster.createWritableRaster(sampleModel, new Point(sx, sy)); 766 767 int x = mapToSourceX(sx); 768 int y = mapToSourceY(sy); 769 770 int minY = input.getMinY(); 771 int maxY = input.getMinY() + input.getHeight(); 772 773 int cTileWidth = bounds.width; 774 int length = (cTileWidth -1) * scaleX + 1; 775 776 for (int j = 0; j < bounds.height; j++, sy++, y += scaleY) { 777 if (y < minY || y >= maxY) 778 continue; 779 780 Raster source = 781 input.getData(new Rectangle(x, y, length, 1)); 782 783 int tempX = sx; 784 for (int i = 0, offset = x; i < cTileWidth; 785 i++, tempX++, offset += scaleX) { 786 for (int k = 0; k < numBands; k++) { 787 int p = source.getSample(offset, y, sourceBands[k]); 788 ras.setSample(tempX, sy, k, p); 789 } 790 } 791 } 792 return ras; 793 } 794 } 795 796 private int mapToSourceX(int x) { 797 return x * scaleX + xOffset; 798 } 799 800 private int mapToSourceY(int y) { 801 return y * scaleY + yOffset; 802 } 803 804 private int getMinTileX() { 805 return ToTile(destinationRegion.x, tileXOffset, tileWidth); 806 } 807 808 private int getMaxTileX() { 809 return ToTile(destinationRegion.x + destinationRegion.width - 1, 810 tileXOffset, tileWidth); 811 } 812 813 private int getMinTileY() { 814 return ToTile(destinationRegion.y, tileYOffset, tileHeight); 815 } 816 817 private int getMaxTileY() { 818 return ToTile(destinationRegion.y + destinationRegion.height - 1, 819 tileYOffset, tileHeight); 820 } 821 822 private static int ToTile(int pos, int tileOffset, int tileSize) { 823 pos -= tileOffset; 824 if (pos < 0) { 825 pos += 1 - tileSize; // force round to -infinity (ceiling) 826 } 827 return pos/tileSize; 828 } 829 830 public void reset() { 831 super.reset(); 832 stream = null; 833 optimal = false; 834 sourceBands = null; 835 destinationRegion = null; 836 noTransform = true; 837 noSubband = true; 838 writeRaster = false; 839 } 840}