001/*
002 * $RCSfile: RawRenderedImage.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.2 $
042 * $Date: 2006/04/21 23:19:13 $
043 * $State: Exp $
044 */
045package com.github.jaiimageio.impl.plugins.raw;
046
047import java.awt.Dimension;
048import java.awt.Point;
049import java.awt.Rectangle;
050import java.awt.image.BandedSampleModel;
051import java.awt.image.BufferedImage;
052import java.awt.image.ComponentSampleModel;
053import java.awt.image.DataBuffer;
054import java.awt.image.DataBufferByte;
055import java.awt.image.DataBufferDouble;
056import java.awt.image.DataBufferFloat;
057import java.awt.image.DataBufferInt;
058import java.awt.image.DataBufferShort;
059import java.awt.image.DataBufferUShort;
060import java.awt.image.MultiPixelPackedSampleModel;
061import java.awt.image.PixelInterleavedSampleModel;
062import java.awt.image.Raster;
063import java.awt.image.SampleModel;
064import java.awt.image.SinglePixelPackedSampleModel;
065import java.awt.image.WritableRaster;
066import java.io.IOException;
067
068import javax.imageio.ImageReadParam;
069import javax.imageio.ImageTypeSpecifier;
070
071import com.github.jaiimageio.impl.common.ImageUtil;
072import com.github.jaiimageio.impl.common.SimpleRenderedImage;
073import com.github.jaiimageio.stream.RawImageInputStream;
074
075public class RawRenderedImage extends SimpleRenderedImage {
076    /** The sample model for the original image. */
077    private SampleModel originalSampleModel;
078
079    private Raster currentTile;
080    private Point currentTileGrid;
081
082    /** The input stream we read from */
083    private RawImageInputStream iis = null;
084
085    /** Caches the <code>RawImageReader</code> which creates this object.  This
086     *  variable is used to monitor the abortion.
087     */
088    private RawImageReader reader;
089
090    /** The <code>ImageReadParam</code> to create this
091     *  <code>renderedImage</code>.
092     */
093    private ImageReadParam param = null;
094
095    // The image index in the stream
096    private int imageIndex;
097
098    /** The destination bounds. */
099    private Rectangle destinationRegion;
100    private Rectangle originalRegion;
101    private Point sourceOrigin;
102    private Dimension originalDimension;
103    private int maxXTile, maxYTile;
104
105    /** The subsampling parameters. */
106    private int scaleX, scaleY, xOffset, yOffset;
107    private int[] destinationBands = null;
108    private int[] sourceBands = null;
109    private int nComp;
110
111    /** Coordinate transform is not needed from the source (image stream)
112     *  to the destination.
113     */
114    private boolean noTransform = true;
115
116    /** The raster for medialib tiles to share. */
117    private WritableRaster rasForATile;
118
119    private BufferedImage destImage;
120
121    /** The position of the first sample of this image in the stream. */
122    private long position;
123
124    /** cache the size of the data for each tile in the stream. */
125    private long tileDataSize;
126
127    /** The orginal number tiles in X direction. */
128    private int originalNumXTiles;
129
130    public RawRenderedImage(RawImageInputStream iis,
131                            RawImageReader reader,
132                            ImageReadParam param,
133                            int imageIndex) throws IOException {
134        this.iis = iis;
135        this.reader = reader;
136        this.param = param;
137        this.imageIndex = imageIndex;
138        this.position = iis.getImageOffset(imageIndex);
139        this.originalDimension = iis.getImageDimension(imageIndex);
140
141        ImageTypeSpecifier type = iis.getImageType();
142        sampleModel = originalSampleModel = type.getSampleModel();
143        colorModel = type.getColorModel();
144
145        // If the destination band is set used it
146        sourceBands = (param == null) ? null : param.getSourceBands();
147
148        if (sourceBands == null) {
149            nComp = originalSampleModel.getNumBands();
150            sourceBands = new int[nComp];
151            for (int i = 0; i < nComp; i++)
152                sourceBands[i] = i;
153        } else {
154            sampleModel =
155                originalSampleModel.createSubsetSampleModel(sourceBands);
156            colorModel = ImageUtil.createColorModel(null, sampleModel);
157        }
158
159        nComp = sourceBands.length;
160
161        destinationBands = (param == null) ? null : param.getDestinationBands();
162        if (destinationBands == null) {
163            destinationBands = new int[nComp];
164            for (int i = 0; i < nComp; i++)
165                destinationBands[i] = i;
166        }
167
168        Dimension dim = iis.getImageDimension(imageIndex);
169        this.width = dim.width;
170        this.height = dim.height;
171
172        Rectangle sourceRegion =
173                new Rectangle(0, 0, this.width, this.height);
174
175        originalRegion = (Rectangle)sourceRegion.clone();
176
177        destinationRegion = (Rectangle)sourceRegion.clone();
178
179        if (param != null) {
180            RawImageReader.computeRegionsWrapper(param,
181                                          this.width, this.height,
182                                          param.getDestination(),
183                                          sourceRegion,
184                                          destinationRegion);
185            scaleX = param.getSourceXSubsampling();
186            scaleY = param.getSourceYSubsampling();
187            xOffset = param.getSubsamplingXOffset();
188            yOffset = param.getSubsamplingYOffset();
189        }
190
191        sourceOrigin = new Point(sourceRegion.x, sourceRegion.y);
192        if (!destinationRegion.equals(sourceRegion))
193            noTransform = false;
194
195        this.tileDataSize = ImageUtil.getTileSize(originalSampleModel);
196
197        this.tileWidth = originalSampleModel.getWidth();
198        this.tileHeight = originalSampleModel.getHeight();
199        this.tileGridXOffset = destinationRegion.x;
200        this.tileGridYOffset = destinationRegion.y;
201        this.originalNumXTiles = getNumXTiles();
202
203        this.width = destinationRegion.width;
204        this.height = destinationRegion.height;
205        this.minX = destinationRegion.x;
206        this.minY = destinationRegion.y;
207
208        sampleModel =
209            sampleModel.createCompatibleSampleModel(tileWidth, tileHeight);
210
211        maxXTile = originalDimension.width / tileWidth;
212        maxYTile = originalDimension.height / tileHeight;
213    }
214
215    public synchronized Raster getTile(int tileX, int tileY) {
216        if (currentTile != null &&
217            currentTileGrid.x == tileX &&
218            currentTileGrid.y == tileY)
219            return currentTile;
220
221        if (tileX >= getNumXTiles() || tileY >= getNumYTiles())
222            throw new IllegalArgumentException(I18N.getString("RawRenderedImage0"));
223
224        try {
225            iis.seek(position + (tileY * originalNumXTiles + tileX) * tileDataSize);
226
227            int x = tileXToX(tileX);
228            int y = tileYToY(tileY);
229            currentTile = Raster.createWritableRaster(sampleModel, new Point(x, y));
230
231            if (noTransform) {
232                switch (sampleModel.getDataType()) {
233                    case DataBuffer.TYPE_BYTE:
234                        byte[][] buf =
235                            ((DataBufferByte)currentTile.getDataBuffer()).getBankData();
236                        for (int i = 0; i < buf.length; i++)
237                            iis.readFully(buf[i], 0, buf[i].length);
238                        break;
239
240                    case DataBuffer.TYPE_SHORT:
241                        short[][] sbuf =
242                            ((DataBufferShort)currentTile.getDataBuffer()).getBankData();
243                        for (int i = 0; i < sbuf.length; i++)
244                            iis.readFully(sbuf[i], 0, sbuf[i].length);
245                        break;
246
247                    case DataBuffer.TYPE_USHORT:
248                        short[][] usbuf =
249                            ((DataBufferUShort)currentTile.getDataBuffer()).getBankData();
250                        for (int i = 0; i < usbuf.length; i++)
251                            iis.readFully(usbuf[i], 0, usbuf[i].length);
252                        break;
253                    case DataBuffer.TYPE_INT:
254                        int[][] ibuf =
255                            ((DataBufferInt)currentTile.getDataBuffer()).getBankData();
256                        for (int i = 0; i < ibuf.length; i++)
257                            iis.readFully(ibuf[i], 0, ibuf[i].length);
258                        break;
259                    case DataBuffer.TYPE_FLOAT:
260                        float[][] fbuf =
261                            ((DataBufferFloat)currentTile.getDataBuffer()).getBankData();
262                        for (int i = 0; i < fbuf.length; i++)
263                            iis.readFully(fbuf[i], 0, fbuf[i].length);
264                        break;
265                    case DataBuffer.TYPE_DOUBLE:
266                        double[][] dbuf =
267                            ((DataBufferDouble)currentTile.getDataBuffer()).getBankData();
268                        for (int i = 0; i < dbuf.length; i++)
269                            iis.readFully(dbuf[i], 0, dbuf[i].length);
270                        break;
271                }
272            } else {
273                currentTile = readSubsampledRaster((WritableRaster)currentTile);
274            }
275        } catch (IOException e) {
276            throw new RuntimeException(e);
277        }
278
279        if (currentTileGrid == null)
280            currentTileGrid = new Point(tileX, tileY);
281        else {
282            currentTileGrid.x = tileX;
283            currentTileGrid.y = tileY;
284        }
285
286        return currentTile;
287    }
288
289    public void readAsRaster(WritableRaster raster) throws java.io.IOException {
290        readSubsampledRaster(raster);
291    }
292
293    private Raster readSubsampledRaster(WritableRaster raster) throws IOException {
294        if (raster == null)
295            raster = Raster.createWritableRaster(
296                sampleModel.createCompatibleSampleModel(destinationRegion.x +
297                                                        destinationRegion.width,
298                                                        destinationRegion.y +
299                                                        destinationRegion.height),
300                new Point(destinationRegion.x, destinationRegion.y));
301
302        int numBands = sourceBands.length;
303        int dataType = sampleModel.getDataType();
304        int sampleSizeBit = DataBuffer.getDataTypeSize(dataType);
305        int sampleSizeByte = (sampleSizeBit + 7) / 8;   
306        
307        Rectangle destRect = raster.getBounds().intersection(destinationRegion);
308
309        int offx = destinationRegion.x;
310        int offy = destinationRegion.y;
311
312        int sourceSX = (destRect.x - offx) * scaleX + sourceOrigin.x;
313        int sourceSY = (destRect.y - offy) * scaleY + sourceOrigin.y;
314        int sourceEX = (destRect.width - 1) * scaleX + sourceSX;
315        int sourceEY = (destRect.height - 1) * scaleY + sourceSY;
316        int startXTile = sourceSX / tileWidth;
317        int startYTile = sourceSY / tileHeight;
318        int endXTile = sourceEX / tileWidth;
319        int endYTile = sourceEY / tileHeight;
320
321        startXTile = clip(startXTile, 0, maxXTile);
322        startYTile = clip(startYTile, 0, maxYTile);
323        endXTile = clip(endXTile, 0,  maxXTile);
324        endYTile = clip(endYTile, 0, maxYTile);
325
326        int totalXTiles = getNumXTiles();
327        int totalYTiles = getNumYTiles();
328        int totalTiles = totalXTiles * totalYTiles;
329
330        //The line buffer for the source
331        byte[] pixbuf = null;  // byte buffer for the decoded pixels.
332        short[] spixbuf = null;  // byte buffer for the decoded pixels.
333        int[] ipixbuf = null;  // byte buffer for the decoded pixels.
334        float[] fpixbuf = null;  // byte buffer for the decoded pixels.
335        double[] dpixbuf = null;  // byte buffer for the decoded pixels.
336
337        // A flag to show the ComponentSampleModel has a single data bank
338        boolean singleBank = true;
339        int pixelStride = 0;
340        int scanlineStride = 0;
341        int bandStride = 0;
342        int[] bandOffsets = null;
343        int[] bankIndices = null;
344
345        if (originalSampleModel instanceof ComponentSampleModel) {
346            ComponentSampleModel csm = (ComponentSampleModel)originalSampleModel;
347            bankIndices = csm.getBankIndices();
348            int maxBank = 0;
349            for (int i = 0; i < bankIndices.length; i++)
350                if (maxBank > bankIndices[i])
351                    maxBank = bankIndices[i];
352
353            if (maxBank > 0)
354                singleBank = false;
355            pixelStride = csm.getPixelStride();
356
357            scanlineStride = csm.getScanlineStride();
358            bandOffsets = csm.getBandOffsets();
359            for (int i = 0; i < bandOffsets.length; i++)
360                if (bandStride < bandOffsets[i])
361                    bandStride = bandOffsets[i];
362        } else if (originalSampleModel instanceof MultiPixelPackedSampleModel) {
363            scanlineStride =
364                ((MultiPixelPackedSampleModel)originalSampleModel).getScanlineStride();
365        } else if(originalSampleModel instanceof SinglePixelPackedSampleModel) {
366            pixelStride = 1;
367            scanlineStride =
368                ((SinglePixelPackedSampleModel)originalSampleModel).getScanlineStride();
369        }
370
371        // The dstination buffer for the raster
372        byte[] destPixbuf = null;  // byte buffer for the decoded pixels.
373        short[] destSPixbuf = null;  // byte buffer for the decoded pixels.
374        int[] destIPixbuf = null;  // byte buffer for the decoded pixels.
375        float[] destFPixbuf = null;  // byte buffer for the decoded pixels.
376        double[] destDPixbuf = null;  // byte buffer for the decoded pixels.
377        int[] destBandOffsets = null;
378        int destPixelStride = 0;
379        int destScanlineStride = 0;
380        int destSX = 0;                // The first pixel for the destionation
381
382        if (raster.getSampleModel() instanceof ComponentSampleModel) {
383            ComponentSampleModel csm =
384                (ComponentSampleModel)raster.getSampleModel();
385            bankIndices = csm.getBankIndices();
386            destBandOffsets = csm.getBandOffsets();
387            destPixelStride = csm.getPixelStride();
388            destScanlineStride = csm.getScanlineStride();
389            destSX = csm.getOffset(raster.getMinX() -
390                                   raster.getSampleModelTranslateX(),
391                                   raster.getMinY() -
392                                   raster.getSampleModelTranslateY())
393                    - destBandOffsets[0];
394
395            switch(dataType) {
396            case DataBuffer.TYPE_BYTE:
397                destPixbuf = ((DataBufferByte)raster.getDataBuffer()).getData();
398                break;
399            case DataBuffer.TYPE_SHORT:
400                destSPixbuf =
401                    ((DataBufferShort)raster.getDataBuffer()).getData();
402                break;
403
404            case DataBuffer.TYPE_USHORT:
405                destSPixbuf =
406                    ((DataBufferUShort)raster.getDataBuffer()).getData();
407                break;
408
409            case DataBuffer.TYPE_INT:
410                destIPixbuf =
411                    ((DataBufferInt)raster.getDataBuffer()).getData();
412                break;
413
414            case DataBuffer.TYPE_FLOAT:
415                destFPixbuf =
416                    ((DataBufferFloat)raster.getDataBuffer()).getData();
417                break;
418
419            case DataBuffer.TYPE_DOUBLE:
420                destDPixbuf =
421                    ((DataBufferDouble)raster.getDataBuffer()).getData();
422                break;
423            }
424        } else if (raster.getSampleModel() instanceof SinglePixelPackedSampleModel) {
425            numBands = 1;
426            bankIndices = new int[]{0};
427            destBandOffsets = new int[numBands];
428            for (int i = 0; i < numBands; i++)
429                destBandOffsets[i] = 0;
430            destPixelStride = 1;
431            destScanlineStride =
432                ((SinglePixelPackedSampleModel)raster.getSampleModel()).getScanlineStride();
433        }
434
435        // Start the data delivery to the cached consumers tile by tile
436        for(int y = startYTile; y <= endYTile; y++){
437            if (reader.getAbortRequest())
438                break;
439
440            // Loop on horizontal tiles
441            for(int x=startXTile; x <= endXTile; x++){
442                if (reader.getAbortRequest())
443                    break;
444
445                long tilePosition =
446                    position + (y * originalNumXTiles + x) * tileDataSize;
447                iis.seek(tilePosition);
448                float percentage = 
449                    (x - startXTile + y * totalXTiles) / totalXTiles;
450
451                int startX = x * tileWidth;
452                int startY = y * tileHeight;
453
454                int cTileHeight = tileHeight;
455                int cTileWidth = tileWidth;
456
457                if (startY + cTileHeight >= originalDimension.height)
458                    cTileHeight = originalDimension.height - startY;
459
460                if (startX + cTileWidth >= originalDimension.width)
461                    cTileWidth = originalDimension.width - startX;
462
463                int tx = startX;
464                int ty = startY;
465
466                // If source start position calculated by taking subsampling
467                // into account is after the tile's start X position, adjust
468                // the start position accordingly
469                if (sourceSX > startX) {
470                    cTileWidth += startX - sourceSX;
471                    tx = sourceSX;
472                    startX = sourceSX;
473                }
474
475                if (sourceSY > startY) {
476                    cTileHeight += startY - sourceSY;
477                    ty = sourceSY;
478                    startY = sourceSY;
479                }
480
481                // If source end position calculated by taking subsampling
482                // into account is prior to the tile's end X position, adjust
483                // the tile width to read accordingly
484                if (sourceEX < startX + cTileWidth -1) {
485                    cTileWidth += sourceEX - startX - cTileWidth + 1;
486                }
487
488                if (sourceEY < startY + cTileHeight - 1) {
489                    cTileHeight += sourceEY - startY - cTileHeight + 1;
490                }
491
492                // The start X in the destination
493                int x1 = (startX + scaleX - 1 - sourceOrigin.x) / scaleX;
494                int x2 = (startX + scaleX - 1 + cTileWidth - sourceOrigin.x) /
495                          scaleX;
496                int lineLength = x2 - x1;
497                x2 = (x2 - 1) * scaleX + sourceOrigin.x;
498
499                int y1 = (startY + scaleY -1 - sourceOrigin.y) /scaleY;
500                startX = x1 * scaleX + sourceOrigin.x;
501                startY = y1 * scaleY + sourceOrigin.y;
502
503                // offx is destination.x
504                x1 += offx;
505                y1 += offy;
506
507                tx -= x * tileWidth;
508                ty -= y * tileHeight;
509
510                if (sampleModel instanceof MultiPixelPackedSampleModel) {
511                    MultiPixelPackedSampleModel mppsm =
512                        (MultiPixelPackedSampleModel)originalSampleModel;
513
514                    iis.skipBytes(mppsm.getOffset(tx, ty) * sampleSizeByte);
515
516                    int readBytes = (mppsm.getOffset(x2, 0) -
517                                     mppsm.getOffset(startX, 0) + 1) *
518                                     sampleSizeByte;
519
520                    int skipLength = (scanlineStride * scaleY - readBytes) *
521                                        sampleSizeByte;
522                    readBytes *= sampleSizeByte;
523
524                    if (pixbuf == null || pixbuf.length < readBytes)
525                        pixbuf = new byte[readBytes];
526
527                    int bitoff = mppsm.getBitOffset(tx);
528
529                    for (int l = 0, m = y1; l < cTileHeight;
530                         l += scaleY, m++) {
531                        if (reader.getAbortRequest())
532                            break;
533                        iis.readFully(pixbuf, 0, readBytes);
534                        if (scaleX == 1) {
535
536                            if (bitoff != 0) {
537                                int mask1 = (255 << bitoff) & 255;
538                                int mask2 = ~mask1 & 255;
539                                int shift = 8 - bitoff;
540
541                                int n = 0;
542                                for (; n < readBytes -1; n++)
543                                    pixbuf[n] = (byte)(((pixbuf[n] & mask2) << shift) |
544                                                (pixbuf[n + 1] & mask1) >>bitoff);
545                                pixbuf[n] = (byte)((pixbuf[n] & mask2) << shift);
546                            }
547                        } else {
548
549                            int bit = 7 ;
550                            int pos = 0 ;
551                            int mask = 128;
552
553                            for (int n = 0, n1 = startX & 7;
554                                n < lineLength; n++, n1 += scaleX) {
555                                pixbuf[pos] = (byte)((pixbuf[pos] & ~(1 << bit)) |
556                                    (((pixbuf[n1 >> 3] >> (7 - (n1 & 7))) & 1) << bit));
557                                bit--;
558                                if (bit == -1) {
559                                    bit = 7;
560                                    pos++;
561                                }
562                            }
563                        }
564
565                        ImageUtil.setPackedBinaryData(pixbuf, raster,
566                                                      new Rectangle(x1, m,
567                                                                    lineLength,
568                                                                    1));
569                        iis.skipBytes(skipLength);
570                        if (destImage != null)
571                            reader.processImageUpdateWrapper(destImage, x1, m,
572                                                             cTileWidth, 1, 1, 1,
573                                                             destinationBands);
574
575                        reader.processImageProgressWrapper(percentage +
576                                                    (l - startY + 1.0F) /
577                                                    cTileHeight / totalTiles);
578                    }
579                } else {
580
581                    int readLength, skipLength;
582                    if (pixelStride < scanlineStride) {
583                        readLength = cTileWidth * pixelStride;
584                        skipLength = (scanlineStride * scaleY - readLength) *
585                                      sampleSizeByte;
586                    } else {
587                        readLength = cTileHeight * scanlineStride;
588                        skipLength = (pixelStride * scaleX - readLength) *
589                                      sampleSizeByte;
590                    }
591
592                    //Allocate buffer for all the types
593                    switch (sampleModel.getDataType()) {
594                    case DataBuffer.TYPE_BYTE:
595                        if (pixbuf == null || pixbuf.length < readLength)
596                        pixbuf = new byte[readLength];
597                        break;
598
599                    case DataBuffer.TYPE_SHORT:
600                    case DataBuffer.TYPE_USHORT:
601                        if (spixbuf == null || spixbuf.length < readLength)
602                            spixbuf = new short[readLength];
603                        break;
604
605                    case DataBuffer.TYPE_INT:
606                        if (ipixbuf == null || ipixbuf.length < readLength)
607                            ipixbuf = new int[readLength];
608                        break;
609
610                    case DataBuffer.TYPE_FLOAT:
611                        if (fpixbuf == null || fpixbuf.length < readLength)
612                            fpixbuf = new float[readLength];
613                        break;
614
615                    case DataBuffer.TYPE_DOUBLE:
616                        if (dpixbuf == null || dpixbuf.length < readLength)
617                            dpixbuf = new double[readLength];
618                        break;
619                    }
620
621                    if (sampleModel instanceof PixelInterleavedSampleModel) {
622                        iis.skipBytes((tx * pixelStride + ty * scanlineStride) *
623                                      sampleSizeByte);
624
625                        // variables for ther loop
626                        int outerFirst, outerSecond, outerStep, outerBound;
627                        int innerStep, innerStep1, outerStep1;
628                        if (pixelStride < scanlineStride) {
629                            outerFirst = 0;
630                            outerSecond = y1;
631                            outerStep = scaleY;
632                            outerBound = cTileHeight;
633                            innerStep = scaleX * pixelStride;
634                            innerStep1 = destPixelStride;
635                            outerStep1 = destScanlineStride;
636                        } else {
637                            outerFirst = 0;
638                            outerSecond = x1;
639                            outerStep = scaleX;
640                            outerBound = cTileWidth;
641                            innerStep = scaleY * scanlineStride;
642                            innerStep1 = destScanlineStride;
643                            outerStep1 = destPixelStride;
644                        }
645
646                        int destPos =
647                            destSX + (y1 - raster.getSampleModelTranslateY())
648                                      * destScanlineStride +
649                                      (x1 - raster.getSampleModelTranslateX())
650                                      * destPixelStride;
651
652                        for (int l = outerFirst, m = outerSecond; l < outerBound;
653                             l += outerStep, m++) {
654                            if (reader.getAbortRequest())
655                                break;
656
657                            switch(dataType) {
658                            case DataBuffer.TYPE_BYTE:
659                                if (innerStep == numBands &&
660                                    innerStep1 == numBands)
661                                    iis.readFully(destPixbuf, destPos, readLength);
662                                else
663                                    iis.readFully(pixbuf, 0, readLength);
664                                break;
665                            case DataBuffer.TYPE_SHORT:
666                            case DataBuffer.TYPE_USHORT:
667                                if (innerStep == numBands &&
668                                    innerStep1 == numBands) {
669                                    iis.readFully(destSPixbuf, destPos, readLength);
670                                } else
671                                    iis.readFully(spixbuf, 0, readLength);
672                                break;
673                            case DataBuffer.TYPE_INT:
674                                if (innerStep == numBands &&
675                                    innerStep1 == numBands)
676                                    iis.readFully(destIPixbuf, destPos, readLength);
677                                else
678                                    iis.readFully(ipixbuf, 0, readLength);
679                                break;
680                            case DataBuffer.TYPE_FLOAT:
681                                if (innerStep == numBands &&
682                                    innerStep1 == numBands)
683                                    iis.readFully(destFPixbuf, destPos, readLength);
684                                else
685                                    iis.readFully(fpixbuf, 0, readLength);
686                                break;
687                            case DataBuffer.TYPE_DOUBLE:
688                                if (innerStep == numBands &&
689                                    innerStep1 == numBands)
690                                    iis.readFully(destDPixbuf, destPos, readLength);
691                                else
692                                    iis.readFully(dpixbuf, 0, readLength);
693                                break;
694                            }
695
696                            if (innerStep != numBands || innerStep1 != numBands)
697                                for (int b = 0; b < numBands; b++) {
698                                    int destBandOffset =
699                                        destBandOffsets[destinationBands[b]];
700                                    destPos += destBandOffset;
701
702                                    int sourceBandOffset =
703                                        bandOffsets[sourceBands[b]];
704
705                                    switch(dataType) {
706                                    case DataBuffer.TYPE_BYTE:
707                                        for (int m1 = 0, n = destPos; m1 < readLength;
708                                             m1 += innerStep, n += innerStep1) {
709                                            destPixbuf[n]
710                                                    = pixbuf[m1 + sourceBandOffset];
711                                        }
712                                        break;
713                                    case DataBuffer.TYPE_SHORT:
714                                    case DataBuffer.TYPE_USHORT:
715                                        for (int m1 = 0, n = destPos; m1 < readLength;
716                                             m1 += innerStep, n += innerStep1) {
717                                            destSPixbuf[n]
718                                                = spixbuf[m1 + sourceBandOffset];
719                                        }
720                                        break;
721                                    case DataBuffer.TYPE_INT:
722                                        for (int m1 = 0, n = destPos; m1 < readLength;
723                                             m1 += innerStep, n += innerStep1) {
724                                            destIPixbuf[n]
725                                                = ipixbuf[m1 + sourceBandOffset];
726                                        }
727                                        break;
728                                    case DataBuffer.TYPE_FLOAT:
729                                        for (int m1 = 0, n = destPos; m1 < readLength;
730                                             m1 += innerStep, n += innerStep1) {
731                                            destFPixbuf[n]
732                                                = fpixbuf[m1 + sourceBandOffset];
733                                        }
734                                        break;
735                                    case DataBuffer.TYPE_DOUBLE:
736                                        for (int m1 = 0, n = destPos; m1 < readLength;
737                                             m1 += innerStep, n += innerStep1) {
738                                            destDPixbuf[n]
739                                                = dpixbuf[m1 + sourceBandOffset];
740                                        }
741                                        break;
742                                    }
743                                    destPos -= destBandOffset;
744                                }
745
746                            iis.skipBytes(skipLength);
747                            destPos += outerStep1;
748
749                            if (destImage != null)
750                                if (pixelStride < scanlineStride)
751                                reader.processImageUpdateWrapper(destImage,
752                                                                 x1, m,
753                                                                 outerBound,
754                                                                 1, 1, 1,
755                                                                 destinationBands);
756                                else
757                                reader.processImageUpdateWrapper(destImage,
758                                                                 m, y1,
759                                                                 1, outerBound,
760                                                                 1, 1,
761                                                                 destinationBands);
762
763                            reader.processImageProgressWrapper(percentage +
764                                                            (l + 1.0F) /
765                                                            outerBound /
766                                                            totalTiles);
767                        }
768                    } else if (sampleModel instanceof BandedSampleModel ||
769                               sampleModel instanceof SinglePixelPackedSampleModel ||
770                               bandStride == 0) {
771                        boolean isBanded = sampleModel instanceof BandedSampleModel;
772
773                        int bandSize =
774                            (int)ImageUtil.getBandSize(originalSampleModel);
775
776                        for (int b = 0; b < numBands; b++) {
777                            iis.seek(tilePosition + bandSize * sourceBands[b] *
778                                     sampleSizeByte);
779                            int destBandOffset =
780                                destBandOffsets[destinationBands[b]];
781
782                            iis.skipBytes((ty * scanlineStride + tx * pixelStride) *
783                                          sampleSizeByte);
784
785                            // variables for ther loop
786                            int outerFirst, outerSecond, outerStep, outerBound;
787                            int innerStep, innerStep1, outerStep1;
788                            if (pixelStride < scanlineStride) {
789                                outerFirst = 0;
790                                outerSecond = y1;
791                                outerStep = scaleY;
792                                outerBound = cTileHeight;
793                                innerStep = scaleX * pixelStride;
794                                innerStep1 = destPixelStride;
795                                outerStep1 = destScanlineStride;
796                            } else {
797                                outerFirst = 0;
798                                outerSecond = x1;
799                                outerStep = scaleX;
800                                outerBound = cTileWidth;
801                                innerStep = scaleY * scanlineStride;
802                                innerStep1 = destScanlineStride;
803                                outerStep1 = destPixelStride;
804                            }
805
806                            int destPos = destSX + (y1 - raster.getSampleModelTranslateY())* destScanlineStride +
807                                      (x1 - raster.getSampleModelTranslateX()) * destPixelStride + destBandOffset;
808
809                            int bank = bankIndices[destinationBands[b]];
810
811                            switch(dataType) {
812                            case DataBuffer.TYPE_BYTE:
813                                destPixbuf =
814                                    ((DataBufferByte)raster.getDataBuffer()).getData(bank);
815                                break;
816                            case DataBuffer.TYPE_SHORT:
817                                destSPixbuf =
818                                    ((DataBufferShort)raster.getDataBuffer()).getData(bank);
819                                break;
820
821                            case DataBuffer.TYPE_USHORT:
822                                destSPixbuf =
823                                    ((DataBufferUShort)raster.getDataBuffer()).getData(bank);
824                                break;
825
826                            case DataBuffer.TYPE_INT:
827                                destIPixbuf =
828                                    ((DataBufferInt)raster.getDataBuffer()).getData(bank);
829                                break;
830
831                            case DataBuffer.TYPE_FLOAT:
832                                destFPixbuf =
833                                    ((DataBufferFloat)raster.getDataBuffer()).getData(bank);
834                                break;
835
836                            case DataBuffer.TYPE_DOUBLE:
837                                destDPixbuf =
838                                    ((DataBufferDouble)raster.getDataBuffer()).getData(bank);
839                                break;
840                            }
841
842                            for (int l = outerFirst, m = outerSecond; l < outerBound;
843                                 l += outerStep, m++) {
844                                if (reader.getAbortRequest())
845                                    break;
846
847                                switch(dataType) {
848                                case DataBuffer.TYPE_BYTE:
849                                    if (innerStep == 1 && innerStep1 == 1) {
850                                        iis.readFully(destPixbuf, destPos, readLength);
851                                    } else {
852                                        iis.readFully(pixbuf, 0, readLength);
853                                        for (int m1 = 0, n = destPos; m1 < readLength;
854                                             m1 += innerStep, n += innerStep1) {
855                                            destPixbuf[n] = pixbuf[m1];
856                                        }
857                                    }
858                                    break;
859                                case DataBuffer.TYPE_SHORT:
860                                case DataBuffer.TYPE_USHORT:
861                                    if (innerStep == 1 && innerStep1 == 1) {
862                                        iis.readFully(destSPixbuf, destPos, readLength);
863                                    } else {
864                                        iis.readFully(spixbuf, 0, readLength);
865                                        for (int m1 = 0, n = destPos; m1 < readLength;
866                                             m1 += innerStep, n += innerStep1) {
867                                            destSPixbuf[n] = spixbuf[m1];
868                                        }
869                                    }
870                                    break;
871                                case DataBuffer.TYPE_INT:
872                                    if (innerStep == 1 && innerStep1 == 1) {
873                                        iis.readFully(destIPixbuf, destPos, readLength);
874                                    } else {
875                                        iis.readFully(ipixbuf, 0, readLength);
876                                        for (int m1 = 0, n = destPos; m1 < readLength;
877                                             m1 += innerStep, n += innerStep1) {
878                                            destIPixbuf[n] = ipixbuf[m1];
879                                        }
880                                    }
881                                    break;
882                                case DataBuffer.TYPE_FLOAT:
883                                    if (innerStep == 1 && innerStep1 == 1) {
884                                        iis.readFully(destFPixbuf, destPos, readLength);
885                                    } else {
886                                        iis.readFully(fpixbuf, 0, readLength);
887                                        for (int m1 = 0, n = destPos; m1 < readLength;
888                                             m1 += innerStep, n += innerStep1) {
889                                            destFPixbuf[n] = fpixbuf[m1];
890                                        }
891                                    }
892                                    break;
893                                case DataBuffer.TYPE_DOUBLE:
894                                    if (innerStep == 1 && innerStep1 == 1) {
895                                        iis.readFully(destDPixbuf, destPos, readLength);
896                                    } else {
897                                        iis.readFully(dpixbuf, 0, readLength);
898                                        for (int m1 = 0, n = destPos; m1 < readLength;
899                                             m1 += innerStep, n += innerStep1) {
900                                            destDPixbuf[n] = dpixbuf[m1];
901                                        }
902                                    }
903                                    break;
904                                }
905
906                                iis.skipBytes(skipLength);
907                                destPos += outerStep1;
908
909                                if (destImage != null) {
910                                    int[] destBands =
911                                        new int[] {destinationBands[b]};
912                                    if (pixelStride < scanlineStride)
913                                    reader.processImageUpdateWrapper(destImage,
914                                                                     x1, m,
915                                                                     outerBound,
916                                                                     1, 1, 1,
917                                                                     destBands);
918                                    else
919                                    reader.processImageUpdateWrapper(destImage,
920                                                                     m, y1, 1,
921                                                                     outerBound,
922                                                                     1, 1,
923                                                                     destBands);
924                                }
925
926                                reader.processImageProgressWrapper(
927                                    (percentage + 
928                                     (l+1.0F)/outerBound/numBands/totalTiles) *
929                                    100.0F);
930                            }
931                        }
932                    } else if (sampleModel instanceof ComponentSampleModel) {
933                        //for the other case, may slow
934                        //Allocate buffer for all the types
935                        int bufferSize = (int)tileDataSize;
936
937                        switch (sampleModel.getDataType()) {
938                        case DataBuffer.TYPE_BYTE:
939                            if (pixbuf == null || pixbuf.length < tileDataSize)
940                            pixbuf = new byte[(int)tileDataSize];
941                            iis.readFully(pixbuf, 0, (int)tileDataSize);
942                            break;
943
944                        case DataBuffer.TYPE_SHORT:
945                        case DataBuffer.TYPE_USHORT:
946                            bufferSize /= 2;
947                            if (spixbuf == null || spixbuf.length < bufferSize)
948                                spixbuf = new short[(int)bufferSize];
949                            iis.readFully(spixbuf, 0, (int)bufferSize);
950                            break;
951
952                        case DataBuffer.TYPE_INT:
953                            bufferSize /= 4;
954                            if (ipixbuf == null || ipixbuf.length < bufferSize)
955                                ipixbuf = new int[(int)bufferSize];
956                            iis.readFully(ipixbuf, 0, (int)bufferSize);
957                            break;
958
959                        case DataBuffer.TYPE_FLOAT:
960                            bufferSize /= 4;
961                            if (fpixbuf == null || fpixbuf.length < bufferSize)
962                                fpixbuf = new float[(int)bufferSize];
963                            iis.readFully(fpixbuf, 0, (int)bufferSize);
964                            break;
965
966                        case DataBuffer.TYPE_DOUBLE:
967                            bufferSize /= 8;
968                            if (dpixbuf == null || dpixbuf.length < bufferSize)
969                                dpixbuf = new double[(int)bufferSize];
970                            iis.readFully(dpixbuf, 0, (int)bufferSize);
971                            break;
972                        }
973
974                        for (int b = 0; b < numBands; b++) {
975                            int destBandOffset =
976                                destBandOffsets[destinationBands[b]];
977
978                            int destPos =
979                                ((ComponentSampleModel)raster.getSampleModel()).getOffset(
980                                    x1-raster.getSampleModelTranslateX(),
981                                    y1-raster.getSampleModelTranslateY(),
982                                    destinationBands[b]);
983
984                            int bank = bankIndices[destinationBands[b]];
985
986                            switch(dataType) {
987                            case DataBuffer.TYPE_BYTE:
988                            destPixbuf =
989                                ((DataBufferByte)raster.getDataBuffer()).getData(bank);
990                            break;
991                            case DataBuffer.TYPE_SHORT:
992                            destSPixbuf =
993                                ((DataBufferShort)raster.getDataBuffer()).getData(bank);
994                            break;
995
996                            case DataBuffer.TYPE_USHORT:
997                            destSPixbuf =
998                                ((DataBufferUShort)raster.getDataBuffer()).getData(bank);
999                            break;
1000
1001                            case DataBuffer.TYPE_INT:
1002                            destIPixbuf =
1003                                ((DataBufferInt)raster.getDataBuffer()).getData(bank);
1004                            break;
1005
1006                            case DataBuffer.TYPE_FLOAT:
1007                            destFPixbuf =
1008                                ((DataBufferFloat)raster.getDataBuffer()).getData(bank);
1009                            break;
1010
1011                            case DataBuffer.TYPE_DOUBLE:
1012                            destDPixbuf =
1013                                ((DataBufferDouble)raster.getDataBuffer()).getData(bank);
1014                            break;
1015                            }
1016
1017                            int srcPos =
1018                                ((ComponentSampleModel)originalSampleModel).getOffset(tx, ty, sourceBands[b]);
1019                            int skipX = scaleX * pixelStride;;
1020                            for (int l = 0, m = y1; l < cTileHeight;
1021                                 l += scaleY, m++) {
1022                                if (reader.getAbortRequest())
1023                                    break;
1024
1025                                switch(dataType) {
1026                                case DataBuffer.TYPE_BYTE:
1027                                    for (int n = 0, m1 = srcPos, m2 = destPos;
1028                                         n < lineLength;
1029                                         n++, m1 += skipX, m2 += destPixelStride)
1030                                        destPixbuf[m2] = pixbuf[m1];
1031                                    break;
1032                                case DataBuffer.TYPE_SHORT:
1033                                case DataBuffer.TYPE_USHORT:
1034                                    for (int n = 0, m1 = srcPos, m2 = destPos;
1035                                         n < lineLength;
1036                                         n++, m1 += skipX, m2 += destPixelStride)
1037                                        destSPixbuf[m2] = spixbuf[m1];
1038                                    break;
1039                                case DataBuffer.TYPE_INT:
1040                                    for (int n = 0, m1 = srcPos, m2 = destPos;
1041                                         n < lineLength;
1042                                         n++, m1 += skipX, m2 += destPixelStride)
1043                                        destIPixbuf[m2] = ipixbuf[m1];
1044                                    break;
1045                                case DataBuffer.TYPE_FLOAT:
1046                                    for (int n = 0, m1 = srcPos, m2 = destPos;
1047                                         n < lineLength;
1048                                         n++, m1 += skipX, m2 += destPixelStride)
1049                                        destFPixbuf[m2] = fpixbuf[m1];
1050                                    break;
1051                                case DataBuffer.TYPE_DOUBLE:
1052                                    for (int n = 0, m1 = srcPos, m2 = destPos;
1053                                         n < lineLength;
1054                                         n++, m1 += skipX, m2 += destPixelStride)
1055                                        destDPixbuf[m2] = dpixbuf[m1];
1056                                    break;
1057                                }
1058
1059                                destPos += destScanlineStride;
1060                                srcPos += scanlineStride * scaleY;
1061
1062                                if (destImage != null) {
1063                                    int[] destBands =
1064                                        new int[] {destinationBands[b]};
1065                                    reader.processImageUpdateWrapper(destImage,
1066                                                                 x1, m,
1067                                                                 cTileHeight,
1068                                                                 1, 1, 1,
1069                                                                 destBands);
1070                                }
1071
1072                                reader.processImageProgressWrapper(percentage +
1073                                                                (l + 1.0F) /
1074                                                                cTileHeight /
1075                                                                numBands /
1076                                                                totalTiles);
1077                            }
1078                        }
1079                    } else {
1080                        throw new IllegalArgumentException(I18N.getString("RawRenderedImage1"));
1081                    }
1082                }
1083            } // End loop on horizontal tiles
1084        } // End loop on vertical tiles
1085
1086        return raster;
1087    }
1088
1089    public void setDestImage(BufferedImage image) {
1090        destImage = image;
1091    }
1092
1093    public void clearDestImage() {
1094        destImage = null;
1095    }
1096
1097    private int getTileNum(int x, int y) {
1098        int num = (y - getMinTileY()) * getNumXTiles() + x - getMinTileX();
1099
1100        if (num < 0 || num >= getNumXTiles() * getNumYTiles())
1101            throw new IllegalArgumentException(I18N.getString("RawRenderedImage0"));
1102
1103        return num;
1104    }
1105
1106    private int clip(int value, int min, int max) {
1107        if (value < min)
1108            value = min;
1109        if (value > max)
1110            value = max;
1111        return value;
1112    }
1113}