KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > imageio > plugins > bmp > BMPImageReader


1 /*
2  * @(#)BMPImageReader.java 1.11 03/12/19 16:53:53
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package com.sun.imageio.plugins.bmp;
9
10 import java.awt.Point JavaDoc;
11 import java.awt.Rectangle JavaDoc;
12 import java.awt.Transparency JavaDoc;
13 import java.awt.color.ColorSpace JavaDoc;
14 import java.awt.color.ICC_ColorSpace JavaDoc;
15 import java.awt.color.ICC_Profile JavaDoc;
16 import java.awt.image.BufferedImage JavaDoc;
17 import java.awt.image.ColorModel JavaDoc;
18 import java.awt.image.ComponentColorModel JavaDoc;
19 import java.awt.image.ComponentSampleModel JavaDoc;
20 import java.awt.image.DataBuffer JavaDoc;
21 import java.awt.image.DataBufferByte JavaDoc;
22 import java.awt.image.DataBufferInt JavaDoc;
23 import java.awt.image.DataBufferUShort JavaDoc;
24 import java.awt.image.DirectColorModel JavaDoc;
25 import java.awt.image.IndexColorModel JavaDoc;
26 import java.awt.image.MultiPixelPackedSampleModel JavaDoc;
27 import java.awt.image.PixelInterleavedSampleModel JavaDoc;
28 import java.awt.image.Raster JavaDoc;
29 import java.awt.image.SampleModel JavaDoc;
30 import java.awt.image.SinglePixelPackedSampleModel JavaDoc;
31 import java.awt.image.WritableRaster JavaDoc;
32
33 import javax.imageio.IIOException JavaDoc;
34 import javax.imageio.ImageIO JavaDoc;
35 import javax.imageio.ImageReader JavaDoc;
36 import javax.imageio.ImageReadParam JavaDoc;
37 import javax.imageio.ImageTypeSpecifier JavaDoc;
38 import javax.imageio.metadata.IIOMetadata JavaDoc;
39 import javax.imageio.spi.ImageReaderSpi JavaDoc;
40 import javax.imageio.stream.ImageInputStream JavaDoc;
41 import javax.imageio.event.IIOReadProgressListener JavaDoc;
42 import javax.imageio.event.IIOReadUpdateListener JavaDoc;
43 import javax.imageio.event.IIOReadWarningListener JavaDoc;
44
45 import java.io.*;
46 import java.nio.*;
47 import java.util.ArrayList JavaDoc;
48 import java.util.Iterator JavaDoc;
49 import java.util.StringTokenizer JavaDoc;
50
51 import com.sun.imageio.plugins.common.ImageUtil;
52 import com.sun.imageio.plugins.common.I18N;
53
54 /** This class is the Java Image IO plugin reader for BMP images.
55  * It may subsample the image, clip the image, select sub-bands,
56  * and shift the decoded image origin if the proper decoding parameter
57  * are set in the provided <code>ImageReadParam</code>.
58  *
59  * This class supports Microsoft Windows Bitmap Version 3-5,
60  * as well as OS/2 Bitmap Version 2.x (for single-image BMP file).
61  */

