History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/imageio/plugins/bmp/BMPImageReader.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/imageio/plugins/bmp/BMPImageReader.java+1821−0
@@ -0,0 +1,1821 @@
1+/*
2+ * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package com.sun.imageio.plugins.bmp;
27+
28+import java.awt.Point;
29+import java.awt.Rectangle;
30+import java.awt.Transparency;
31+import java.awt.color.ColorSpace;
32+import java.awt.color.ICC_ColorSpace;
33+import java.awt.color.ICC_Profile;
34+import java.awt.image.BufferedImage;
35+import java.awt.image.ColorModel;
36+import java.awt.image.ComponentColorModel;
37+import java.awt.image.ComponentSampleModel;
38+import java.awt.image.DataBuffer;
39+import java.awt.image.DataBufferByte;
40+import java.awt.image.DataBufferInt;
41+import java.awt.image.DataBufferUShort;
42+import java.awt.image.DirectColorModel;
43+import java.awt.image.IndexColorModel;
44+import java.awt.image.MultiPixelPackedSampleModel;
45+import java.awt.image.PixelInterleavedSampleModel;
46+import java.awt.image.Raster;
47+import java.awt.image.SampleModel;
48+import java.awt.image.SinglePixelPackedSampleModel;
49+import java.awt.image.WritableRaster;
50+
51+import javax.imageio.IIOException;
52+import javax.imageio.ImageIO;
53+import javax.imageio.ImageReader;
54+import javax.imageio.ImageReadParam;
55+import javax.imageio.ImageTypeSpecifier;
56+import javax.imageio.metadata.IIOMetadata;
57+import javax.imageio.spi.ImageReaderSpi;
58+import javax.imageio.stream.ImageInputStream;
59+import javax.imageio.event.IIOReadProgressListener;
60+import javax.imageio.event.IIOReadUpdateListener;
61+import javax.imageio.event.IIOReadWarningListener;
62+
63+import java.io.*;
64+import java.nio.*;
65+import java.security.AccessController;
66+import java.security.PrivilegedAction;
67+import java.util.ArrayList;
68+import java.util.Iterator;
69+import java.util.StringTokenizer;
70+
71+import com.sun.imageio.plugins.common.ImageUtil;
72+import com.sun.imageio.plugins.common.I18N;
73+
74+/** This class is the Java Image IO plugin reader for BMP images.
75+ * It may subsample the image, clip the image, select sub-bands,
76+ * and shift the decoded image origin if the proper decoding parameter
77+ * are set in the provided <code>ImageReadParam</code>.
78+ *
79+ * This class supports Microsoft Windows Bitmap Version 3-5,
80+ * as well as OS/2 Bitmap Version 2.x (for single-image BMP file).
81+ */
82+public class BMPImageReader extends ImageReader implements BMPConstants {
83+ // BMP Image types
84+ private static final int VERSION_2_1_BIT = 0;
85+ private static final int VERSION_2_4_BIT = 1;
86+ private static final int VERSION_2_8_BIT = 2;
87+ private static final int VERSION_2_24_BIT = 3;
88+
89+ private static final int VERSION_3_1_BIT = 4;
90+ private static final int VERSION_3_4_BIT = 5;
91+ private static final int VERSION_3_8_BIT = 6;
92+ private static final int VERSION_3_24_BIT = 7;
93+
94+ private static final int VERSION_3_NT_16_BIT = 8;
95+ private static final int VERSION_3_NT_32_BIT = 9;
96+
97+ private static final int VERSION_4_1_BIT = 10;
98+ private static final int VERSION_4_4_BIT = 11;
99+ private static final int VERSION_4_8_BIT = 12;
100+ private static final int VERSION_4_16_BIT = 13;
101+ private static final int VERSION_4_24_BIT = 14;
102+ private static final int VERSION_4_32_BIT = 15;
103+
104+ private static final int VERSION_3_XP_EMBEDDED = 16;
105+ private static final int VERSION_4_XP_EMBEDDED = 17;
106+ private static final int VERSION_5_XP_EMBEDDED = 18;
107+
108+ // BMP variables
109+ private long bitmapFileSize;
110+ private long bitmapOffset;
111+ private long compression;
112+ private long imageSize;
113+ private byte palette[];
114+ private int imageType;
115+ private int numBands;
116+ private boolean isBottomUp;
117+ private int bitsPerPixel;
118+ private int redMask, greenMask, blueMask, alphaMask;
119+
120+ private SampleModel sampleModel, originalSampleModel;
121+ private ColorModel colorModel, originalColorModel;
122+
123+ /** The input stream where reads from */
124+ private ImageInputStream iis = null;
125+
126+ /** Indicates whether the header is read. */
127+ private boolean gotHeader = false;
128+
129+ /** The original image width. */
130+ private int width;
131+
132+ /** The original image height. */
133+ private int height;
134+
135+ /** The destination region. */
136+ private Rectangle destinationRegion;
137+
138+ /** The source region. */
139+ private Rectangle sourceRegion;
140+
141+ /** The metadata from the stream. */
142+ private BMPMetadata metadata;
143+
144+ /** The destination image. */
145+ private BufferedImage bi;
146+
147+ /** Indicates whether subsampled, subregion is required, and offset is
148+ * defined
149+ */
150+ private boolean noTransform = true;
151+
152+ /** Indicates whether subband is selected. */
153+ private boolean seleBand = false;
154+
155+ /** The scaling factors. */
156+ private int scaleX, scaleY;
157+
158+ /** source and destination bands. */
159+ private int[] sourceBands, destBands;
160+
161+ /** Constructs <code>BMPImageReader</code> from the provided
162+ * <code>ImageReaderSpi</code>.
163+ */
164+ public BMPImageReader(ImageReaderSpi originator) {
165+ super(originator);
166+ }
167+
168+ /** Overrides the method defined in the superclass. */
169+ public void setInput(Object input,
170+ boolean seekForwardOnly,
171+ boolean ignoreMetadata) {
172+ super.setInput(input, seekForwardOnly, ignoreMetadata);
173+ iis = (ImageInputStream) input; // Always works
174+ if(iis != null)
175+ iis.setByteOrder(ByteOrder.LITTLE_ENDIAN);
176+ resetHeaderInfo();
177+ }
178+
179+ /** Overrides the method defined in the superclass. */
180+ public int getNumImages(boolean allowSearch) throws IOException {
181+ if (iis == null) {
182+ throw new IllegalStateException(I18N.getString("GetNumImages0"));
183+ }
184+ if (seekForwardOnly && allowSearch) {
185+ throw new IllegalStateException(I18N.getString("GetNumImages1"));
186+ }
187+ return 1;
188+ }
189+
190+ public int getWidth(int imageIndex) throws IOException {
191+ checkIndex(imageIndex);
192+ readHeader();
193+ return width;
194+ }
195+
196+ public int getHeight(int imageIndex) throws IOException {
197+ checkIndex(imageIndex);
198+ readHeader();
199+ return height;
200+ }
201+
202+ private void checkIndex(int imageIndex) {
203+ if (imageIndex != 0) {
204+ throw new IndexOutOfBoundsException(I18N.getString("BMPImageReader0"));
205+ }
206+ }
207+
208+ public void readHeader() throws IOException {
209+ if (gotHeader)
210+ return;
211+
212+ if (iis == null) {
213+ throw new IllegalStateException("Input source not set!");
214+ }
215+ int profileData = 0, profileSize = 0;
216+
217+ this.metadata = new BMPMetadata();
218+ iis.mark();
219+
220+ // read and check the magic marker
221+ byte[] marker = new byte[2];
222+ iis.read(marker);
223+ if (marker[0] != 0x42 || marker[1] != 0x4d)
224+ throw new IllegalArgumentException(I18N.getString("BMPImageReader1"));
225+
226+ // Read file size
227+ bitmapFileSize = iis.readUnsignedInt();
228+ // skip the two reserved fields
229+ iis.skipBytes(4);
230+
231+ // Offset to the bitmap from the beginning
232+ bitmapOffset = iis.readUnsignedInt();
233+ // End File Header
234+
235+ // Start BitmapCoreHeader
236+ long size = iis.readUnsignedInt();
237+
238+ if (size == 12) {
239+ width = iis.readShort();
240+ height = iis.readShort();
241+ } else {
242+ width = iis.readInt();
243+ height = iis.readInt();
244+ }
245+
246+ metadata.width = width;
247+ metadata.height = height;
248+
249+ int planes = iis.readUnsignedShort();
250+ bitsPerPixel = iis.readUnsignedShort();
251+
252+ //metadata.colorPlane = planes;
253+ metadata.bitsPerPixel = (short)bitsPerPixel;
254+
255+ // As BMP always has 3 rgb bands, except for Version 5,
256+ // which is bgra
257+ numBands = 3;
258+
259+ if (size == 12) {
260+ // Windows 2.x and OS/2 1.x
261+ metadata.bmpVersion = VERSION_2;
262+
263+ // Classify the image type
264+ if (bitsPerPixel == 1) {
265+ imageType = VERSION_2_1_BIT;
266+ } else if (bitsPerPixel == 4) {
267+ imageType = VERSION_2_4_BIT;
268+ } else if (bitsPerPixel == 8) {
269+ imageType = VERSION_2_8_BIT;
270+ } else if (bitsPerPixel == 24) {
271+ imageType = VERSION_2_24_BIT;
272+ }
273+
274+ // Read in the palette
275+ int numberOfEntries = (int)((bitmapOffset - 14 - size) / 3);
276+ int sizeOfPalette = numberOfEntries*3;
277+ palette = new byte[sizeOfPalette];
278+ iis.readFully(palette, 0, sizeOfPalette);
279+ metadata.palette = palette;
280+ metadata.paletteSize = numberOfEntries;
281+ } else {
282+ compression = iis.readUnsignedInt();
283+ imageSize = iis.readUnsignedInt();
284+ long xPelsPerMeter = iis.readInt();
285+ long yPelsPerMeter = iis.readInt();
286+ long colorsUsed = iis.readUnsignedInt();
287+ long colorsImportant = iis.readUnsignedInt();
288+
289+ metadata.compression = (int)compression;
290+ metadata.xPixelsPerMeter = (int)xPelsPerMeter;
291+ metadata.yPixelsPerMeter = (int)yPelsPerMeter;
292+ metadata.colorsUsed = (int)colorsUsed;
293+ metadata.colorsImportant = (int)colorsImportant;
294+
295+ if (size == 40) {
296+ // Windows 3.x and Windows NT
297+ switch((int)compression) {
298+
299+ case BI_JPEG:
300+ case BI_PNG:
301+ metadata.bmpVersion = VERSION_3;
302+ imageType = VERSION_3_XP_EMBEDDED;
303+ break;
304+
305+ case BI_RGB: // No compression
306+ case BI_RLE8: // 8-bit RLE compression
307+ case BI_RLE4: // 4-bit RLE compression
308+
309+ // Read in the palette
310+ int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
311+ int sizeOfPalette = numberOfEntries * 4;
312+ palette = new byte[sizeOfPalette];
313+ iis.readFully(palette, 0, sizeOfPalette);
314+
315+ metadata.palette = palette;
316+ metadata.paletteSize = numberOfEntries;
317+
318+ if (bitsPerPixel == 1) {
319+ imageType = VERSION_3_1_BIT;
320+ } else if (bitsPerPixel == 4) {
321+ imageType = VERSION_3_4_BIT;
322+ } else if (bitsPerPixel == 8) {
323+ imageType = VERSION_3_8_BIT;
324+ } else if (bitsPerPixel == 24) {
325+ imageType = VERSION_3_24_BIT;
326+ } else if (bitsPerPixel == 16) {
327+ imageType = VERSION_3_NT_16_BIT;
328+
329+ redMask = 0x7C00;
330+ greenMask = 0x3E0;
331+ blueMask = (1 << 5) - 1;// 0x1F;
332+ metadata.redMask = redMask;
333+ metadata.greenMask = greenMask;
334+ metadata.blueMask = blueMask;
335+ } else if (bitsPerPixel == 32) {
336+ imageType = VERSION_3_NT_32_BIT;
337+ redMask = 0x00FF0000;
338+ greenMask = 0x0000FF00;
339+ blueMask = 0x000000FF;
340+ metadata.redMask = redMask;
341+ metadata.greenMask = greenMask;
342+ metadata.blueMask = blueMask;
343+ }
344+
345+ metadata.bmpVersion = VERSION_3;
346+ break;
347+
348+ case BI_BITFIELDS:
349+
350+ if (bitsPerPixel == 16) {
351+ imageType = VERSION_3_NT_16_BIT;
352+ } else if (bitsPerPixel == 32) {
353+ imageType = VERSION_3_NT_32_BIT;
354+ }
355+
356+ // BitsField encoding
357+ redMask = (int)iis.readUnsignedInt();
358+ greenMask = (int)iis.readUnsignedInt();
359+ blueMask = (int)iis.readUnsignedInt();
360+ metadata.redMask = redMask;
361+ metadata.greenMask = greenMask;
362+ metadata.blueMask = blueMask;
363+
364+ if (colorsUsed != 0) {
365+ // there is a palette
366+ sizeOfPalette = (int)colorsUsed*4;
367+ palette = new byte[sizeOfPalette];
368+ iis.readFully(palette, 0, sizeOfPalette);
369+
370+ metadata.palette = palette;
371+ metadata.paletteSize = (int)colorsUsed;
372+ }
373+ metadata.bmpVersion = VERSION_3_NT;
374+
375+ break;
376+ default:
377+ throw new
378+ RuntimeException(I18N.getString("BMPImageReader2"));
379+ }
380+ } else if (size == 108 || size == 124) {
381+ // Windows 4.x BMP
382+ if (size == 108)
383+ metadata.bmpVersion = VERSION_4;
384+ else if (size == 124)
385+ metadata.bmpVersion = VERSION_5;
386+
387+ // rgb masks, valid only if comp is BI_BITFIELDS
388+ redMask = (int)iis.readUnsignedInt();
389+ greenMask = (int)iis.readUnsignedInt();
390+ blueMask = (int)iis.readUnsignedInt();
391+ // Only supported for 32bpp BI_RGB argb
392+ alphaMask = (int)iis.readUnsignedInt();
393+ long csType = iis.readUnsignedInt();
394+ int redX = iis.readInt();
395+ int redY = iis.readInt();
396+ int redZ = iis.readInt();
397+ int greenX = iis.readInt();
398+ int greenY = iis.readInt();
399+ int greenZ = iis.readInt();
400+ int blueX = iis.readInt();
401+ int blueY = iis.readInt();
402+ int blueZ = iis.readInt();
403+ long gammaRed = iis.readUnsignedInt();
404+ long gammaGreen = iis.readUnsignedInt();
405+ long gammaBlue = iis.readUnsignedInt();
406+
407+ if (size == 124) {
408+ metadata.intent = iis.readInt();
409+ profileData = iis.readInt();
410+ profileSize = iis.readInt();
411+ iis.skipBytes(4);
412+ }
413+
414+ metadata.colorSpace = (int)csType;
415+
416+ if (csType == LCS_CALIBRATED_RGB) {
417+ // All the new fields are valid only for this case
418+ metadata.redX = redX;
419+ metadata.redY = redY;
420+ metadata.redZ = redZ;
421+ metadata.greenX = greenX;
422+ metadata.greenY = greenY;
423+ metadata.greenZ = greenZ;
424+ metadata.blueX = blueX;
425+ metadata.blueY = blueY;
426+ metadata.blueZ = blueZ;
427+ metadata.gammaRed = (int)gammaRed;
428+ metadata.gammaGreen = (int)gammaGreen;
429+ metadata.gammaBlue = (int)gammaBlue;
430+ }
431+
432+ // Read in the palette
433+ int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
434+ int sizeOfPalette = numberOfEntries*4;
435+ palette = new byte[sizeOfPalette];
436+ iis.readFully(palette, 0, sizeOfPalette);
437+ metadata.palette = palette;
438+ metadata.paletteSize = numberOfEntries;
439+
440+ switch ((int)compression) {
441+ case BI_JPEG:
442+ case BI_PNG:
443+ if (size == 108) {
444+ imageType = VERSION_4_XP_EMBEDDED;
445+ } else if (size == 124) {
446+ imageType = VERSION_5_XP_EMBEDDED;
447+ }
448+ break;
449+ default:
450+ if (bitsPerPixel == 1) {
451+ imageType = VERSION_4_1_BIT;
452+ } else if (bitsPerPixel == 4) {
453+ imageType = VERSION_4_4_BIT;
454+ } else if (bitsPerPixel == 8) {
455+ imageType = VERSION_4_8_BIT;
456+ } else if (bitsPerPixel == 16) {
457+ imageType = VERSION_4_16_BIT;
458+ if ((int)compression == BI_RGB) {
459+ redMask = 0x7C00;
460+ greenMask = 0x3E0;
461+ blueMask = 0x1F;
462+ }
463+ } else if (bitsPerPixel == 24) {
464+ imageType = VERSION_4_24_BIT;
465+ } else if (bitsPerPixel == 32) {
466+ imageType = VERSION_4_32_BIT;
467+ if ((int)compression == BI_RGB) {
468+ redMask = 0x00FF0000;
469+ greenMask = 0x0000FF00;
470+ blueMask = 0x000000FF;
471+ }
472+ }
473+
474+ metadata.redMask = redMask;
475+ metadata.greenMask = greenMask;
476+ metadata.blueMask = blueMask;
477+ metadata.alphaMask = alphaMask;
478+ }
479+ } else {
480+ throw new
481+ RuntimeException(I18N.getString("BMPImageReader3"));
482+ }
483+ }
484+
485+ if (height > 0) {
486+ // bottom up image
487+ isBottomUp = true;
488+ } else {
489+ // top down image
490+ isBottomUp = false;
491+ height = Math.abs(height);
492+ }
493+
494+ // Reset Image Layout so there's only one tile.
495+ //Define the color space
496+ ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
497+ if (metadata.colorSpace == PROFILE_LINKED ||
498+ metadata.colorSpace == PROFILE_EMBEDDED) {
499+
500+ iis.mark();
501+ iis.skipBytes(profileData - size);
502+ byte[] profile = new byte[profileSize];
503+ iis.readFully(profile, 0, profileSize);
504+ iis.reset();
505+
506+ try {
507+ if (metadata.colorSpace == PROFILE_LINKED &&
508+ isLinkedProfileAllowed() &&
509+ !isUncOrDevicePath(profile))
510+ {
511+ String path = new String(profile, "windows-1252");
512+
513+ colorSpace =
514+ new ICC_ColorSpace(ICC_Profile.getInstance(path));
515+ } else {
516+ colorSpace =
517+ new ICC_ColorSpace(ICC_Profile.getInstance(profile));
518+ }
519+ } catch (Exception e) {
520+ colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
521+ }
522+ }
523+
524+ if (bitsPerPixel == 0 ||
525+ compression == BI_JPEG || compression == BI_PNG )
526+ {
527+ // the colorModel and sampleModel will be initialzed
528+ // by the reader of embedded image
529+ colorModel = null;
530+ sampleModel = null;
531+ } else if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) {
532+ // When number of bitsPerPixel is <= 8, we use IndexColorModel.
533+ numBands = 1;
534+
535+ if (bitsPerPixel == 8) {
536+ int[] bandOffsets = new int[numBands];
537+ for (int i = 0; i < numBands; i++) {
538+ bandOffsets[i] = numBands -1 -i;
539+ }
540+ sampleModel =
541+ new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
542+ width, height,
543+ numBands,
544+ numBands * width,
545+ bandOffsets);
546+ } else {
547+ // 1 and 4 bit pixels can be stored in a packed format.
548+ sampleModel =
549+ new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
550+ width, height,
551+ bitsPerPixel);
552+ }
553+
554+ // Create IndexColorModel from the palette.
555+ byte r[], g[], b[];
556+ if (imageType == VERSION_2_1_BIT ||
557+ imageType == VERSION_2_4_BIT ||
558+ imageType == VERSION_2_8_BIT) {
559+
560+
561+ size = palette.length/3;
562+
563+ if (size > 256) {
564+ size = 256;
565+ }
566+
567+ int off;
568+ r = new byte[(int)size];
569+ g = new byte[(int)size];
570+ b = new byte[(int)size];
571+ for (int i=0; i<(int)size; i++) {
572+ off = 3 * i;
573+ b[i] = palette[off];
574+ g[i] = palette[off+1];
575+ r[i] = palette[off+2];
576+ }
577+ } else {
578+ size = palette.length/4;
579+
580+ if (size > 256) {
581+ size = 256;
582+ }
583+
584+ int off;
585+ r = new byte[(int)size];
586+ g = new byte[(int)size];
587+ b = new byte[(int)size];
588+ for (int i=0; i<size; i++) {
589+ off = 4 * i;
590+ b[i] = palette[off];
591+ g[i] = palette[off+1];
592+ r[i] = palette[off+2];
593+ }
594+ }
595+
596+ if (ImageUtil.isIndicesForGrayscale(r, g, b))
597+ colorModel =
598+ ImageUtil.createColorModel(null, sampleModel);
599+ else
600+ colorModel = new IndexColorModel(bitsPerPixel, (int)size, r, g, b);
601+ } else if (bitsPerPixel == 16) {
602+ numBands = 3;
603+ sampleModel =
604+ new SinglePixelPackedSampleModel(DataBuffer.TYPE_USHORT,
605+ width, height,
606+ new int[] {redMask, greenMask, blueMask});
607+
608+ colorModel =
609+ new DirectColorModel(colorSpace,
610+ 16, redMask, greenMask, blueMask, 0,
611+ false, DataBuffer.TYPE_USHORT);
612+
613+ } else if (bitsPerPixel == 32) {
614+ numBands = alphaMask == 0 ? 3 : 4;
615+
616+ // The number of bands in the SampleModel is determined by
617+ // the length of the mask array passed in.
618+ int[] bitMasks = numBands == 3 ?
619+ new int[] {redMask, greenMask, blueMask} :
620+ new int[] {redMask, greenMask, blueMask, alphaMask};
621+
622+ sampleModel =
623+ new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT,
624+ width, height,
625+ bitMasks);
626+
627+ colorModel =
628+ new DirectColorModel(colorSpace,
629+ 32, redMask, greenMask, blueMask, alphaMask,
630+ false, DataBuffer.TYPE_INT);
631+ } else {
632+ numBands = 3;
633+ // Create SampleModel
634+ int[] bandOffsets = new int[numBands];
635+ for (int i = 0; i < numBands; i++) {
636+ bandOffsets[i] = numBands -1 -i;
637+ }
638+
639+ sampleModel =
640+ new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
641+ width, height,
642+ numBands,
643+ numBands * width,
644+ bandOffsets);
645+
646+ colorModel =
647+ ImageUtil.createColorModel(colorSpace, sampleModel);
648+ }
649+
650+ originalSampleModel = sampleModel;
651+ originalColorModel = colorModel;
652+
653+ // Reset to the start of bitmap; then jump to the
654+ //start of image data
655+ iis.reset();
656+ iis.skipBytes(bitmapOffset);
657+ gotHeader = true;
658+ }
659+
660+ public Iterator getImageTypes(int imageIndex)
661+ throws IOException {
662+ checkIndex(imageIndex);
663+ readHeader();
664+ ArrayList list = new ArrayList(1);
665+ list.add(new ImageTypeSpecifier(originalColorModel,
666+ originalSampleModel));
667+ return list.iterator();
668+ }
669+
670+ public ImageReadParam getDefaultReadParam() {
671+ return new ImageReadParam();
672+ }
673+
674+ public IIOMetadata getImageMetadata(int imageIndex)
675+ throws IOException {
676+ checkIndex(imageIndex);
677+ if (metadata == null) {
678+ readHeader();
679+ }
680+ return metadata;
681+ }
682+
683+ public IIOMetadata getStreamMetadata() throws IOException {
684+ return null;
685+ }
686+
687+ public boolean isRandomAccessEasy(int imageIndex) throws IOException {
688+ checkIndex(imageIndex);
689+ readHeader();
690+ return metadata.compression == BI_RGB;
691+ }
692+
693+ public BufferedImage read(int imageIndex, ImageReadParam param)
694+ throws IOException {
695+
696+ if (iis == null) {
697+ throw new IllegalStateException(I18N.getString("BMPImageReader5"));
698+ }
699+
700+ checkIndex(imageIndex);
701+ clearAbortRequest();
702+ processImageStarted(imageIndex);
703+
704+ if (param == null)
705+ param = getDefaultReadParam();
706+
707+ //read header
708+ readHeader();
709+
710+ sourceRegion = new Rectangle(0, 0, 0, 0);
711+ destinationRegion = new Rectangle(0, 0, 0, 0);
712+
713+ computeRegions(param, this.width, this.height,
714+ param.getDestination(),
715+ sourceRegion,
716+ destinationRegion);
717+
718+ scaleX = param.getSourceXSubsampling();
719+ scaleY = param.getSourceYSubsampling();
720+
721+ // If the destination band is set used it
722+ sourceBands = param.getSourceBands();
723+ destBands = param.getDestinationBands();
724+
725+ seleBand = (sourceBands != null) && (destBands != null);
726+ noTransform =
727+ destinationRegion.equals(new Rectangle(0, 0, width, height)) ||
728+ seleBand;
729+
730+ if (!seleBand) {
731+ sourceBands = new int[numBands];
732+ destBands = new int[numBands];
733+ for (int i = 0; i < numBands; i++)
734+ destBands[i] = sourceBands[i] = i;
735+ }
736+
737+ // If the destination is provided, then use it. Otherwise, create new one
738+ bi = param.getDestination();
739+
740+ // Get the image data.
741+ WritableRaster raster = null;
742+
743+ if (bi == null) {
744+ if (sampleModel != null && colorModel != null) {
745+ sampleModel =
746+ sampleModel.createCompatibleSampleModel(destinationRegion.x +
747+ destinationRegion.width,
748+ destinationRegion.y +
749+ destinationRegion.height);
750+ if (seleBand)
751+ sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
752+ raster = Raster.createWritableRaster(sampleModel, new Point());
753+ bi = new BufferedImage(colorModel, raster, false, null);
754+ }
755+ } else {
756+ raster = bi.getWritableTile(0, 0);
757+ sampleModel = bi.getSampleModel();
758+ colorModel = bi.getColorModel();
759+
760+ noTransform &= destinationRegion.equals(raster.getBounds());
761+ }
762+
763+ byte bdata[] = null; // buffer for byte data
764+ short sdata[] = null; // buffer for short data
765+ int idata[] = null; // buffer for int data
766+
767+ // the sampleModel can be null in case of embedded image
768+ if (sampleModel != null) {
769+ if (sampleModel.getDataType() == DataBuffer.TYPE_BYTE)
770+ bdata = (byte[])
771+ ((DataBufferByte)raster.getDataBuffer()).getData();
772+ else if (sampleModel.getDataType() == DataBuffer.TYPE_USHORT)
773+ sdata = (short[])
774+ ((DataBufferUShort)raster.getDataBuffer()).getData();
775+ else if (sampleModel.getDataType() == DataBuffer.TYPE_INT)
776+ idata = (int[])
777+ ((DataBufferInt)raster.getDataBuffer()).getData();
778+ }
779+
780+ // There should only be one tile.
781+ switch(imageType) {
782+
783+ case VERSION_2_1_BIT:
784+ // no compression
785+ read1Bit(bdata);
786+ break;
787+
788+ case VERSION_2_4_BIT:
789+ // no compression
790+ read4Bit(bdata);
791+ break;
792+
793+ case VERSION_2_8_BIT:
794+ // no compression
795+ read8Bit(bdata);
796+ break;
797+
798+ case VERSION_2_24_BIT:
799+ // no compression
800+ read24Bit(bdata);
801+ break;
802+
803+ case VERSION_3_1_BIT:
804+ // 1-bit images cannot be compressed.
805+ read1Bit(bdata);
806+ break;
807+
808+ case VERSION_3_4_BIT:
809+ switch((int)compression) {
810+ case BI_RGB:
811+ read4Bit(bdata);
812+ break;
813+
814+ case BI_RLE4:
815+ readRLE4(bdata);
816+ break;
817+
818+ default:
819+ throw new
820+ RuntimeException(I18N.getString("BMPImageReader1"));
821+ }
822+ break;
823+
824+ case VERSION_3_8_BIT:
825+ switch((int)compression) {
826+ case BI_RGB:
827+ read8Bit(bdata);
828+ break;
829+
830+ case BI_RLE8:
831+ readRLE8(bdata);
832+ break;
833+
834+ default:
835+ throw new
836+ RuntimeException(I18N.getString("BMPImageReader1"));
837+ }
838+
839+ break;
840+
841+ case VERSION_3_24_BIT:
842+ // 24-bit images are not compressed
843+ read24Bit(bdata);
844+ break;
845+
846+ case VERSION_3_NT_16_BIT:
847+ read16Bit(sdata);
848+ break;
849+
850+ case VERSION_3_NT_32_BIT:
851+ read32Bit(idata);
852+ break;
853+
854+ case VERSION_3_XP_EMBEDDED:
855+ case VERSION_4_XP_EMBEDDED:
856+ case VERSION_5_XP_EMBEDDED:
857+ bi = readEmbedded((int)compression, bi, param);
858+ break;
859+
860+ case VERSION_4_1_BIT:
861+ read1Bit(bdata);
862+ break;
863+
864+ case VERSION_4_4_BIT:
865+ switch((int)compression) {
866+
867+ case BI_RGB:
868+ read4Bit(bdata);
869+ break;
870+
871+ case BI_RLE4:
872+ readRLE4(bdata);
873+ break;
874+
875+ default:
876+ throw new
877+ RuntimeException(I18N.getString("BMPImageReader1"));
878+ }
879+
880+ case VERSION_4_8_BIT:
881+ switch((int)compression) {
882+
883+ case BI_RGB:
884+ read8Bit(bdata);
885+ break;
886+
887+ case BI_RLE8:
888+ readRLE8(bdata);
889+ break;
890+
891+ default:
892+ throw new
893+ RuntimeException(I18N.getString("BMPImageReader1"));
894+ }
895+ break;
896+
897+ case VERSION_4_16_BIT:
898+ read16Bit(sdata);
899+ break;
900+
901+ case VERSION_4_24_BIT:
902+ read24Bit(bdata);
903+ break;
904+
905+ case VERSION_4_32_BIT:
906+ read32Bit(idata);
907+ break;
908+ }
909+
910+ if (abortRequested())
911+ processReadAborted();
912+ else
913+ processImageComplete();
914+
915+ return bi;
916+ }
917+
918+ public boolean canReadRaster() {
919+ return true;
920+ }
921+
922+ public Raster readRaster(int imageIndex,
923+ ImageReadParam param) throws IOException {
924+ BufferedImage bi = read(imageIndex, param);
925+ return bi.getData();
926+ }
927+
928+ private void resetHeaderInfo() {
929+ gotHeader = false;
930+ bi = null;
931+ sampleModel = originalSampleModel = null;
932+ colorModel = originalColorModel = null;
933+ }
934+
935+ public void reset() {
936+ super.reset();
937+ iis = null;
938+ resetHeaderInfo();
939+ }
940+
941+ // Deal with 1 Bit images using IndexColorModels
942+ private void read1Bit(byte[] bdata) throws IOException {
943+ int bytesPerScanline = (width + 7) / 8;
944+ int padding = bytesPerScanline % 4;
945+ if (padding != 0) {
946+ padding = 4 - padding;
947+ }
948+
949+ int lineLength = bytesPerScanline + padding;
950+
951+ if (noTransform) {
952+ int j = isBottomUp ? (height -1)*bytesPerScanline : 0;
953+
954+ for (int i=0; i<height; i++) {
955+ if (abortRequested()) {
956+ break;
957+ }
958+ iis.readFully(bdata, j, bytesPerScanline);
959+ iis.skipBytes(padding);
960+ j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
961+ processImageUpdate(bi, 0, i,
962+ destinationRegion.width, 1, 1, 1,
963+ new int[]{0});
964+ processImageProgress(100.0F * i/destinationRegion.height);
965+ }
966+ } else {
967+ byte[] buf = new byte[lineLength];
968+ int lineStride =
969+ ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
970+
971+ if (isBottomUp) {
972+ int lastLine =
973+ sourceRegion.y + (destinationRegion.height - 1) * scaleY;
974+ iis.skipBytes(lineLength * (height - 1 - lastLine));
975+ } else
976+ iis.skipBytes(lineLength * sourceRegion.y);
977+
978+ int skipLength = lineLength * (scaleY - 1);
979+
980+ // cache the values to avoid duplicated computation
981+ int[] srcOff = new int[destinationRegion.width];
982+ int[] destOff = new int[destinationRegion.width];
983+ int[] srcPos = new int[destinationRegion.width];
984+ int[] destPos = new int[destinationRegion.width];
985+
986+ for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
987+ i < destinationRegion.x + destinationRegion.width;
988+ i++, j++, x += scaleX) {
989+ srcPos[j] = x >> 3;
990+ srcOff[j] = 7 - (x & 7);
991+ destPos[j] = i >> 3;
992+ destOff[j] = 7 - (i & 7);
993+ }
994+
995+ int k = destinationRegion.y * lineStride;
996+ if (isBottomUp)
997+ k += (destinationRegion.height - 1) * lineStride;
998+
999+ for (int j = 0, y = sourceRegion.y;
1000+ j < destinationRegion.height; j++, y+=scaleY) {
1001+
1002+ if (abortRequested())
1003+ break;
1004+ iis.read(buf, 0, lineLength);
1005+ for (int i = 0; i < destinationRegion.width; i++) {
1006+ //get the bit and assign to the data buffer of the raster
1007+ int v = (buf[srcPos[i]] >> srcOff[i]) & 1;
1008+ bdata[k + destPos[i]] |= v << destOff[i];
1009+ }
1010+
1011+ k += isBottomUp ? -lineStride : lineStride;
1012+ iis.skipBytes(skipLength);
1013+ processImageUpdate(bi, 0, j,
1014+ destinationRegion.width, 1, 1, 1,
1015+ new int[]{0});
1016+ processImageProgress(100.0F*j/destinationRegion.height);
1017+ }
1018+ }
1019+ }
1020+
1021+ // Method to read a 4 bit BMP image data
1022+ private void read4Bit(byte[] bdata) throws IOException {
1023+
1024+ int bytesPerScanline = (width + 1) / 2;
1025+
1026+ // Padding bytes at the end of each scanline
1027+ int padding = bytesPerScanline % 4;
1028+ if (padding != 0)
1029+ padding = 4 - padding;
1030+
1031+ int lineLength = bytesPerScanline + padding;
1032+
1033+ if (noTransform) {
1034+ int j = isBottomUp ? (height -1) * bytesPerScanline : 0;
1035+
1036+ for (int i=0; i<height; i++) {
1037+ if (abortRequested()) {
1038+ break;
1039+ }
1040+ iis.readFully(bdata, j, bytesPerScanline);
1041+ iis.skipBytes(padding);
1042+ j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
1043+ processImageUpdate(bi, 0, i,
1044+ destinationRegion.width, 1, 1, 1,
1045+ new int[]{0});
1046+ processImageProgress(100.0F * i/destinationRegion.height);
1047+ }
1048+ } else {
1049+ byte[] buf = new byte[lineLength];
1050+ int lineStride =
1051+ ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
1052+
1053+ if (isBottomUp) {
1054+ int lastLine =
1055+ sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1056+ iis.skipBytes(lineLength * (height - 1 - lastLine));
1057+ } else
1058+ iis.skipBytes(lineLength * sourceRegion.y);
1059+
1060+ int skipLength = lineLength * (scaleY - 1);
1061+
1062+ // cache the values to avoid duplicated computation
1063+ int[] srcOff = new int[destinationRegion.width];
1064+ int[] destOff = new int[destinationRegion.width];
1065+ int[] srcPos = new int[destinationRegion.width];
1066+ int[] destPos = new int[destinationRegion.width];
1067+
1068+ for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
1069+ i < destinationRegion.x + destinationRegion.width;
1070+ i++, j++, x += scaleX) {
1071+ srcPos[j] = x >> 1;
1072+ srcOff[j] = (1 - (x & 1)) << 2;
1073+ destPos[j] = i >> 1;
1074+ destOff[j] = (1 - (i & 1)) << 2;
1075+ }
1076+
1077+ int k = destinationRegion.y * lineStride;
1078+ if (isBottomUp)
1079+ k += (destinationRegion.height - 1) * lineStride;
1080+
1081+ for (int j = 0, y = sourceRegion.y;
1082+ j < destinationRegion.height; j++, y+=scaleY) {
1083+
1084+ if (abortRequested())
1085+ break;
1086+ iis.read(buf, 0, lineLength);
1087+ for (int i = 0; i < destinationRegion.width; i++) {
1088+ //get the bit and assign to the data buffer of the raster
1089+ int v = (buf[srcPos[i]] >> srcOff[i]) & 0x0F;
1090+ bdata[k + destPos[i]] |= v << destOff[i];
1091+ }
1092+
1093+ k += isBottomUp ? -lineStride : lineStride;
1094+ iis.skipBytes(skipLength);
1095+ processImageUpdate(bi, 0, j,
1096+ destinationRegion.width, 1, 1, 1,
1097+ new int[]{0});
1098+ processImageProgress(100.0F*j/destinationRegion.height);
1099+ }
1100+ }
1101+ }
1102+
1103+ // Method to read 8 bit BMP image data
1104+ private void read8Bit(byte[] bdata) throws IOException {
1105+
1106+ // Padding bytes at the end of each scanline
1107+ int padding = width % 4;
1108+ if (padding != 0) {
1109+ padding = 4 - padding;
1110+ }
1111+
1112+ int lineLength = width + padding;
1113+
1114+ if (noTransform) {
1115+ int j = isBottomUp ? (height -1) * width : 0;
1116+
1117+ for (int i=0; i<height; i++) {
1118+ if (abortRequested()) {
1119+ break;
1120+ }
1121+ iis.readFully(bdata, j, width);
1122+ iis.skipBytes(padding);
1123+ j += isBottomUp ? -width : width;
1124+ processImageUpdate(bi, 0, i,
1125+ destinationRegion.width, 1, 1, 1,
1126+ new int[]{0});
1127+ processImageProgress(100.0F * i/destinationRegion.height);
1128+ }
1129+ } else {
1130+ byte[] buf = new byte[lineLength];
1131+ int lineStride =
1132+ ((ComponentSampleModel)sampleModel).getScanlineStride();
1133+
1134+ if (isBottomUp) {
1135+ int lastLine =
1136+ sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1137+ iis.skipBytes(lineLength * (height - 1 - lastLine));
1138+ } else
1139+ iis.skipBytes(lineLength * sourceRegion.y);
1140+
1141+ int skipLength = lineLength * (scaleY - 1);
1142+
1143+ int k = destinationRegion.y * lineStride;
1144+ if (isBottomUp)
1145+ k += (destinationRegion.height - 1) * lineStride;
1146+ k += destinationRegion.x;
1147+
1148+ for (int j = 0, y = sourceRegion.y;
1149+ j < destinationRegion.height; j++, y+=scaleY) {
1150+
1151+ if (abortRequested())
1152+ break;
1153+ iis.read(buf, 0, lineLength);
1154+ for (int i = 0, m = sourceRegion.x;
1155+ i < destinationRegion.width; i++, m += scaleX) {
1156+ //get the bit and assign to the data buffer of the raster
1157+ bdata[k + i] = buf[m];
1158+ }
1159+
1160+ k += isBottomUp ? -lineStride : lineStride;
1161+ iis.skipBytes(skipLength);
1162+ processImageUpdate(bi, 0, j,
1163+ destinationRegion.width, 1, 1, 1,
1164+ new int[]{0});
1165+ processImageProgress(100.0F*j/destinationRegion.height);
1166+ }
1167+ }
1168+ }
1169+
1170+ // Method to read 24 bit BMP image data
1171+ private void read24Bit(byte[] bdata) throws IOException {
1172+ // Padding bytes at the end of each scanline
1173+ // width * bitsPerPixel should be divisible by 32
1174+ int padding = width * 3 % 4;
1175+ if ( padding != 0)
1176+ padding = 4 - padding;
1177+
1178+ int lineStride = width * 3;
1179+ int lineLength = lineStride + padding;
1180+
1181+ if (noTransform) {
1182+ int j = isBottomUp ? (height -1) * width * 3 : 0;
1183+
1184+ for (int i=0; i<height; i++) {
1185+ if (abortRequested()) {
1186+ break;
1187+ }
1188+ iis.readFully(bdata, j, lineStride);
1189+ iis.skipBytes(padding);
1190+ j += isBottomUp ? -lineStride : lineStride;
1191+ processImageUpdate(bi, 0, i,
1192+ destinationRegion.width, 1, 1, 1,
1193+ new int[]{0});
1194+ processImageProgress(100.0F * i/destinationRegion.height);
1195+ }
1196+ } else {
1197+ byte[] buf = new byte[lineLength];
1198+ lineStride =
1199+ ((ComponentSampleModel)sampleModel).getScanlineStride();
1200+
1201+ if (isBottomUp) {
1202+ int lastLine =
1203+ sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1204+ iis.skipBytes(lineLength * (height - 1 - lastLine));
1205+ } else
1206+ iis.skipBytes(lineLength * sourceRegion.y);
1207+
1208+ int skipLength = lineLength * (scaleY - 1);
1209+
1210+ int k = destinationRegion.y * lineStride;
1211+ if (isBottomUp)
1212+ k += (destinationRegion.height - 1) * lineStride;
1213+ k += destinationRegion.x * 3;
1214+
1215+ for (int j = 0, y = sourceRegion.y;
1216+ j < destinationRegion.height; j++, y+=scaleY) {
1217+
1218+ if (abortRequested())
1219+ break;
1220+ iis.read(buf, 0, lineLength);
1221+ for (int i = 0, m = 3 * sourceRegion.x;
1222+ i < destinationRegion.width; i++, m += 3 * scaleX) {
1223+ //get the bit and assign to the data buffer of the raster
1224+ int n = 3 * i + k;
1225+ for (int b = 0; b < destBands.length; b++)
1226+ bdata[n + destBands[b]] = buf[m + sourceBands[b]];
1227+ }
1228+
1229+ k += isBottomUp ? -lineStride : lineStride;
1230+ iis.skipBytes(skipLength);
1231+ processImageUpdate(bi, 0, j,
1232+ destinationRegion.width, 1, 1, 1,
1233+ new int[]{0});
1234+ processImageProgress(100.0F*j/destinationRegion.height);
1235+ }
1236+ }
1237+ }
1238+
1239+ private void read16Bit(short sdata[]) throws IOException {
1240+ // Padding bytes at the end of each scanline
1241+ // width * bitsPerPixel should be divisible by 32
1242+ int padding = width * 2 % 4;
1243+
1244+ if ( padding != 0)
1245+ padding = 4 - padding;
1246+
1247+ int lineLength = width + padding / 2;
1248+
1249+ if (noTransform) {
1250+ int j = isBottomUp ? (height -1) * width : 0;
1251+ for (int i=0; i<height; i++) {
1252+ if (abortRequested()) {
1253+ break;
1254+ }
1255+
1256+ iis.readFully(sdata, j, width);
1257+ iis.skipBytes(padding);
1258+
1259+ j += isBottomUp ? -width : width;
1260+ processImageUpdate(bi, 0, i,
1261+ destinationRegion.width, 1, 1, 1,
1262+ new int[]{0});
1263+ processImageProgress(100.0F * i/destinationRegion.height);
1264+ }
1265+ } else {
1266+ short[] buf = new short[lineLength];
1267+ int lineStride =
1268+ ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
1269+
1270+ if (isBottomUp) {
1271+ int lastLine =
1272+ sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1273+ iis.skipBytes(lineLength * (height - 1 - lastLine) << 1);
1274+ } else
1275+ iis.skipBytes(lineLength * sourceRegion.y << 1);
1276+
1277+ int skipLength = lineLength * (scaleY - 1) << 1;
1278+
1279+ int k = destinationRegion.y * lineStride;
1280+ if (isBottomUp)
1281+ k += (destinationRegion.height - 1) * lineStride;
1282+ k += destinationRegion.x;
1283+
1284+ for (int j = 0, y = sourceRegion.y;
1285+ j < destinationRegion.height; j++, y+=scaleY) {
1286+
1287+ if (abortRequested())
1288+ break;
1289+ iis.readFully(buf, 0, lineLength);
1290+ for (int i = 0, m = sourceRegion.x;
1291+ i < destinationRegion.width; i++, m += scaleX) {
1292+ //get the bit and assign to the data buffer of the raster
1293+ sdata[k + i] = buf[m];
1294+ }
1295+
1296+ k += isBottomUp ? -lineStride : lineStride;
1297+ iis.skipBytes(skipLength);
1298+ processImageUpdate(bi, 0, j,
1299+ destinationRegion.width, 1, 1, 1,
1300+ new int[]{0});
1301+ processImageProgress(100.0F*j/destinationRegion.height);
1302+ }
1303+ }
1304+ }
1305+
1306+ private void read32Bit(int idata[]) throws IOException {
1307+ if (noTransform) {
1308+ int j = isBottomUp ? (height -1) * width : 0;
1309+
1310+ for (int i=0; i<height; i++) {
1311+ if (abortRequested()) {
1312+ break;
1313+ }
1314+ iis.readFully(idata, j, width);
1315+ j += isBottomUp ? -width : width;
1316+ processImageUpdate(bi, 0, i,
1317+ destinationRegion.width, 1, 1, 1,
1318+ new int[]{0});
1319+ processImageProgress(100.0F * i/destinationRegion.height);
1320+ }
1321+ } else {
1322+ int[] buf = new int[width];
1323+ int lineStride =
1324+ ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
1325+
1326+ if (isBottomUp) {
1327+ int lastLine =
1328+ sourceRegion.y + (destinationRegion.height - 1) * scaleY;
1329+ iis.skipBytes(width * (height - 1 - lastLine) << 2);
1330+ } else
1331+ iis.skipBytes(width * sourceRegion.y << 2);
1332+
1333+ int skipLength = width * (scaleY - 1) << 2;
1334+
1335+ int k = destinationRegion.y * lineStride;
1336+ if (isBottomUp)
1337+ k += (destinationRegion.height - 1) * lineStride;
1338+ k += destinationRegion.x;
1339+
1340+ for (int j = 0, y = sourceRegion.y;
1341+ j < destinationRegion.height; j++, y+=scaleY) {
1342+
1343+ if (abortRequested())
1344+ break;
1345+ iis.readFully(buf, 0, width);
1346+ for (int i = 0, m = sourceRegion.x;
1347+ i < destinationRegion.width; i++, m += scaleX) {
1348+ //get the bit and assign to the data buffer of the raster
1349+ idata[k + i] = buf[m];
1350+ }
1351+
1352+ k += isBottomUp ? -lineStride : lineStride;
1353+ iis.skipBytes(skipLength);
1354+ processImageUpdate(bi, 0, j,
1355+ destinationRegion.width, 1, 1, 1,
1356+ new int[]{0});
1357+ processImageProgress(100.0F*j/destinationRegion.height);
1358+ }
1359+ }
1360+ }
1361+
1362+ private void readRLE8(byte bdata[]) throws IOException {
1363+ // If imageSize field is not provided, calculate it.
1364+ int imSize = (int)imageSize;
1365+ if (imSize == 0) {
1366+ imSize = (int)(bitmapFileSize - bitmapOffset);
1367+ }
1368+
1369+ int padding = 0;
1370+ // If width is not 32 bit aligned, then while uncompressing each
1371+ // scanline will have padding bytes, calculate the amount of padding
1372+ int remainder = width % 4;
1373+ if (remainder != 0) {
1374+ padding = 4 - remainder;
1375+ }
1376+
1377+ // Read till we have the whole image
1378+ byte values[] = new byte[imSize];
1379+ int bytesRead = 0;
1380+ iis.readFully(values, 0, imSize);
1381+
1382+ // Since data is compressed, decompress it
1383+ decodeRLE8(imSize, padding, values, bdata);
1384+ }
1385+
1386+ private void decodeRLE8(int imSize,
1387+ int padding,
1388+ byte[] values,
1389+ byte[] bdata) throws IOException {
1390+
1391+ byte val[] = new byte[width * height];
1392+ int count = 0, l = 0;
1393+ int value;
1394+ boolean flag = false;
1395+ int lineNo = isBottomUp ? height - 1 : 0;
1396+ int lineStride =
1397+ ((ComponentSampleModel)sampleModel).getScanlineStride();
1398+ int finished = 0;
1399+
1400+ while (count != imSize) {
1401+ value = values[count++] & 0xff;
1402+ if (value == 0) {
1403+ switch(values[count++] & 0xff) {
1404+
1405+ case 0:
1406+ // End-of-scanline marker
1407+ if (lineNo >= sourceRegion.y &&
1408+ lineNo < sourceRegion.y + sourceRegion.height) {
1409+ if (noTransform) {
1410+ int pos = lineNo * width;
1411+ for(int i = 0; i < width; i++)
1412+ bdata[pos++] = val[i];
1413+ processImageUpdate(bi, 0, lineNo,
1414+ destinationRegion.width, 1, 1, 1,
1415+ new int[]{0});
1416+ finished++;
1417+ } else if ((lineNo - sourceRegion.y) % scaleY == 0) {
1418+ int currentLine = (lineNo - sourceRegion.y) / scaleY +
1419+ destinationRegion.y;
1420+ int pos = currentLine * lineStride;
1421+ pos += destinationRegion.x;
1422+ for (int i = sourceRegion.x;
1423+ i < sourceRegion.x + sourceRegion.width;
1424+ i += scaleX)
1425+ bdata[pos++] = val[i];
1426+ processImageUpdate(bi, 0, currentLine,
1427+ destinationRegion.width, 1, 1, 1,
1428+ new int[]{0});
1429+ finished++;
1430+ }
1431+ }
1432+ processImageProgress(100.0F * finished / destinationRegion.height);
1433+ lineNo += isBottomUp ? -1 : 1;
1434+ l = 0;
1435+
1436+ if (abortRequested()) {
1437+ flag = true;
1438+ }
1439+
1440+ break;
1441+
1442+ case 1:
1443+ // End-of-RLE marker
1444+ flag = true;
1445+ break;
1446+
1447+ case 2:
1448+ // delta or vector marker
1449+ int xoff = values[count++] & 0xff;
1450+ int yoff = values[count] & 0xff;
1451+ // Move to the position xoff, yoff down
1452+ l += xoff + yoff*width;
1453+ break;
1454+
1455+ default:
1456+ int end = values[count-1] & 0xff;
1457+ for (int i=0; i<end; i++) {
1458+ val[l++] = (byte)(values[count++] & 0xff);
1459+ }
1460+
1461+ // Whenever end pixels can fit into odd number of bytes,
1462+ // an extra padding byte will be present, so skip that.
1463+ if ((end & 1) == 1) {
1464+ count++;
1465+ }
1466+ }
1467+ } else {
1468+ for (int i=0; i<value; i++) {
1469+ val[l++] = (byte)(values[count] & 0xff);
1470+ }
1471+
1472+ count++;
1473+ }
1474+
1475+ // If End-of-RLE data, then exit the while loop
1476+ if (flag) {
1477+ break;
1478+ }
1479+ }
1480+ }
1481+
1482+ private void readRLE4(byte[] bdata) throws IOException {
1483+
1484+ // If imageSize field is not specified, calculate it.
1485+ int imSize = (int)imageSize;
1486+ if (imSize == 0) {
1487+ imSize = (int)(bitmapFileSize - bitmapOffset);
1488+ }
1489+
1490+ int padding = 0;
1491+ // If width is not 32 byte aligned, then while uncompressing each
1492+ // scanline will have padding bytes, calculate the amount of padding
1493+ int remainder = width % 4;
1494+ if (remainder != 0) {
1495+ padding = 4 - remainder;
1496+ }
1497+
1498+ // Read till we have the whole image
1499+ byte[] values = new byte[imSize];
1500+ iis.readFully(values, 0, imSize);
1501+
1502+ // Decompress the RLE4 compressed data.
1503+ decodeRLE4(imSize, padding, values, bdata);
1504+ }
1505+
1506+ private void decodeRLE4(int imSize,
1507+ int padding,
1508+ byte[] values,
1509+ byte[] bdata) throws IOException {
1510+ byte[] val = new byte[width];
1511+ int count = 0, l = 0;
1512+ int value;
1513+ boolean flag = false;
1514+ int lineNo = isBottomUp ? height - 1 : 0;
1515+ int lineStride =
1516+ ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
1517+ int finished = 0;
1518+
1519+ while (count != imSize) {
1520+
1521+ value = values[count++] & 0xFF;
1522+ if (value == 0) {
1523+
1524+
1525+ // Absolute mode
1526+ switch(values[count++] & 0xFF) {
1527+
1528+ case 0:
1529+ // End-of-scanline marker
1530+ // End-of-scanline marker
1531+ if (lineNo >= sourceRegion.y &&
1532+ lineNo < sourceRegion.y + sourceRegion.height) {
1533+ if (noTransform) {
1534+ int pos = lineNo * (width + 1 >> 1);
1535+ for(int i = 0, j = 0; i < width >> 1; i++)
1536+ bdata[pos++] =
1537+ (byte)((val[j++] << 4) | val[j++]);
1538+ if ((width & 1) == 1)
1539+ bdata[pos] |= val[width - 1] << 4;
1540+
1541+ processImageUpdate(bi, 0, lineNo,
1542+ destinationRegion.width, 1, 1, 1,
1543+ new int[]{0});
1544+ finished++;
1545+ } else if ((lineNo - sourceRegion.y) % scaleY == 0) {
1546+ int currentLine = (lineNo - sourceRegion.y) / scaleY +
1547+ destinationRegion.y;
1548+ int pos = currentLine * lineStride;
1549+ pos += destinationRegion.x >> 1;
1550+ int shift = (1 - (destinationRegion.x & 1)) << 2;
1551+ for (int i = sourceRegion.x;
1552+ i < sourceRegion.x + sourceRegion.width;
1553+ i += scaleX) {
1554+ bdata[pos] |= val[i] << shift;
1555+ shift += 4;
1556+ if (shift == 4) {
1557+ pos++;
1558+ }
1559+ shift &= 7;
1560+ }
1561+ processImageUpdate(bi, 0, currentLine,
1562+ destinationRegion.width, 1, 1, 1,
1563+ new int[]{0});
1564+ finished++;
1565+ }
1566+ }
1567+ processImageProgress(100.0F * finished / destinationRegion.height);
1568+ lineNo += isBottomUp ? -1 : 1;
1569+ l = 0;
1570+
1571+ if (abortRequested()) {
1572+ flag = true;
1573+ }
1574+
1575+ break;
1576+
1577+ case 1:
1578+ // End-of-RLE marker
1579+ flag = true;
1580+ break;
1581+
1582+ case 2:
1583+ // delta or vector marker
1584+ int xoff = values[count++] & 0xFF;
1585+ int yoff = values[count] & 0xFF;
1586+ // Move to the position xoff, yoff down
1587+ l += xoff + yoff*width;
1588+ break;
1589+
1590+ default:
1591+ int end = values[count-1] & 0xFF;
1592+ for (int i=0; i<end; i++) {
1593+ val[l++] = (byte)(((i & 1) == 0) ? (values[count] & 0xf0) >> 4
1594+ : (values[count++] & 0x0f));
1595+ }
1596+
1597+ // When end is odd, the above for loop does not
1598+ // increment count, so do it now.
1599+ if ((end & 1) == 1) {
1600+ count++;
1601+ }
1602+
1603+ // Whenever end pixels can fit into odd number of bytes,
1604+ // an extra padding byte will be present, so skip that.
1605+ if ((((int)Math.ceil(end/2)) & 1) ==1 ) {
1606+ count++;
1607+ }
1608+ break;
1609+ }
1610+ } else {
1611+ // Encoded mode
1612+ int alternate[] = { (values[count] & 0xf0) >> 4,
1613+ values[count] & 0x0f };
1614+ for (int i=0; (i < value) && (l < width); i++) {
1615+ val[l++] = (byte)alternate[i & 1];
1616+ }
1617+
1618+ count++;
1619+ }
1620+
1621+ // If End-of-RLE data, then exit the while loop
1622+ if (flag) {
1623+ break;
1624+ }
1625+ }
1626+ }
1627+
1628+ /** Decodes the jpeg/png image embedded in the bitmap using any jpeg
1629+ * ImageIO-style plugin.
1630+ *
1631+ * @param bi The destination <code>BufferedImage</code>.
1632+ * @param bmpParam The <code>ImageReadParam</code> for decoding this
1633+ * BMP image. The parameters for subregion, band selection and
1634+ * subsampling are used in decoding the jpeg image.
1635+ */
1636+
1637+ private BufferedImage readEmbedded(int type,
1638+ BufferedImage bi, ImageReadParam bmpParam)
1639+ throws IOException {
1640+ String format;
1641+ switch(type) {
1642+ case BI_JPEG:
1643+ format = "JPEG";
1644+ break;
1645+ case BI_PNG:
1646+ format = "PNG";
1647+ break;
1648+ default:
1649+ throw new
1650+ IOException("Unexpected compression type: " + type);
1651+ }
1652+ ImageReader reader =
1653+ ImageIO.getImageReadersByFormatName(format).next();
1654+ if (reader == null) {
1655+ throw new RuntimeException(I18N.getString("BMPImageReader4") +
1656+ " " + format);
1657+ }
1658+ // prepare input
1659+ byte[] buff = new byte[(int)imageSize];
1660+ iis.read(buff);
1661+ reader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(buff)));
1662+ if (bi == null) {
1663+ ImageTypeSpecifier embType = reader.getImageTypes(0).next();
1664+ bi = embType.createBufferedImage(destinationRegion.x +
1665+ destinationRegion.width,
1666+ destinationRegion.y +
1667+ destinationRegion.height);
1668+ }
1669+
1670+ reader.addIIOReadProgressListener(new EmbeddedProgressAdapter() {
1671+ public void imageProgress(ImageReader source,
1672+ float percentageDone)
1673+ {
1674+ processImageProgress(percentageDone);
1675+ }
1676+ });
1677+
1678+ reader.addIIOReadUpdateListener(new IIOReadUpdateListener() {
1679+ public void imageUpdate(ImageReader source,
1680+ BufferedImage theImage,
1681+ int minX, int minY,
1682+ int width, int height,
1683+ int periodX, int periodY,
1684+ int[] bands)
1685+ {
1686+ processImageUpdate(theImage, minX, minY,
1687+ width, height,
1688+ periodX, periodY, bands);
1689+ }
1690+ public void passComplete(ImageReader source,
1691+ BufferedImage theImage)
1692+ {
1693+ processPassComplete(theImage);
1694+ }
1695+ public void passStarted(ImageReader source,
1696+ BufferedImage theImage,
1697+ int pass,
1698+ int minPass, int maxPass,
1699+ int minX, int minY,
1700+ int periodX, int periodY,
1701+ int[] bands)
1702+ {
1703+ processPassStarted(theImage, pass, minPass, maxPass,
1704+ minX, minY, periodX, periodY,
1705+ bands);
1706+ }
1707+ public void thumbnailPassComplete(ImageReader source,
1708+ BufferedImage thumb) {}
1709+ public void thumbnailPassStarted(ImageReader source,
1710+ BufferedImage thumb,
1711+ int pass,
1712+ int minPass, int maxPass,
1713+ int minX, int minY,
1714+ int periodX, int periodY,
1715+ int[] bands) {}
1716+ public void thumbnailUpdate(ImageReader source,
1717+ BufferedImage theThumbnail,
1718+ int minX, int minY,
1719+ int width, int height,
1720+ int periodX, int periodY,
1721+ int[] bands) {}
1722+ });
1723+
1724+ reader.addIIOReadWarningListener(new IIOReadWarningListener() {
1725+ public void warningOccurred(ImageReader source, String warning)
1726+ {
1727+ processWarningOccurred(warning);
1728+ }
1729+ });
1730+
1731+ ImageReadParam param = reader.getDefaultReadParam();
1732+ param.setDestination(bi);
1733+ param.setDestinationBands(bmpParam.getDestinationBands());
1734+ param.setDestinationOffset(bmpParam.getDestinationOffset());
1735+ param.setSourceBands(bmpParam.getSourceBands());
1736+ param.setSourceRegion(bmpParam.getSourceRegion());
1737+ param.setSourceSubsampling(bmpParam.getSourceXSubsampling(),
1738+ bmpParam.getSourceYSubsampling(),
1739+ bmpParam.getSubsamplingXOffset(),
1740+ bmpParam.getSubsamplingYOffset());
1741+ reader.read(0, param);
1742+ return bi;
1743+ }
1744+
1745+ private class EmbeddedProgressAdapter implements IIOReadProgressListener {
1746+ public void imageComplete(ImageReader src) {}
1747+ public void imageProgress(ImageReader src, float percentageDone) {}
1748+ public void imageStarted(ImageReader src, int imageIndex) {}
1749+ public void thumbnailComplete(ImageReader src) {}
1750+ public void thumbnailProgress(ImageReader src, float percentageDone) {}
1751+ public void thumbnailStarted(ImageReader src, int iIdx, int tIdx) {}
1752+ public void sequenceComplete(ImageReader src) {}
1753+ public void sequenceStarted(ImageReader src, int minIndex) {}
1754+ public void readAborted(ImageReader src) {}
1755+ }
1756+
1757+ private static Boolean isLinkedProfileDisabled = null;
1758+
1759+ private static boolean isLinkedProfileAllowed() {
1760+ if (isLinkedProfileDisabled == null) {
1761+ PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() {
1762+ public Boolean run() {
1763+ return Boolean.getBoolean("sun.imageio.plugins.bmp.disableLinkedProfiles");
1764+ }
1765+ };
1766+ isLinkedProfileDisabled = AccessController.doPrivileged(a);
1767+ }
1768+ return !isLinkedProfileDisabled;
1769+ }
1770+
1771+ private static Boolean isWindowsPlatform = null;
1772+
1773+ /**
1774+ * Verifies whether the byte array contans a unc path.
1775+ * Non-UNC path examples:
1776+ * c:\path\to\file - simple notation
1777+ * \\?\c:\path\to\file - long notation
1778+ *
1779+ * UNC path examples:
1780+ * \\server\share - a UNC path in simple notation
1781+ * \\?\UNC\server\share - a UNC path in long notation
1782+ * \\.\some\device - a path to device.
1783+ */
1784+ private static boolean isUncOrDevicePath(byte[] p) {
1785+ if (isWindowsPlatform == null) {
1786+ PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() {
1787+ public Boolean run() {
1788+ String osname = System.getProperty("os.name");
1789+ return (osname != null &&
1790+ osname.toLowerCase().startsWith("win"));
1791+ }
1792+ };
1793+ isWindowsPlatform = AccessController.doPrivileged(a);
1794+ }
1795+
1796+ if (!isWindowsPlatform) {
1797+ /* no need for the check on platforms except windows */
1798+ return false;
1799+ }
1800+
1801+ /* normalize prefix of the path */
1802+ if (p[0] == '/') p[0] = '\\';
1803+ if (p[1] == '/') p[1] = '\\';
1804+ if (p[3] == '/') p[3] = '\\';
1805+
1806+
1807+ if ((p[0] == '\\') && (p[1] == '\\')) {
1808+ if ((p[2] == '?') && (p[3] == '\\')) {
1809+ // long path: whether unc or local
1810+ return ((p[4] == 'U' || p[4] == 'u') &&
1811+ (p[5] == 'N' || p[5] == 'n') &&
1812+ (p[6] == 'C' || p[6] == 'c'));
1813+ } else {
1814+ // device path or short unc notation
1815+ return true;
1816+ }
1817+ } else {
1818+ return false;
1819+ }
1820+ }
1821+}