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