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