62 public class BMPImageReader extends ImageReader JavaDoc implements BMPConstants {
63     // BMP Image types
64
private static final int VERSION_2_1_BIT = 0;
65     private static final int VERSION_2_4_BIT = 1;
66     private static final int VERSION_2_8_BIT = 2;
67     private static final int VERSION_2_24_BIT = 3;
68
69     private static final int VERSION_3_1_BIT = 4;
70     private static final int VERSION_3_4_BIT = 5;
71     private static final int VERSION_3_8_BIT = 6;
72     private static final int VERSION_3_24_BIT = 7;
73
74     private static final int VERSION_3_NT_16_BIT = 8;
75     private static final int VERSION_3_NT_32_BIT = 9;
76
77     private static final int VERSION_4_1_BIT = 10;
78     private static final int VERSION_4_4_BIT = 11;
79     private static final int VERSION_4_8_BIT = 12;
80     private static final int VERSION_4_16_BIT = 13;
81     private static final int VERSION_4_24_BIT = 14;
82     private static final int VERSION_4_32_BIT = 15;
83
84     // BMP variables
85
private long bitmapFileSize;
86     private long bitmapOffset;
87     private long compression;
88     private long imageSize;
89     private byte palette[];
90     private int imageType;
91     private int numBands;
92     private boolean isBottomUp;
93     private int bitsPerPixel;
94     private int redMask, greenMask, blueMask, alphaMask;
95
96     private SampleModel JavaDoc sampleModel, originalSampleModel;
97     private ColorModel JavaDoc colorModel, originalColorModel;
98
99     /** The input stream where reads from */
100     private ImageInputStream JavaDoc iis = null;
101
102     /** Indicates whether the header is read. */
103     private boolean gotHeader = false;
104
105     /** The original image width. */
106     private int width;
107
108     /** The original image height. */
109     private int height;
110
111     /** The destination region. */
112     private Rectangle JavaDoc destinationRegion;
113
114     /** The source region. */
115     private Rectangle JavaDoc sourceRegion;
116
117     /** The metadata from the stream. */
118     private BMPMetadata metadata;
119
120     /** The destination image. */
121     private BufferedImage JavaDoc bi;
122
123     /** Indicates whether subsampled, subregion is required, and offset is
124      * defined
125      */

126     private boolean noTransform = true;
127
128     /** Indicates whether subband is selected. */
129     private boolean seleBand = false;
130
131     /** The scaling factors. */
132     private int scaleX, scaleY;
133
134     /** source and destination bands. */
135     private int[] sourceBands, destBands;
136
137     /** Constructs <code>BMPImageReader</code> from the provided
138      * <code>ImageReaderSpi</code>.
139      */

140     public BMPImageReader(ImageReaderSpi JavaDoc originator) {
141         super(originator);
142     }
143
144     /** Overrides the method defined in the superclass. */
145     public void setInput(Object JavaDoc input,
146                          boolean seekForwardOnly,
147                          boolean ignoreMetadata) {
148         super.setInput(input, seekForwardOnly, ignoreMetadata);
149         iis = (ImageInputStream JavaDoc) input; // Always works
150
if(iis != null)
151             iis.setByteOrder(ByteOrder.LITTLE_ENDIAN);
152         resetHeaderInfo();
153     }
154
155     /** Overrides the method defined in the superclass. */
156     public int getNumImages(boolean allowSearch) throws IOException JavaDoc {
157         if (iis == null) {
158             throw new IllegalStateException JavaDoc(I18N.getString("GetNumImages0"));
159         }
160         if (seekForwardOnly && allowSearch) {
161             throw new IllegalStateException JavaDoc(I18N.getString("GetNumImages1"));
162         }
163         return 1;
164     }
165
166     public int getWidth(int imageIndex) throws IOException JavaDoc {
167         checkIndex(imageIndex);
168         readHeader();
169         return width;
170     }
171
172     public int getHeight(int imageIndex) throws IOException JavaDoc {
173         checkIndex(imageIndex);
174         readHeader();
175         return height;
176     }
177
178     private void checkIndex(int imageIndex) {
179         if (imageIndex != 0) {
180             throw new IndexOutOfBoundsException JavaDoc(I18N.getString("BMPImageReader0"));
181         }
182     }
183
184     public void readHeader() throws IOException JavaDoc {
185         if (gotHeader)
186             return;
187
188         if (iis == null) {
189             throw new IllegalStateException JavaDoc("Input source not set!");
190         }
191         int profileData = 0, profileSize = 0;
192
193         this.metadata = new BMPMetadata();
194         iis.mark();
195
196         // read and check the magic marker
197
byte[] marker = new byte[2];
198         iis.read(marker);
199         if (marker[0] != 0x42 || marker[1] != 0x4d)
200             throw new IllegalArgumentException JavaDoc(I18N.getString("BMPImageReader1"));
201
202         // Read file size
203
bitmapFileSize = iis.readUnsignedInt();
204         // skip the two reserved fields
205
iis.skipBytes(4);
206
207         // Offset to the bitmap from the beginning
208
bitmapOffset = iis.readUnsignedInt();
209         // End File Header
210

211         // Start BitmapCoreHeader
212
long size = iis.readUnsignedInt();
213
214         if (size == 12) {
215             width = iis.readShort();
216             height = iis.readShort();
217         } else {
218             width = iis.readInt();
219             height = iis.readInt();
220         }
221
222         metadata.width = width;
223         metadata.height = height;
224
225         int planes = iis.readUnsignedShort();
226         bitsPerPixel = iis.readUnsignedShort();
227
228         //metadata.colorPlane = planes;
229
metadata.bitsPerPixel = (short)bitsPerPixel;
230
231         // As BMP always has 3 rgb bands, except for Version 5,
232
// which is bgra
233
numBands = 3;
234
235         if (size == 12) {
236             // Windows 2.x and OS/2 1.x
237
metadata.bmpVersion = VERSION_2;
238
239             // Classify the image type
240
if (bitsPerPixel == 1) {
241                 imageType = VERSION_2_1_BIT;
242             } else if (bitsPerPixel == 4) {
243                 imageType = VERSION_2_4_BIT;
244             } else if (bitsPerPixel == 8) {
245                 imageType = VERSION_2_8_BIT;
246             } else if (bitsPerPixel == 24) {
247                 imageType = VERSION_2_24_BIT;
248             }
249
250             // Read in the palette
251
int numberOfEntries = (int)((bitmapOffset - 14 - size) / 3);
252             int sizeOfPalette = numberOfEntries*3;
253             palette = new byte[sizeOfPalette];
254             iis.readFully(palette, 0, sizeOfPalette);
255             metadata.palette = palette;
256             metadata.paletteSize = numberOfEntries;
257         } else {
258             compression = iis.readUnsignedInt();
259             imageSize = iis.readUnsignedInt();
260             long xPelsPerMeter = iis.readInt();
261             long yPelsPerMeter = iis.readInt();
262             long colorsUsed = iis.readUnsignedInt();
263             long colorsImportant = iis.readUnsignedInt();
264
265             metadata.compression = (int)compression;
266             metadata.xPixelsPerMeter = (int)xPelsPerMeter;
267             metadata.yPixelsPerMeter = (int)yPelsPerMeter;
268             metadata.colorsUsed = (int)colorsUsed;
269             metadata.colorsImportant = (int)colorsImportant;
270
271             if (size == 40) {
272                 // Windows 3.x and Windows NT
273
switch((int)compression) {
274
275                 case BI_RGB: // No compression
276
case BI_RLE8: // 8-bit RLE compression
277
case BI_RLE4: // 4-bit RLE compression
278
case BI_PNG:
279                 case BI_JPEG:
280
281                     // Read in the palette
282
int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
283                     int sizeOfPalette = numberOfEntries * 4;
284                     palette = new byte[sizeOfPalette];
285                     iis.readFully(palette, 0, sizeOfPalette);
286
287                     metadata.palette = palette;
288                     metadata.paletteSize = numberOfEntries;
289
290                     if (bitsPerPixel == 1) {
291                         imageType = VERSION_3_1_BIT;
292                     } else if (bitsPerPixel == 4) {
293                         imageType = VERSION_3_4_BIT;
294                     } else if (bitsPerPixel == 8) {
295                         imageType = VERSION_3_8_BIT;
296                     } else if (bitsPerPixel == 24) {
297                         imageType = VERSION_3_24_BIT;
298                     } else if (bitsPerPixel == 16) {
299                         imageType = VERSION_3_NT_16_BIT;
300                 
301                         redMask = 0x7C00;
302                         greenMask = 0x3E0;
303                         blueMask = (1 << 5) - 1;// 0x1F;
304
metadata.redMask = redMask;
305                         metadata.greenMask = greenMask;
306                         metadata.blueMask = blueMask;
307                     } else if (bitsPerPixel == 32) {
308                         imageType = VERSION_3_NT_32_BIT;
309                         redMask = 0x00FF0000;
310                         greenMask = 0x0000FF00;
311                         blueMask = 0x000000FF;
312                         metadata.redMask = redMask;
313                         metadata.greenMask = greenMask;
314                         metadata.blueMask = blueMask;
315                     }
316
317                     metadata.bmpVersion = VERSION_3;
318                     break;
319
320                 case BI_BITFIELDS:
321
322                     if (bitsPerPixel == 16) {
323                         imageType = VERSION_3_NT_16_BIT;
324                     } else if (bitsPerPixel == 32) {
325                         imageType = VERSION_3_NT_32_BIT;
326                     }
327
328                     // BitsField encoding
329
redMask = (int)iis.readUnsignedInt();
330                     greenMask = (int)iis.readUnsignedInt();
331                     blueMask = (int)iis.readUnsignedInt();
332                     metadata.redMask = redMask;
333                     metadata.greenMask = greenMask;
334                     metadata.blueMask = blueMask;
335
336                     if (colorsUsed != 0) {
337                         // there is a palette
338
sizeOfPalette = (int)colorsUsed*4;
339                         palette = new byte[sizeOfPalette];
340                         iis.readFully(palette, 0, sizeOfPalette);
341
342                         metadata.palette = palette;
343                         metadata.paletteSize = (int)colorsUsed;
344                     }
345                     metadata.bmpVersion = VERSION_3_NT;
346
347                     break;
348                 default:
349                     throw new
350                         RuntimeException JavaDoc(I18N.getString("BMPImageReader2"));
351                 }
352             } else if (size == 108 || size == 124) {
353                 // Windows 4.x BMP
354
if (size == 108)
355                     metadata.bmpVersion = VERSION_4;
356                 else if (size == 124)
357                     metadata.bmpVersion = VERSION_5;
358
359                 // rgb masks, valid only if comp is BI_BITFIELDS
360
redMask = (int)iis.readUnsignedInt();
361                 greenMask = (int)iis.readUnsignedInt();
362                 blueMask = (int)iis.readUnsignedInt();
363                 // Only supported for 32bpp BI_RGB argb
364
alphaMask = (int)iis.readUnsignedInt();
365                 long csType = iis.readUnsignedInt();
366                 int redX = iis.readInt();
367                 int redY = iis.readInt();
368                 int redZ = iis.readInt();
369                 int greenX = iis.readInt();
370                 int greenY = iis.readInt();
371                 int greenZ = iis.readInt();
372                 int blueX = iis.readInt();
373                 int blueY = iis.readInt();
374                 int blueZ = iis.readInt();
375                 long gammaRed = iis.readUnsignedInt();
376                 long gammaGreen = iis.readUnsignedInt();
377                 long gammaBlue = iis.readUnsignedInt();
378
379                 if (size == 124) {
380                     metadata.intent = iis.readInt();
381                     profileData = iis.readInt();
382                     profileSize = iis.readInt();
383                     iis.skipBytes(4);
384                 }
385
386                 metadata.colorSpace = (int)csType;
387
388                 if (csType == LCS_CALIBRATED_RGB) {
389                     // All the new fields are valid only for this case
390
metadata.redX = redX;
391                     metadata.redY = redY;
392                     metadata.redZ = redZ;
393                     metadata.greenX = greenX;
394                     metadata.greenY = greenY;
395                     metadata.greenZ = greenZ;
396                     metadata.blueX = blueX;
397                     metadata.blueY = blueY;
398                     metadata.blueZ = blueZ;
399                     metadata.gammaRed = (int)gammaRed;
400                     metadata.gammaGreen = (int)gammaGreen;
401                     metadata.gammaBlue = (int)gammaBlue;
402                 }
403
404                 // Read in the palette
405
int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
406                 int sizeOfPalette = numberOfEntries*4;
407                 palette = new byte[sizeOfPalette];
408                 iis.readFully(palette, 0, sizeOfPalette);
409                 metadata.palette = palette;
410                 metadata.paletteSize = numberOfEntries;
411
412                 if (bitsPerPixel == 1) {
413                     imageType = VERSION_4_1_BIT;
414                 } else if (bitsPerPixel == 4) {
415                     imageType = VERSION_4_4_BIT;
416                 } else if (bitsPerPixel == 8) {
417                     imageType = VERSION_4_8_BIT;
418                 } else if (bitsPerPixel == 16) {
419                     imageType = VERSION_4_16_BIT;
420                     if ((int)compression == BI_RGB) {
421                         redMask = 0x7C00;
422                         greenMask = 0x3E0;
423                         blueMask = 0x1F;
424                     }
425                 } else if (bitsPerPixel == 24) {
426                     imageType = VERSION_4_24_BIT;
427                 } else if (bitsPerPixel == 32) {
428                     imageType = VERSION_4_32_BIT;
429                     if ((int)compression == BI_RGB) {
430                         redMask = 0x00FF0000;
431                         greenMask = 0x0000FF00;
432                         blueMask = 0x000000FF;
433                     }
434                 }
435
436                 metadata.redMask = redMask;
437                 metadata.greenMask = greenMask;
438                 metadata.blueMask = blueMask;
439                 metadata.alphaMask = alphaMask;
440             } else {
441                 throw new
442                     RuntimeException JavaDoc(I18N.getString("BMPImageReader3"));
443             }
444         }
445
446         if (height > 0) {
447             // bottom up image
448
isBottomUp = true;
449         } else {
450             // top down image
451
isBottomUp = false;
452             height = Math.abs(height);
453         }
454
455         // Reset Image Layout so there's only one tile.
456
//Define the color space
457
ColorSpace JavaDoc colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
458         if (metadata.colorSpace == PROFILE_LINKED ||
459             metadata.colorSpace == PROFILE_EMBEDDED) {
460
461             iis.mark();
462             iis.skipBytes(profileData - size);
463             byte[] profile = new byte[profileSize];
464             iis.readFully(profile, 0, profileSize);
465             iis.reset();
466
467             try {
468                 if (metadata.colorSpace == PROFILE_LINKED)
469                     colorSpace =
470                         new ICC_ColorSpace JavaDoc(ICC_Profile.getInstance(new String JavaDoc(profile)));
471                 else
472                     colorSpace =
473                         new ICC_ColorSpace JavaDoc(ICC_Profile.getInstance(profile));
474             } catch (Exception JavaDoc e) {
475                 colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
476             }
477         }
478
479         // When number of bitsPerPixel is <= 8, we use IndexColorModel.
480
if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) {
481
482             numBands = 1;
483
484             if (bitsPerPixel == 8) {
485                 int[] bandOffsets = new int[numBands];
486                 for (int i = 0; i < numBands; i++) {
487                     bandOffsets[i] = numBands -1 -i;
488                 }
489                 sampleModel =
490                     new PixelInterleavedSampleModel JavaDoc(DataBuffer.TYPE_BYTE,
491                                                     width, height,
492                                                     numBands,
493                                                     numBands * width,
494                                                     bandOffsets);
495             } else {
496                 // 1 and 4 bit pixels can be stored in a packed format.
497
sampleModel =
498                     new MultiPixelPackedSampleModel JavaDoc(DataBuffer.TYPE_BYTE,
499                                                     width, height,
500                                                     bitsPerPixel);
501             }
502
503             // Create IndexColorModel from the palette.
504
byte r[], g[], b[];
505             if (imageType == VERSION_2_1_BIT ||
506                 imageType == VERSION_2_4_BIT ||
507                 imageType == VERSION_2_8_BIT) {
508
509
510                 size = palette.length/3;
511
512                 if (size > 256) {
513                     size = 256;
514                 }
515
516                 int off;
517                 r = new byte[(int)size];
518                 g = new byte[(int)size];
519                 b = new byte[(int)size];
520                 for (int i=0; i<(int)size; i++) {
521                     off = 3 * i;
522                     b[i] = palette[off];
523                     g[i] = palette[off+1];
524                     r[i] = palette[off+2];
525                 }
526             } else {
527                 size = palette.length/4;
528
529                 if (size > 256) {
530                     size = 256;
531                 }
532
533                 int off;
534                 r = new byte[(int)size];
535                 g = new byte[(int)size];
536                 b = new byte[(int)size];
537                 for (int i=0; i<size; i++) {
538                     off = 4 * i;
539                     b[i] = palette[off];
540                     g[i] = palette[off+1];
541                     r[i] = palette[off+2];
542                 }
543             }
544
545             if (ImageUtil.isIndicesForGrayscale(r, g, b))
546                 colorModel =
547                     ImageUtil.createColorModel(null, sampleModel);
548             else
549                 colorModel = new IndexColorModel JavaDoc(bitsPerPixel, (int)size, r, g, b);
550         } else if (bitsPerPixel == 16) {
551             numBands = 3;
552             sampleModel =
553                 new SinglePixelPackedSampleModel JavaDoc(DataBuffer.TYPE_USHORT,
554                                                  width, height,
555                                                  new int[] {redMask, greenMask, blueMask});
556
557             colorModel =
558                 new DirectColorModel JavaDoc(colorSpace,
559                                      16, redMask, greenMask, blueMask, 0,
560                                      false, DataBuffer.TYPE_USHORT);
561            
562         } else if (bitsPerPixel == 32) {
563             numBands = alphaMask == 0 ? 3 : 4;
564
565             // The number of bands in the SampleModel is determined by
566
// the length of the mask array passed in.
567
int[] bitMasks = numBands == 3 ?
568                 new int[] {redMask, greenMask, blueMask} :
569                 new int[] {redMask, greenMask, blueMask, alphaMask};
570
571                 sampleModel =
572                     new SinglePixelPackedSampleModel JavaDoc(DataBuffer.TYPE_INT,
573                                                      width, height,
574                                                      bitMasks);
575
576                 colorModel =
577                     new DirectColorModel JavaDoc(colorSpace,
578                                          32, redMask, greenMask, blueMask, alphaMask,
579                                          false, DataBuffer.TYPE_INT);
580         } else {
581             numBands = 3;
582             // Create SampleModel
583
int[] bandOffsets = new int[numBands];
584             for (int i = 0; i < numBands; i++) {
585                 bandOffsets[i] = numBands -1 -i;
586             }
587
588             sampleModel =
589                 new PixelInterleavedSampleModel JavaDoc(DataBuffer.TYPE_BYTE,
590                                                 width, height,
591                                                 numBands,
592                                                 numBands * width,
593                                                 bandOffsets);
594
595             colorModel =
596                 ImageUtil.createColorModel(colorSpace, sampleModel);
597         }
598
599         originalSampleModel = sampleModel;
600         originalColorModel = colorModel;
601
602         // Reset to the start of bitmap; then jump to the
603
//start of image data
604
iis.reset();
605         iis.skipBytes(bitmapOffset);
606         gotHeader = true;
607     }
608
609     public Iterator JavaDoc getImageTypes(int imageIndex)
610       throws IOException JavaDoc {
611         checkIndex(imageIndex);
612         readHeader();
613         ArrayList JavaDoc list = new ArrayList JavaDoc(1);
614         list.add(new ImageTypeSpecifier JavaDoc(originalColorModel,
615                                         originalSampleModel));
616         return list.iterator();
617     }
618
619     public ImageReadParam JavaDoc getDefaultReadParam() {
620         return new ImageReadParam JavaDoc();
621     }
622
623     public IIOMetadata JavaDoc getImageMetadata(int imageIndex)
624       throws IOException JavaDoc {
625         checkIndex(imageIndex);
626         if (metadata == null) {
627             readHeader();
628         }
629         return metadata;
630     }
631
632     public IIOMetadata JavaDoc getStreamMetadata() throws IOException JavaDoc {
633         return null;
634     }
635
636     public boolean isRandomAccessEasy(int imageIndex) throws IOException JavaDoc {
637         checkIndex(imageIndex);
638         readHeader();
639         return metadata.compression == BI_RGB;
640     }
641
642     public BufferedImage JavaDoc read(int imageIndex, ImageReadParam JavaDoc param)
643         throws IOException JavaDoc {
644
645         if (iis == null) {
646             throw new IllegalStateException JavaDoc(I18N.getString("BMPImageReader5"));
647         }
648
649         checkIndex(imageIndex);
650         clearAbortRequest();
651         processImageStarted(imageIndex);
652
653         if (param == null)
654             param = getDefaultReadParam();
655
656         //read header
657
readHeader();
658
659         sourceRegion = new Rectangle JavaDoc(0, 0, 0, 0);
660         destinationRegion = new Rectangle JavaDoc(0, 0, 0, 0);
661
662         computeRegions(param, this.width, this.height,
663                        param.getDestination(),
664                        sourceRegion,
665                        destinationRegion);
666
667         scaleX = param.getSourceXSubsampling();
668         scaleY = param.getSourceYSubsampling();
669
670         // If the destination band is set used it
671
sourceBands = param.getSourceBands();
672         destBands = param.getDestinationBands();
673
674         seleBand = (sourceBands != null) && (destBands != null);
675         noTransform =
676             destinationRegion.equals(new Rectangle JavaDoc(0, 0, width, height)) ||
677             seleBand;
678
679         if (!seleBand) {
680             sourceBands = new int[numBands];
681             destBands = new int[numBands];
682             for (int i = 0; i < numBands; i++)
683                 destBands[i] = sourceBands[i] = i;
684         }
685
686         // If the destination is provided, then use it. Otherwise, create new one
687
bi = param.getDestination();
688
689         // Get the image data.
690
WritableRaster JavaDoc raster = null;
691
692         if (bi == null) {
693             sampleModel =
694                 sampleModel.createCompatibleSampleModel(destinationRegion.x +
695                                                         destinationRegion.width,
696                                                         destinationRegion.y +
697                                                         destinationRegion.height);
698             if (seleBand)
699                 sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
700             raster = Raster.createWritableRaster(sampleModel, new Point JavaDoc());
701             bi = new BufferedImage JavaDoc(colorModel, raster, false, null);
702         } else {
703             raster = bi.getWritableTile(0, 0);
704             sampleModel = bi.getSampleModel();
705             colorModel = bi.getColorModel();
706
707             noTransform &= destinationRegion.equals(raster.getBounds());
708         }
709
710         byte bdata[] = null; // buffer for byte data
711
short sdata[] = null; // buffer for short data
712
int idata[] = null; // buffer for int data
713

714         if (sampleModel.getDataType() == DataBuffer.TYPE_BYTE)
715             bdata = (byte[])((DataBufferByte JavaDoc)raster.getDataBuffer()).getData();
716         else if (sampleModel.getDataType() == DataBuffer.TYPE_USHORT)
717             sdata = (short[])((DataBufferUShort JavaDoc)raster.getDataBuffer()).getData();
718         else if (sampleModel.getDataType() == DataBuffer.TYPE_INT)
719             idata = (int[])((DataBufferInt JavaDoc)raster.getDataBuffer()).getData();
720
721         // There should only be one tile.
722
switch(imageType) {
723
724         case VERSION_2_1_BIT:
725             // no compression
726
read1Bit(bdata);
727             break;
728
729         case VERSION_2_4_BIT:
730             // no compression
731
read4Bit(bdata);
732             break;
733
734         case VERSION_2_8_BIT:
735             // no compression
736
read8Bit(bdata);
737             break;
738
739         case VERSION_2_24_BIT:
740             // no compression
741
read24Bit(bdata);
742             break;
743
744         case VERSION_3_1_BIT:
745             // 1-bit images cannot be compressed.
746
read1Bit(bdata);
747             break;
748
749         case VERSION_3_4_BIT:
750             switch((int)compression) {
751             case BI_RGB:
752                 read4Bit(bdata);
753                 break;
754
755             case BI_RLE4:
756                 readRLE4(bdata);
757                 break;
758
759             case BI_JPEG:
760                 readEmbedded("JPEG", bi, param);
761                 break;
762
763             case BI_PNG:
764                 readEmbedded("PNG", bi, param);
765                 break;
766         
767             default:
768                 throw new
769                     RuntimeException JavaDoc(I18N.getString("BMPImageReader1"));
770             }
771             break;
772
773         case VERSION_3_8_BIT:
774             switch((int)compression) {
775             case BI_RGB:
776                 read8Bit(bdata);
777                 break;
778
779             case BI_RLE8:
780                 readRLE8(bdata);
781                 break;
782
783             case BI_JPEG:
784                 readEmbedded("JPEG", bi, param);
785                 break;
786
787             case BI_PNG:
788                 readEmbedded("PNG", bi, param);
789                 break;
790
791             default:
792                 throw new
793                     RuntimeException JavaDoc(I18N.getString("BMPImageReader1"));
794             }
795
796             break;
797
798         case VERSION_3_24_BIT:
799             // 24-bit images are not compressed
800
read24Bit(bdata);
801             break;
802
803         case VERSION_3_NT_16_BIT:
804             read16Bit(sdata);
805             break;
806
807         case VERSION_3_NT_32_BIT:
808             switch((int)compression) {
809             case BI_JPEG:
810                 iis.seek(54);
811                 readEmbedded("JPEG", bi, param);
812                 break;
813         
814             case BI_PNG:
815                 readEmbedded("PNG", bi, param);
816                 break;
817             default:
818                 read32Bit(idata);
819             }
820             break;
821
822         case VERSION_4_1_BIT:
823             read1Bit(bdata);
824             break;
825
826         case VERSION_4_4_BIT:
827             switch((int)compression) {
828
829             case BI_RGB:
830                 read4Bit(bdata);
831                 break;
832
833             case BI_RLE4:
834                 readRLE4(bdata);
835                 break;
836
837             case BI_JPEG:
838                 readEmbedded("JPEG", bi, param);
839                 break;
840
841             case BI_PNG:
842                 readEmbedded("PNG", bi, param);
843                 break;
844
845             default:
846                 throw new
847                     RuntimeException JavaDoc(I18N.getString("BMPImageReader1"));
848             }
849
850         case VERSION_4_8_BIT:
851             switch((int)compression) {
852
853             case BI_RGB:
854                 read8Bit(bdata);
855                 break;
856
857             case BI_RLE8:
858                 readRLE8(bdata);
859                 break;
860
861             case BI_JPEG:
862                 readEmbedded("JPEG", bi, param);
863                 break;
864
865             case BI_PNG:
866                 readEmbedded("PNG", bi, param);
867                 break;
868
869             default:
870                 throw new
871                     RuntimeException JavaDoc(I18N.getString("BMPImageReader1"));
872             }
873             break;
874
875         case VERSION_4_16_BIT:
876             read16Bit(sdata);
877             break;
878
879         case VERSION_4_24_BIT:
880             read24Bit(bdata);
881             break;
882
883         case VERSION_4_32_BIT:
884             read32Bit(idata);
885             break;
886         }
887
888         if (abortRequested())
889             processReadAborted();
890         else
891             processImageComplete();
892
893         return bi;
894     }
895
896     public boolean canReadRaster() {
897         return true;
898     }
899
900     public Raster JavaDoc readRaster(int imageIndex,
901                              ImageReadParam JavaDoc param) throws IOException JavaDoc {
902         BufferedImage JavaDoc bi = read(imageIndex, param);
903         return bi.getData();
904     }
905
906     private void resetHeaderInfo() {
907         gotHeader = false;
908         bi = null;
909         sampleModel = originalSampleModel = null;
910         colorModel = originalColorModel = null;
911     }
912
913     public void reset() {
914         super.reset();
915         iis = null;
916         resetHeaderInfo();
917     }
918
919     // Deal with 1 Bit images using IndexColorModels
920
private void read1Bit(byte[] bdata) throws IOException JavaDoc {
921         int bytesPerScanline = (width + 7) / 8;
922         int padding = bytesPerScanline % 4;
923         if (padding != 0) {
924             padding = 4 - padding;
925         }
926
927         int lineLength = bytesPerScanline + padding;
928
929         if (noTransform) {
930             int j = isBottomUp ? (height -1)*bytesPerScanline : 0;
931
932             for (int i=0; i<height; i++) {
933                 if (abortRequested()) {
934                     break;
935                 }
936                 iis.readFully(bdata, j, bytesPerScanline);
937                 iis.skipBytes(padding);
938                 j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
939                 processImageUpdate(bi, 0, i,
940                                    destinationRegion.width, 1, 1, 1,
941                                    new int[]{0});
942                 processImageProgress(100.0F * i/destinationRegion.height);
943             }
944         } else {
945             byte[] buf = new byte[lineLength];
946             int lineStride =
947                 ((MultiPixelPackedSampleModel JavaDoc)sampleModel).getScanlineStride();
948
949             if (isBottomUp) {
950                 int lastLine =
951                     sourceRegion.y + (destinationRegion.height - 1) * scaleY;
952                 iis.skipBytes(lineLength * (height - 1 - lastLine));
953             } else
954                 iis.skipBytes(lineLength * sourceRegion.y);
955
956             int skipLength = lineLength * (scaleY - 1);
957
958             // cache the values to avoid duplicated computation
959
int[] srcOff = new int[destinationRegion.width];
960             int[] destOff = new int[destinationRegion.width];
961             int[] srcPos = new int[destinationRegion.width];
962             int[] destPos = new int[destinationRegion.width];
963
964             for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
965                  i < destinationRegion.x + destinationRegion.width;
966                  i++, j++, x += scaleX) {
967                 srcPos[j] = x >> 3;
968                 srcOff[j] = 7 - (x & 7);
969                 destPos[j] = i >> 3;
970                 destOff[j] = 7 - (i & 7);
971             }
972
973             int k = destinationRegion.y * lineStride;
974             if (isBottomUp)
975                 k += (destinationRegion.height - 1) * lineStride;
976
977             for (int j = 0, y = sourceRegion.y;
978                  j < destinationRegion.height; j++, y+=scaleY) {
979
980                 if (abortRequested())
981                     break;
982                 iis.read(buf, 0, lineLength);
983                 for (int i = 0; i < destinationRegion.width; i++) {
984                     //get the bit and assign to the data buffer of the raster
985
int v = (buf[srcPos[i]] >> srcOff[i]) & 1;
986                     bdata[k + destPos[i]] |= v << destOff[i];
987                 }
988
989                 k += isBottomUp ? -lineStride : lineStride;
990                 iis.skipBytes(skipLength);
991                 processImageUpdate(bi, 0, j,
992                                    destinationRegion.width, 1, 1, 1,
993                                    new int[]{0});
994                 processImageProgress(100.0F*j/destinationRegion.height);
995             }
996         }
997     }
998
999     // Method to read a 4 bit BMP image data
1000
private void read4Bit(byte[] bdata) throws IOException JavaDoc {
1001
1002        int bytesPerScanline = (width + 1) / 2;
1003
1004        // Padding bytes at the end of each scanline
1005
int padding = bytesPerScanline % 4;
1006        if (padding != 0)
1007            padding = 4 - padding;
1008
1009        int lineLength = bytesPerScanline + padding;
1010
1011        if (noTransform) {
1012            int j = isBottomUp ? (height -1) * bytesPerScanline : 0;
1013
1014            for (int i=0; i<height; i++) {
1015                if (abortRequested()) {
1016                    break;
1017                }
1018                iis.readFully(bdata, j, bytesPerScanline);
1019                iis.skipBytes(padding);
1020                j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
1021                processImageUpdate(bi, 0, i,
1022                                   destinationRegion.width, 1, 1, 1,
1023                                   new int[]{0});
1024                processImageProgress(100.0F * i/destinationRegion.height);
1025            }
1026        } else {
1027            byte[] buf = new byte[lineLength];
1028            int lineStride =
1029                ((MultiPixelPackedSampleModel JavaDoc)sampleModel).getScanlineStride();
1030
1031            if (isBottomUp) {
1032                int lastLine =
1033                    sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1034                iis.skipBytes(lineLength * (height - 1 - lastLine));
1035            } else
1036                iis.skipBytes(lineLength * sourceRegion.y);
1037
1038            int skipLength = lineLength * (scaleY - 1);
1039
1040            // cache the values to avoid duplicated computation
1041
int[] srcOff = new int[destinationRegion.width];
1042            int[] destOff = new int[destinationRegion.width];
1043            int[] srcPos = new int[destinationRegion.width];
1044            int[] destPos = new int[destinationRegion.width];
1045
1046            for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
1047                 i < destinationRegion.x + destinationRegion.width;
1048                 i++, j++, x += scaleX) {
1049                srcPos[j] = x >> 1;
1050                srcOff[j] = (1 - (x & 1)) << 2;
1051                destPos[j] = i >> 1;
1052                destOff[j] = (1 - (i & 1)) << 2;
1053            }
1054
1055            int k = destinationRegion.y * lineStride;
1056            if (isBottomUp)
1057                k += (destinationRegion.height - 1) * lineStride;
1058
1059            for (int j = 0, y = sourceRegion.y;
1060                 j < destinationRegion.height; j++, y+=scaleY) {
1061
1062                if (abortRequested())
1063                    break;
1064                iis.read(buf, 0, lineLength);
1065                for (int i = 0; i < destinationRegion.width; i++) {
1066                    //get the bit and assign to the data buffer of the raster
1067
int v = (buf[srcPos[i]] >> srcOff[i]) & 0x0F;
1068                    bdata[k + destPos[i]] |= v << destOff[i];
1069                }
1070
1071                k += isBottomUp ? -lineStride : lineStride;
1072                iis.skipBytes(skipLength);
1073                processImageUpdate(bi, 0, j,
1074                                   destinationRegion.width, 1, 1, 1,
1075                                   new int[]{0});
1076                processImageProgress(100.0F*j/destinationRegion.height);
1077            }
1078        }
1079    }
1080
1081    // Method to read 8 bit BMP image data
1082
private void read8Bit(byte[] bdata) throws IOException JavaDoc {
1083
1084        // Padding bytes at the end of each scanline
1085
int padding = width % 4;
1086        if (padding != 0) {
1087            padding = 4 - padding;
1088        }
1089
1090        int lineLength = width + padding;
1091
1092        if (noTransform) {
1093            int j = isBottomUp ? (height -1) * width : 0;
1094
1095            for (int i=0; i<height; i++) {
1096                if (abortRequested()) {
1097                    break;
1098                }
1099                iis.readFully(bdata, j, width);
1100                iis.skipBytes(padding);
1101                j += isBottomUp ? -width : width;
1102                processImageUpdate(bi, 0, i,
1103                                   destinationRegion.width, 1, 1, 1,
1104                                   new int[]{0});
1105                processImageProgress(100.0F * i/destinationRegion.height);
1106            }
1107        } else {
1108            byte[] buf = new byte[lineLength];
1109            int lineStride =
1110                ((ComponentSampleModel JavaDoc)sampleModel).getScanlineStride();
1111
1112            if (isBottomUp) {
1113                int lastLine =
1114                    sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1115                iis.skipBytes(lineLength * (height - 1 - lastLine));
1116            } else
1117                iis.skipBytes(lineLength * sourceRegion.y);
1118
1119            int skipLength = lineLength * (scaleY - 1);
1120
1121            int k = destinationRegion.y * lineStride;
1122            if (isBottomUp)
1123                k += (destinationRegion.height - 1) * lineStride;
1124            k += destinationRegion.x;
1125
1126            for (int j = 0, y = sourceRegion.y;
1127                 j < destinationRegion.height; j++, y+=scaleY) {
1128
1129                if (abortRequested())
1130                    break;
1131                iis.read(buf, 0, lineLength);
1132                for (int i = 0, m = sourceRegion.x;
1133                     i < destinationRegion.width; i++, m += scaleX) {
1134                    //get the bit and assign to the data buffer of the raster
1135
bdata[k + i] = buf[m];
1136                }
1137
1138                k += isBottomUp ? -lineStride : lineStride;
1139                iis.skipBytes(skipLength);
1140                processImageUpdate(bi, 0, j,
1141                                   destinationRegion.width, 1, 1, 1,
1142                                   new int[]{0});
1143                processImageProgress(100.0F*j/destinationRegion.height);
1144            }
1145        }
1146    }
1147
1148    // Method to read 24 bit BMP image data
1149
private void read24Bit(byte[] bdata) throws IOException JavaDoc {
1150        // Padding bytes at the end of each scanline
1151
// width * bitsPerPixel should be divisible by 32
1152
int padding = width * 3 % 4;
1153        if ( padding != 0)
1154            padding = 4 - padding;
1155
1156        int lineStride = width * 3;
1157        int lineLength = lineStride + padding;
1158
1159        if (noTransform) {
1160            int j = isBottomUp ? (height -1) * width * 3 : 0;
1161
1162            for (int i=0; i<height; i++) {
1163                if (abortRequested()) {
1164                    break;
1165                }
1166                iis.readFully(bdata, j, lineStride);
1167                iis.skipBytes(padding);
1168                j += isBottomUp ? -lineStride : lineStride;
1169                processImageUpdate(bi, 0, i,
1170                                   destinationRegion.width, 1, 1, 1,
1171                                   new int[]{0});
1172                processImageProgress(100.0F * i/destinationRegion.height);
1173            }
1174        } else {
1175            byte[] buf = new byte[lineLength];
1176            lineStride =
1177                ((ComponentSampleModel JavaDoc)sampleModel).getScanlineStride();
1178
1179            if (isBottomUp) {
1180                int lastLine =
1181                    sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1182                iis.skipBytes(lineLength * (height - 1 - lastLine));
1183            } else
1184                iis.skipBytes(lineLength * sourceRegion.y);
1185
1186            int skipLength = lineLength * (scaleY - 1);
1187
1188            int k = destinationRegion.y * lineStride;
1189            if (isBottomUp)
1190                k += (destinationRegion.height - 1) * lineStride;
1191            k += destinationRegion.x * 3;
1192
1193            for (int j = 0, y = sourceRegion.y;
1194                 j < destinationRegion.height; j++, y+=scaleY) {
1195
1196                if (abortRequested())
1197                    break;
1198                iis.read(buf, 0, lineLength);
1199                for (int i = 0, m = 3 * sourceRegion.x;
1200                     i < destinationRegion.width; i++, m += 3 * scaleX) {
1201                    //get the bit and assign to the data buffer of the raster
1202
int n = 3 * i + k;
1203                    for (int b = 0; b < destBands.length; b++)
1204                        bdata[n + destBands[b]] = buf[m + sourceBands[b]];
1205                }
1206
1207                k += isBottomUp ? -lineStride : lineStride;
1208                iis.skipBytes(skipLength);
1209                processImageUpdate(bi, 0, j,
1210                                   destinationRegion.width, 1, 1, 1,
1211                                   new int[]{0});
1212                processImageProgress(100.0F*j/destinationRegion.height);
1213            }
1214        }
1215    }
1216
1217    private void read16Bit(short sdata[]) throws IOException JavaDoc {
1218        // Padding bytes at the end of each scanline
1219
// width * bitsPerPixel should be divisible by 32
1220
int padding = width * 2 % 4;
1221        
1222        if ( padding != 0)
1223            padding = 4 - padding;
1224        
1225        int lineLength = width + padding / 2;
1226        
1227        if (noTransform) {
1228            int j = isBottomUp ? (height -1) * width : 0;
1229            for (int i=0; i<height; i++) {
1230                if (abortRequested()) {
1231                    break;
1232                }
1233
1234                iis.readFully(sdata, j, width);
1235                iis.skipBytes(padding);
1236                
1237                j += isBottomUp ? -width : width;
1238                processImageUpdate(bi, 0, i,
1239                                   destinationRegion.width, 1, 1, 1,
1240                                   new int[]{0});
1241                processImageProgress(100.0F * i/destinationRegion.height);
1242            }
1243        } else {
1244            short[] buf = new short[lineLength];
1245            int lineStride =
1246                ((SinglePixelPackedSampleModel JavaDoc)sampleModel).getScanlineStride();
1247            
1248            if (isBottomUp) {
1249                int lastLine =
1250                    sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1251                iis.skipBytes(lineLength * (height - 1 - lastLine) << 1);
1252            } else
1253                iis.skipBytes(lineLength * sourceRegion.y << 1);
1254            
1255            int skipLength = lineLength * (scaleY - 1) << 1;
1256            
1257            int k = destinationRegion.y * lineStride;
1258            if (isBottomUp)
1259                k += (destinationRegion.height - 1) * lineStride;
1260            k += destinationRegion.x;
1261            
1262            for (int j = 0, y = sourceRegion.y;
1263                 j < destinationRegion.height; j++, y+=scaleY) {
1264                
1265                if (abortRequested())
1266                    break;
1267                iis.readFully(buf, 0, lineLength);
1268                for (int i = 0, m = sourceRegion.x;
1269                     i < destinationRegion.width; i++, m += scaleX) {
1270                    //get the bit and assign to the data buffer of the raster
1271
sdata[k + i] = buf[m];
1272                }
1273
1274                k += isBottomUp ? -lineStride : lineStride;
1275                iis.skipBytes(skipLength);
1276                processImageUpdate(bi, 0, j,
1277                                   destinationRegion.width, 1, 1, 1,
1278                                   new int[]{0});
1279                processImageProgress(100.0F*j/destinationRegion.height);
1280            }
1281        }
1282    }
1283
1284    private void read32Bit(int idata[]) throws IOException JavaDoc {
1285        if (noTransform) {
1286            int j = isBottomUp ? (height -1) * width : 0;
1287
1288            for (int i=0; i<height; i++) {
1289                if (abortRequested()) {
1290                    break;
1291                }
1292                iis.readFully(idata, j, width);
1293                j += isBottomUp ? -width : width;
1294                processImageUpdate(bi, 0, i,
1295                                   destinationRegion.width, 1, 1, 1,
1296                                   new int[]{0});
1297                processImageProgress(100.0F * i/destinationRegion.height);
1298            }
1299        } else {
1300            int[] buf = new int[width];
1301            int lineStride =
1302                ((SinglePixelPackedSampleModel JavaDoc)sampleModel).getScanlineStride();
1303
1304            if (isBottomUp) {
1305                int lastLine =
1306                    sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1307                iis.skipBytes(width * (height - 1 - lastLine) << 2);
1308            } else
1309                iis.skipBytes(width * sourceRegion.y << 2);
1310
1311            int skipLength = width * (scaleY - 1) << 2;
1312
1313            int k = destinationRegion.y * lineStride;
1314            if (isBottomUp)
1315                k += (destinationRegion.height - 1) * lineStride;
1316            k += destinationRegion.x;
1317
1318            for (int j = 0, y = sourceRegion.y;
1319                 j < destinationRegion.height; j++, y+=scaleY) {
1320
1321                if (abortRequested())
1322                    break;
1323                iis.readFully(buf, 0, width);
1324                for (int i = 0, m = sourceRegion.x;
1325                     i < destinationRegion.width; i++, m += scaleX) {
1326                    //get the bit and assign to the data buffer of the raster
1327
idata[k + i] = buf[m];
1328                }
1329
1330                k += isBottomUp ? -lineStride : lineStride;
1331                iis.skipBytes(skipLength);
1332                processImageUpdate(bi, 0, j,
1333                                   destinationRegion.width, 1, 1, 1,
1334                                   new int[]{0});
1335                processImageProgress(100.0F*j/destinationRegion.height);
1336            }
1337        }
1338    }
1339
1340    private void readRLE8(byte bdata[]) throws IOException JavaDoc {
1341        // If imageSize field is not provided, calculate it.
1342
int imSize = (int)imageSize;
1343        if (imSize == 0) {
1344            imSize = (int)(bitmapFileSize - bitmapOffset);
1345        }
1346
1347        int padding = 0;
1348        // If width is not 32 bit aligned, then while uncompressing each
1349
// scanline will have padding bytes, calculate the amount of padding
1350
int remainder = width % 4;
1351        if (remainder != 0) {
1352            padding = 4 - remainder;
1353        }
1354
1355        // Read till we have the whole image
1356
byte values[] = new byte[imSize];
1357        int bytesRead = 0;
1358        iis.readFully(values, 0, imSize);
1359
1360        // Since data is compressed, decompress it
1361
decodeRLE8(imSize, padding, values, bdata);
1362    }
1363
1364    private void decodeRLE8(int imSize,
1365                            int padding,
1366                            byte[] values,
1367                            byte[] bdata) throws IOException JavaDoc {
1368
1369        byte val[] = new byte[width * height];
1370        int count = 0, l = 0;
1371        int value;
1372        boolean flag = false;
1373        int lineNo = isBottomUp ? height - 1 : 0;
1374        int lineStride =
1375            ((ComponentSampleModel JavaDoc)sampleModel).getScanlineStride();
1376        int finished = 0;
1377
1378        while (count != imSize) {
1379            value = values[count++] & 0xff;
1380            if (value == 0) {
1381                switch(values[count++] & 0xff) {
1382
1383                case 0:
1384                    // End-of-scanline marker
1385
if (lineNo >= sourceRegion.y &&
1386                        lineNo < sourceRegion.y + sourceRegion.width) {
1387                        if (noTransform) {
1388                            int pos = lineNo * width;
1389                            for(int i = 0; i < width; i++)
1390                                bdata[pos++] = val[i];
1391                            processImageUpdate(bi, 0, lineNo,
1392                                               destinationRegion.width, 1, 1, 1,
1393                                               new int[]{0});
1394                            finished++;
1395                        } else if ((lineNo - sourceRegion.y) % scaleY == 0) {
1396                            int currentLine = (lineNo - sourceRegion.y) / scaleY +
1397                                destinationRegion.y;
1398                            int pos = currentLine * lineStride;
1399                            pos += destinationRegion.x;
1400                            for (int i = sourceRegion.x;
1401                                 i < sourceRegion.x + sourceRegion.width;
1402                                 i += scaleX)
1403                                bdata[pos++] = val[i];
1404                            processImageUpdate(bi, 0, currentLine,
1405                                               destinationRegion.width, 1, 1, 1,
1406                                               new int[]{0});
1407                            finished++;
1408                        }
1409                    }
1410                    processImageProgress(100.0F * finished / destinationRegion.height);
1411                    lineNo += isBottomUp ? -1 : 1;
1412                    l = 0;
1413
1414                    if (abortRequested()) {
1415                        flag = true;
1416                    }
1417
1418                    break;
1419
1420                case 1:
1421                    // End-of-RLE marker
1422
flag = true;
1423                    break;
1424
1425                case 2:
1426                    // delta or vector marker
1427
int xoff = values[count++] & 0xff;
1428                    int yoff = values[count] & 0xff;
1429                    // Move to the position xoff, yoff down
1430
l += xoff + yoff*width;
1431                    break;
1432
1433                default:
1434                    int end = values[count-1] & 0xff;
1435                    for (int i=0; i<end; i++) {
1436                        val[l++] = (byte)(values[count++] & 0xff);
1437                    }
1438
1439                    // Whenever end pixels can fit into odd number of bytes,
1440
// an extra padding byte will be present, so skip that.
1441
if ((end & 1) == 1) {
1442                        count++;
1443                    }
1444                }
1445            } else {
1446                for (int i=0; i<value; i++) {
1447                    val[l++] = (byte)(values[count] & 0xff);
1448                }
1449
1450                count++;
1451            }
1452
1453            // If End-of-RLE data, then exit the while loop
1454
if (flag) {
1455                break;
1456            }
1457        }
1458    }
1459
1460    private void readRLE4(byte[] bdata) throws IOException JavaDoc {
1461
1462        // If imageSize field is not specified, calculate it.
1463
int imSize = (int)imageSize;
1464        if (imSize == 0) {
1465            imSize = (int)(bitmapFileSize - bitmapOffset);
1466        }
1467        
1468        int padding = 0;
1469        // If width is not 32 byte aligned, then while uncompressing each
1470
// scanline will have padding bytes, calculate the amount of padding
1471
int remainder = width % 4;
1472        if (remainder != 0) {
1473            padding = 4 - remainder;
1474        }
1475        
1476        // Read till we have the whole image
1477
byte[] values = new byte[imSize];
1478        iis.readFully(values, 0, imSize);
1479
1480        // Decompress the RLE4 compressed data.
1481
decodeRLE4(imSize, padding, values, bdata);
1482    }
1483
1484    private void decodeRLE4(int imSize,
1485                            int padding,
1486                            byte[] values,
1487                            byte[] bdata) throws IOException JavaDoc {
1488        byte[] val = new byte[width];
1489        int count = 0, l = 0;
1490        int value;
1491        boolean flag = false;
1492        int lineNo = isBottomUp ? height - 1 : 0;
1493        int lineStride =
1494            ((MultiPixelPackedSampleModel JavaDoc)sampleModel).getScanlineStride();
1495        int finished = 0;
1496        
1497        while (count != imSize) {
1498            
1499            value = values[count++] & 0xFF;
1500            if (value == 0) {
1501                
1502                
1503                // Absolute mode
1504
switch(values[count++] & 0xFF) {
1505                    
1506                case 0:
1507                    // End-of-scanline marker
1508
// End-of-scanline marker
1509
if (lineNo >= sourceRegion.y &&
1510                        lineNo < sourceRegion.y + sourceRegion.width) {
1511                        if (noTransform) {
1512                            int pos = lineNo * (width + 1 >> 1);
1513                            for(int i = 0, j = 0; i < width >> 1; i++)
1514                                bdata[pos++] =
1515                                    (byte)((val[j++] << 4) | val[j++]);
1516                            if ((width & 1) == 1)
1517                                bdata[pos] |= val[width - 1] << 4;
1518
1519                            processImageUpdate(bi, 0, lineNo,
1520                                               destinationRegion.width, 1, 1, 1,
1521                                               new int[]{0});
1522                            finished++;
1523                        } else if ((lineNo - sourceRegion.y) % scaleY == 0) {
1524                            int currentLine = (lineNo - sourceRegion.y) / scaleY +
1525                                destinationRegion.y;
1526                            int pos = currentLine * lineStride;
1527                            pos += destinationRegion.x >> 1;
1528                            int shift = (1 - (destinationRegion.x & 1)) << 2;
1529                            for (int i = sourceRegion.x;
1530                                 i < sourceRegion.x + sourceRegion.width;
1531                                 i += scaleX) {
1532                                bdata[pos] |= val[i] << shift;
1533                                shift += 4;
1534                                if (shift == 4) {
1535                                    pos++;
1536                                }
1537                                shift &= 7;
1538                            }
1539                            processImageUpdate(bi, 0, currentLine,
1540                                               destinationRegion.width, 1, 1, 1,
1541                                               new int[]{0});
1542                            finished++;
1543                        }
1544                    }
1545                    processImageProgress(100.0F * finished / destinationRegion.height);
1546                    lineNo += isBottomUp ? -1 : 1;
1547                    l = 0;
1548
1549                    if (abortRequested()) {
1550                        flag = true;
1551                    }
1552
1553                    break;
1554
1555                case 1:
1556                    // End-of-RLE marker
1557
flag = true;
1558                    break;
1559
1560                case 2:
1561                    // delta or vector marker
1562
int xoff = values[count++] & 0xFF;
1563                    int yoff = values[count] & 0xFF;
1564                    // Move to the position xoff, yoff down
1565
l += xoff + yoff*width;
1566                    break;
1567
1568                default:
1569                    int end = values[count-1] & 0xFF;
1570                    for (int i=0; i<end; i++) {
1571                        val[l++] = (byte)(((i & 1) == 0) ? (values[count] & 0xf0) >> 4
1572                                          : (values[count++] & 0x0f));
1573                    }
1574
1575                    // When end is odd, the above for loop does not
1576
// increment count, so do it now.
1577
if ((end & 1) == 1) {
1578                        count++;
1579                    }
1580
1581                    // Whenever end pixels can fit into odd number of bytes,
1582
// an extra padding byte will be present, so skip that.
1583
if ((((int)Math.ceil(end/2)) & 1) ==1 ) {
1584                        count++;
1585                    }
1586                    break;
1587                }
1588            } else {
1589                // Encoded mode
1590
int alternate[] = { (values[count] & 0xf0) >> 4,
1591                                    values[count] & 0x0f };
1592                for (int i=0; (i < value) && (l < width); i++) {
1593                    val[l++] = (byte)alternate[i & 1];
1594                }
1595
1596                count++;
1597            }
1598
1599            // If End-of-RLE data, then exit the while loop
1600
if (flag) {
1601                break;
1602            }
1603        }
1604    }
1605
1606    /** Decodes the jpeg/png image embedded in the bitmap using any jpeg
1607     * ImageIO-style plugin.
1608     *
1609     * @param bi The destination <code>BufferedImage</code>.
1610     * @param bmpParam The <code>ImageReadParam</code> for decoding this
1611     * BMP image. The parameters for subregion, band selection and
1612     * subsampling are used in decoding the jpeg image.
1613     */

1614
1615    private void readEmbedded(String JavaDoc format,
1616                              BufferedImage JavaDoc bi, ImageReadParam JavaDoc bmpParam)
1617      throws IOException JavaDoc {
1618        Iterator JavaDoc iterator = ImageIO.getImageReadersByFormatName(format);
1619        ImageReader JavaDoc reader = null;
1620        if (iterator.hasNext())
1621            reader = (ImageReader JavaDoc)iterator.next();
1622        if (reader != null) {
1623            // prepare input
1624
byte[] buff = new byte[(int)imageSize];
1625            iis.read(buff);
1626            reader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(buff)));
1627
1628            reader.addIIOReadProgressListener(new EmbeddedProgressAdapter() {
1629                    public void imageProgress(ImageReader JavaDoc source,
1630                                              float percentageDone)
1631                    {
1632                        processImageProgress(percentageDone);
1633                    }
1634                });
1635
1636            reader.addIIOReadUpdateListener(new IIOReadUpdateListener JavaDoc() {
1637                    public void imageUpdate(ImageReader JavaDoc source,
1638                                            BufferedImage JavaDoc theImage,
1639                                            int minX, int minY,
1640                                            int width, int height,
1641                                            int periodX, int periodY,
1642                                            int[] bands)
1643                    {
1644                        processImageUpdate(theImage, minX, minY,
1645                                           width, height,
1646                                           periodX, periodY, bands);
1647                    }
1648                    public void passComplete(ImageReader JavaDoc source,
1649                                             BufferedImage JavaDoc theImage)
1650                    {
1651                        processPassComplete(theImage);
1652                    }
1653                    public void passStarted(ImageReader JavaDoc source,
1654                                            BufferedImage JavaDoc theImage,
1655                                            int pass,
1656                                            int minPass, int maxPass,
1657                                            int minX, int minY,
1658                                            int periodX, int periodY,
1659                                            int[] bands)
1660                    {
1661                        processPassStarted(theImage, pass, minPass, maxPass,
1662                                           minX, minY, periodX, periodY,
1663                                           bands);
1664                    }
1665                    public void thumbnailPassComplete(ImageReader JavaDoc source,
1666                                                      BufferedImage JavaDoc thumb) {}
1667                    public void thumbnailPassStarted(ImageReader JavaDoc source,
1668                                                     BufferedImage JavaDoc thumb,
1669                                                     int pass,
1670                                                     int minPass, int maxPass,
1671                                                     int minX, int minY,
1672                                                     int periodX, int periodY,
1673                                                     int[] bands) {}
1674                    public void thumbnailUpdate(ImageReader JavaDoc source,
1675                                                BufferedImage JavaDoc theThumbnail,
1676                                                int minX, int minY,
1677                                                int width, int height,
1678                                                int periodX, int periodY,
1679                                                int[] bands) {}
1680                });
1681
1682            reader.addIIOReadWarningListener(new IIOReadWarningListener JavaDoc() {
1683                    public void warningOccurred(ImageReader JavaDoc source, String JavaDoc warning) {
1684                        processWarningOccurred(warning);
1685                    }
1686                });
1687 
1688            ImageReadParam JavaDoc param = reader.getDefaultReadParam();
1689            param.setDestination(bi);
1690            param.setDestinationBands(bmpParam.getDestinationBands());
1691            param.setDestinationOffset(bmpParam.getDestinationOffset());
1692            param.setSourceBands(bmpParam.getSourceBands());
1693            param.setSourceRegion(bmpParam.getSourceRegion());
1694            param.setSourceSubsampling(bmpParam.getSourceXSubsampling(),
1695                                       bmpParam.getSourceYSubsampling(),
1696                                       bmpParam.getSubsamplingXOffset(),
1697                                       bmpParam.getSubsamplingYOffset());
1698            reader.read(0, param);
1699        } else
1700            throw new RuntimeException JavaDoc(I18N.getString("BMPImageReader4") + " " + format);
1701    }
1702
1703    private class EmbeddedProgressAdapter implements IIOReadProgressListener JavaDoc {
1704        public void imageComplete(ImageReader JavaDoc src) {}
1705        public void imageProgress(ImageReader JavaDoc src, float percentageDone) {}
1706        public void imageStarted(ImageReader JavaDoc src, int imageIndex) {}
1707        public void thumbnailComplete(ImageReader JavaDoc src) {}
1708        public void thumbnailProgress(ImageReader JavaDoc src, float percentageDone) {}
1709        public void thumbnailStarted(ImageReader JavaDoc src, int iIdx, int tIdx) {}
1710        public void sequenceComplete(ImageReader JavaDoc src) {}
1711        public void sequenceStarted(ImageReader JavaDoc src, int minIndex) {}
1712        public void readAborted(ImageReader JavaDoc src) {}
1713    }
1714}
1715
Popular Tags