/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java
Java | 1860 lines | 1411 code | 267 blank | 182 comment | 329 complexity | b07fd32ab68a27336885f1069982232a MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-3.0
Large files files are truncated, but you can click here to view the full file
- /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
- package com.sun.imageio.plugins.bmp;
- import java.awt.Point;
- import java.awt.Rectangle;
- import java.awt.Transparency;
- import java.awt.color.ColorSpace;
- import java.awt.color.ICC_ColorSpace;
- import java.awt.color.ICC_Profile;
- import java.awt.image.BufferedImage;
- import java.awt.image.ColorModel;
- import java.awt.image.ComponentColorModel;
- import java.awt.image.ComponentSampleModel;
- import java.awt.image.DataBuffer;
- import java.awt.image.DataBufferByte;
- import java.awt.image.DataBufferInt;
- import java.awt.image.DataBufferUShort;
- import java.awt.image.DirectColorModel;
- import java.awt.image.IndexColorModel;
- import java.awt.image.MultiPixelPackedSampleModel;
- import java.awt.image.PixelInterleavedSampleModel;
- import java.awt.image.Raster;
- import java.awt.image.SampleModel;
- import java.awt.image.SinglePixelPackedSampleModel;
- import java.awt.image.WritableRaster;
- import javax.imageio.IIOException;
- import javax.imageio.ImageIO;
- import javax.imageio.ImageReader;
- import javax.imageio.ImageReadParam;
- import javax.imageio.ImageTypeSpecifier;
- import javax.imageio.metadata.IIOMetadata;
- import javax.imageio.spi.ImageReaderSpi;
- import javax.imageio.stream.ImageInputStream;
- import javax.imageio.event.IIOReadProgressListener;
- import javax.imageio.event.IIOReadUpdateListener;
- import javax.imageio.event.IIOReadWarningListener;
- import java.io.*;
- import java.nio.*;
- import java.security.AccessController;
- import java.security.PrivilegedAction;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.StringTokenizer;
- import com.sun.imageio.plugins.common.ImageUtil;
- import com.sun.imageio.plugins.common.I18N;
- /** This class is the Java Image IO plugin reader for BMP images.
- * It may subsample the image, clip the image, select sub-bands,
- * and shift the decoded image origin if the proper decoding parameter
- * are set in the provided <code>ImageReadParam</code>.
- *
- * This class supports Microsoft Windows Bitmap Version 3-5,
- * as well as OS/2 Bitmap Version 2.x (for single-image BMP file).
- */
- public class BMPImageReader extends ImageReader implements BMPConstants {
- // BMP Image types
- private static final int VERSION_2_1_BIT = 0;
- private static final int VERSION_2_4_BIT = 1;
- private static final int VERSION_2_8_BIT = 2;
- private static final int VERSION_2_24_BIT = 3;
- private static final int VERSION_3_1_BIT = 4;
- private static final int VERSION_3_4_BIT = 5;
- private static final int VERSION_3_8_BIT = 6;
- private static final int VERSION_3_24_BIT = 7;
- private static final int VERSION_3_NT_16_BIT = 8;
- private static final int VERSION_3_NT_32_BIT = 9;
- private static final int VERSION_4_1_BIT = 10;
- private static final int VERSION_4_4_BIT = 11;
- private static final int VERSION_4_8_BIT = 12;
- private static final int VERSION_4_16_BIT = 13;
- private static final int VERSION_4_24_BIT = 14;
- private static final int VERSION_4_32_BIT = 15;
- private static final int VERSION_3_XP_EMBEDDED = 16;
- private static final int VERSION_4_XP_EMBEDDED = 17;
- private static final int VERSION_5_XP_EMBEDDED = 18;
- // BMP variables
- private long bitmapFileSize;
- private long bitmapOffset;
- private long compression;
- private long imageSize;
- private byte palette[];
- private int imageType;
- private int numBands;
- private boolean isBottomUp;
- private int bitsPerPixel;
- private int redMask, greenMask, blueMask, alphaMask;
- private SampleModel sampleModel, originalSampleModel;
- private ColorModel colorModel, originalColorModel;
- /** The input stream where reads from */
- private ImageInputStream iis = null;
- /** Indicates whether the header is read. */
- private boolean gotHeader = false;
- /** The original image width. */
- private int width;
- /** The original image height. */
- private int height;
- /** The destination region. */
- private Rectangle destinationRegion;
- /** The source region. */
- private Rectangle sourceRegion;
- /** The metadata from the stream. */
- private BMPMetadata metadata;
- /** The destination image. */
- private BufferedImage bi;
- /** Indicates whether subsampled, subregion is required, and offset is
- * defined
- */
- private boolean noTransform = true;
- /** Indicates whether subband is selected. */
- private boolean seleBand = false;
- /** The scaling factors. */
- private int scaleX, scaleY;
- /** source and destination bands. */
- private int[] sourceBands, destBands;
- /** Constructs <code>BMPImageReader</code> from the provided
- * <code>ImageReaderSpi</code>.
- */
- public BMPImageReader(ImageReaderSpi originator) {
- super(originator);
- }
- /** Overrides the method defined in the superclass. */
- public void setInput(Object input,
- boolean seekForwardOnly,
- boolean ignoreMetadata) {
- super.setInput(input, seekForwardOnly, ignoreMetadata);
- iis = (ImageInputStream) input; // Always works
- if(iis != null)
- iis.setByteOrder(ByteOrder.LITTLE_ENDIAN);
- resetHeaderInfo();
- }
- /** Overrides the method defined in the superclass. */
- public int getNumImages(boolean allowSearch) throws IOException {
- if (iis == null) {
- throw new IllegalStateException(I18N.getString("GetNumImages0"));
- }
- if (seekForwardOnly && allowSearch) {
- throw new IllegalStateException(I18N.getString("GetNumImages1"));
- }
- return 1;
- }
- @Override
- public int getWidth(int imageIndex) throws IOException {
- checkIndex(imageIndex);
- try {
- readHeader();
- } catch (IllegalArgumentException e) {
- throw new IIOException(I18N.getString("BMPImageReader6"), e);
- }
- return width;
- }
- public int getHeight(int imageIndex) throws IOException {
- checkIndex(imageIndex);
- try {
- readHeader();
- } catch (IllegalArgumentException e) {
- throw new IIOException(I18N.getString("BMPImageReader6"), e);
- }
- return height;
- }
- private void checkIndex(int imageIndex) {
- if (imageIndex != 0) {
- throw new IndexOutOfBoundsException(I18N.getString("BMPImageReader0"));
- }
- }
- /**
- * Process the image header.
- *
- * @exception IllegalStateException if source stream is not set.
- *
- * @exception IOException if image stream is corrupted.
- *
- * @exception IllegalArgumentException if the image stream does not contain
- * a BMP image, or if a sample model instance to describe the
- * image can not be created.
- */
- protected void readHeader() throws IOException, IllegalArgumentException {
- if (gotHeader)
- return;
- if (iis == null) {
- throw new IllegalStateException("Input source not set!");
- }
- int profileData = 0, profileSize = 0;
- this.metadata = new BMPMetadata();
- iis.mark();
- // read and check the magic marker
- byte[] marker = new byte[2];
- iis.read(marker);
- if (marker[0] != 0x42 || marker[1] != 0x4d)
- throw new IllegalArgumentException(I18N.getString("BMPImageReader1"));
- // Read file size
- bitmapFileSize = iis.readUnsignedInt();
- // skip the two reserved fields
- iis.skipBytes(4);
- // Offset to the bitmap from the beginning
- bitmapOffset = iis.readUnsignedInt();
- // End File Header
- // Start BitmapCoreHeader
- long size = iis.readUnsignedInt();
- if (size == 12) {
- width = iis.readShort();
- height = iis.readShort();
- } else {
- width = iis.readInt();
- height = iis.readInt();
- }
- metadata.width = width;
- metadata.height = height;
- int planes = iis.readUnsignedShort();
- bitsPerPixel = iis.readUnsignedShort();
- //metadata.colorPlane = planes;
- metadata.bitsPerPixel = (short)bitsPerPixel;
- // As BMP always has 3 rgb bands, except for Version 5,
- // which is bgra
- numBands = 3;
- if (size == 12) {
- // Windows 2.x and OS/2 1.x
- metadata.bmpVersion = VERSION_2;
- // Classify the image type
- if (bitsPerPixel == 1) {
- imageType = VERSION_2_1_BIT;
- } else if (bitsPerPixel == 4) {
- imageType = VERSION_2_4_BIT;
- } else if (bitsPerPixel == 8) {
- imageType = VERSION_2_8_BIT;
- } else if (bitsPerPixel == 24) {
- imageType = VERSION_2_24_BIT;
- }
- // Read in the palette
- int numberOfEntries = (int)((bitmapOffset - 14 - size) / 3);
- int sizeOfPalette = numberOfEntries*3;
- palette = new byte[sizeOfPalette];
- iis.readFully(palette, 0, sizeOfPalette);
- metadata.palette = palette;
- metadata.paletteSize = numberOfEntries;
- } else {
- compression = iis.readUnsignedInt();
- imageSize = iis.readUnsignedInt();
- long xPelsPerMeter = iis.readInt();
- long yPelsPerMeter = iis.readInt();
- long colorsUsed = iis.readUnsignedInt();
- long colorsImportant = iis.readUnsignedInt();
- metadata.compression = (int)compression;
- metadata.xPixelsPerMeter = (int)xPelsPerMeter;
- metadata.yPixelsPerMeter = (int)yPelsPerMeter;
- metadata.colorsUsed = (int)colorsUsed;
- metadata.colorsImportant = (int)colorsImportant;
- if (size == 40) {
- // Windows 3.x and Windows NT
- switch((int)compression) {
- case BI_JPEG:
- case BI_PNG:
- metadata.bmpVersion = VERSION_3;
- imageType = VERSION_3_XP_EMBEDDED;
- break;
- case BI_RGB: // No compression
- case BI_RLE8: // 8-bit RLE compression
- case BI_RLE4: // 4-bit RLE compression
- // Read in the palette
- if (bitmapOffset < (size + 14)) {
- throw new IIOException(I18N.getString("BMPImageReader7"));
- }
- int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
- int sizeOfPalette = numberOfEntries * 4;
- palette = new byte[sizeOfPalette];
- iis.readFully(palette, 0, sizeOfPalette);
- metadata.palette = palette;
- metadata.paletteSize = numberOfEntries;
- if (bitsPerPixel == 1) {
- imageType = VERSION_3_1_BIT;
- } else if (bitsPerPixel == 4) {
- imageType = VERSION_3_4_BIT;
- } else if (bitsPerPixel == 8) {
- imageType = VERSION_3_8_BIT;
- } else if (bitsPerPixel == 24) {
- imageType = VERSION_3_24_BIT;
- } else if (bitsPerPixel == 16) {
- imageType = VERSION_3_NT_16_BIT;
- redMask = 0x7C00;
- greenMask = 0x3E0;
- blueMask = (1 << 5) - 1;// 0x1F;
- metadata.redMask = redMask;
- metadata.greenMask = greenMask;
- metadata.blueMask = blueMask;
- } else if (bitsPerPixel == 32) {
- imageType = VERSION_3_NT_32_BIT;
- redMask = 0x00FF0000;
- greenMask = 0x0000FF00;
- blueMask = 0x000000FF;
- metadata.redMask = redMask;
- metadata.greenMask = greenMask;
- metadata.blueMask = blueMask;
- }
- metadata.bmpVersion = VERSION_3;
- break;
- case BI_BITFIELDS:
- if (bitsPerPixel == 16) {
- imageType = VERSION_3_NT_16_BIT;
- } else if (bitsPerPixel == 32) {
- imageType = VERSION_3_NT_32_BIT;
- }
- // BitsField encoding
- redMask = (int)iis.readUnsignedInt();
- greenMask = (int)iis.readUnsignedInt();
- blueMask = (int)iis.readUnsignedInt();
- metadata.redMask = redMask;
- metadata.greenMask = greenMask;
- metadata.blueMask = blueMask;
- if (colorsUsed != 0) {
- // there is a palette
- sizeOfPalette = (int)colorsUsed*4;
- palette = new byte[sizeOfPalette];
- iis.readFully(palette, 0, sizeOfPalette);
- metadata.palette = palette;
- metadata.paletteSize = (int)colorsUsed;
- }
- metadata.bmpVersion = VERSION_3_NT;
- break;
- default:
- throw new
- IIOException(I18N.getString("BMPImageReader2"));
- }
- } else if (size == 108 || size == 124) {
- // Windows 4.x BMP
- if (size == 108)
- metadata.bmpVersion = VERSION_4;
- else if (size == 124)
- metadata.bmpVersion = VERSION_5;
- // rgb masks, valid only if comp is BI_BITFIELDS
- redMask = (int)iis.readUnsignedInt();
- greenMask = (int)iis.readUnsignedInt();
- blueMask = (int)iis.readUnsignedInt();
- // Only supported for 32bpp BI_RGB argb
- alphaMask = (int)iis.readUnsignedInt();
- long csType = iis.readUnsignedInt();
- int redX = iis.readInt();
- int redY = iis.readInt();
- int redZ = iis.readInt();
- int greenX = iis.readInt();
- int greenY = iis.readInt();
- int greenZ = iis.readInt();
- int blueX = iis.readInt();
- int blueY = iis.readInt();
- int blueZ = iis.readInt();
- long gammaRed = iis.readUnsignedInt();
- long gammaGreen = iis.readUnsignedInt();
- long gammaBlue = iis.readUnsignedInt();
- if (size == 124) {
- metadata.intent = iis.readInt();
- profileData = iis.readInt();
- profileSize = iis.readInt();
- iis.skipBytes(4);
- }
- metadata.colorSpace = (int)csType;
- if (csType == LCS_CALIBRATED_RGB) {
- // All the new fields are valid only for this case
- metadata.redX = redX;
- metadata.redY = redY;
- metadata.redZ = redZ;
- metadata.greenX = greenX;
- metadata.greenY = greenY;
- metadata.greenZ = greenZ;
- metadata.blueX = blueX;
- metadata.blueY = blueY;
- metadata.blueZ = blueZ;
- metadata.gammaRed = (int)gammaRed;
- metadata.gammaGreen = (int)gammaGreen;
- metadata.gammaBlue = (int)gammaBlue;
- }
- // Read in the palette
- int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
- int sizeOfPalette = numberOfEntries*4;
- palette = new byte[sizeOfPalette];
- iis.readFully(palette, 0, sizeOfPalette);
- metadata.palette = palette;
- metadata.paletteSize = numberOfEntries;
- switch ((int)compression) {
- case BI_JPEG:
- case BI_PNG:
- if (size == 108) {
- imageType = VERSION_4_XP_EMBEDDED;
- } else if (size == 124) {
- imageType = VERSION_5_XP_EMBEDDED;
- }
- break;
- default:
- if (bitsPerPixel == 1) {
- imageType = VERSION_4_1_BIT;
- } else if (bitsPerPixel == 4) {
- imageType = VERSION_4_4_BIT;
- } else if (bitsPerPixel == 8) {
- imageType = VERSION_4_8_BIT;
- } else if (bitsPerPixel == 16) {
- imageType = VERSION_4_16_BIT;
- if ((int)compression == BI_RGB) {
- redMask = 0x7C00;
- greenMask = 0x3E0;
- blueMask = 0x1F;
- }
- } else if (bitsPerPixel == 24) {
- imageType = VERSION_4_24_BIT;
- } else if (bitsPerPixel == 32) {
- imageType = VERSION_4_32_BIT;
- if ((int)compression == BI_RGB) {
- redMask = 0x00FF0000;
- greenMask = 0x0000FF00;
- blueMask = 0x000000FF;
- }
- }
- metadata.redMask = redMask;
- metadata.greenMask = greenMask;
- metadata.blueMask = blueMask;
- metadata.alphaMask = alphaMask;
- }
- } else {
- throw new
- IIOException(I18N.getString("BMPImageReader3"));
- }
- }
- if (height > 0) {
- // bottom up image
- isBottomUp = true;
- } else {
- // top down image
- isBottomUp = false;
- height = Math.abs(height);
- }
- // Reset Image Layout so there's only one tile.
- //Define the color space
- ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
- if (metadata.colorSpace == PROFILE_LINKED ||
- metadata.colorSpace == PROFILE_EMBEDDED) {
- iis.mark();
- iis.skipBytes(profileData - size);
- byte[] profile = new byte[profileSize];
- iis.readFully(profile, 0, profileSize);
- iis.reset();
- try {
- if (metadata.colorSpace == PROFILE_LINKED &&
- isLinkedProfileAllowed() &&
- !isUncOrDevicePath(profile))
- {
- String path = new String(profile, "windows-1252");
- colorSpace =
- new ICC_ColorSpace(ICC_Profile.getInstance(path));
- } else {
- colorSpace =
- new ICC_ColorSpace(ICC_Profile.getInstance(profile));
- }
- } catch (Exception e) {
- colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
- }
- }
- if (bitsPerPixel == 0 ||
- compression == BI_JPEG || compression == BI_PNG )
- {
- // the colorModel and sampleModel will be initialzed
- // by the reader of embedded image
- colorModel = null;
- sampleModel = null;
- } else if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) {
- // When number of bitsPerPixel is <= 8, we use IndexColorModel.
- numBands = 1;
- if (bitsPerPixel == 8) {
- int[] bandOffsets = new int[numBands];
- for (int i = 0; i < numBands; i++) {
- bandOffsets[i] = numBands -1 -i;
- }
- sampleModel =
- new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
- width, height,
- numBands,
- numBands * width,
- bandOffsets);
- } else {
- // 1 and 4 bit pixels can be stored in a packed format.
- sampleModel =
- new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
- width, height,
- bitsPerPixel);
- }
- // Create IndexColorModel from the palette.
- byte r[], g[], b[];
- if (imageType == VERSION_2_1_BIT ||
- imageType == VERSION_2_4_BIT ||
- imageType == VERSION_2_8_BIT) {
- size = palette.length/3;
- if (size > 256) {
- size = 256;
- }
- int off;
- r = new byte[(int)size];
- g = new byte[(int)size];
- b = new byte[(int)size];
- for (int i=0; i<(int)size; i++) {
- off = 3 * i;
- b[i] = palette[off];
- g[i] = palette[off+1];
- r[i] = palette[off+2];
- }
- } else {
- size = palette.length/4;
- if (size > 256) {
- size = 256;
- }
- int off;
- r = new byte[(int)size];
- g = new byte[(int)size];
- b = new byte[(int)size];
- for (int i=0; i<size; i++) {
- off = 4 * i;
- b[i] = palette[off];
- g[i] = palette[off+1];
- r[i] = palette[off+2];
- }
- }
- if (ImageUtil.isIndicesForGrayscale(r, g, b))
- colorModel =
- ImageUtil.createColorModel(null, sampleModel);
- else
- colorModel = new IndexColorModel(bitsPerPixel, (int)size, r, g, b);
- } else if (bitsPerPixel == 16) {
- numBands = 3;
- sampleModel =
- new SinglePixelPackedSampleModel(DataBuffer.TYPE_USHORT,
- width, height,
- new int[] {redMask, greenMask, blueMask});
- colorModel =
- new DirectColorModel(colorSpace,
- 16, redMask, greenMask, blueMask, 0,
- false, DataBuffer.TYPE_USHORT);
- } else if (bitsPerPixel == 32) {
- numBands = alphaMask == 0 ? 3 : 4;
- // The number of bands in the SampleModel is determined by
- // the length of the mask array passed in.
- int[] bitMasks = numBands == 3 ?
- new int[] {redMask, greenMask, blueMask} :
- new int[] {redMask, greenMask, blueMask, alphaMask};
- sampleModel =
- new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT,
- width, height,
- bitMasks);
- colorModel =
- new DirectColorModel(colorSpace,
- 32, redMask, greenMask, blueMask, alphaMask,
- false, DataBuffer.TYPE_INT);
- } else {
- numBands = 3;
- // Create SampleModel
- int[] bandOffsets = new int[numBands];
- for (int i = 0; i < numBands; i++) {
- bandOffsets[i] = numBands -1 -i;
- }
- sampleModel =
- new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
- width, height,
- numBands,
- numBands * width,
- bandOffsets);
- colorModel =
- ImageUtil.createColorModel(colorSpace, sampleModel);
- }
- originalSampleModel = sampleModel;
- originalColorModel = colorModel;
- // Reset to the start of bitmap; then jump to the
- //start of image data
- iis.reset();
- iis.skipBytes(bitmapOffset);
- gotHeader = true;
- }
- public Iterator getImageTypes(int imageIndex)
- throws IOException {
- checkIndex(imageIndex);
- try {
- readHeader();
- } catch (IllegalArgumentException e) {
- throw new IIOException(I18N.getString("BMPImageReader6"), e);
- }
- ArrayList list = new ArrayList(1);
- list.add(new ImageTypeSpecifier(originalColorModel,
- originalSampleModel));
- return list.iterator();
- }
- public ImageReadParam getDefaultReadParam() {
- return new ImageReadParam();
- }
- public IIOMetadata getImageMetadata(int imageIndex)
- throws IOException {
- checkIndex(imageIndex);
- if (metadata == null) {
- try {
- readHeader();
- } catch (IllegalArgumentException e) {
- throw new IIOException(I18N.getString("BMPImageReader6"), e);
- }
- }
- return metadata;
- }
- public IIOMetadata getStreamMetadata() throws IOException {
- return null;
- }
- public boolean isRandomAccessEasy(int imageIndex) throws IOException {
- checkIndex(imageIndex);
- try {
- readHeader();
- } catch (IllegalArgumentException e) {
- throw new IIOException(I18N.getString("BMPImageReader6"), e);
- }
- return metadata.compression == BI_RGB;
- }
- public BufferedImage read(int imageIndex, ImageReadParam param)
- throws IOException {
- if (iis == null) {
- throw new IllegalStateException(I18N.getString("BMPImageReader5"));
- }
- checkIndex(imageIndex);
- clearAbortRequest();
- processImageStarted(imageIndex);
- if (param == null)
- param = getDefaultReadParam();
- //read header
- try {
- readHeader();
- } catch (IllegalArgumentException e) {
- throw new IIOException(I18N.getString("BMPImageReader6"), e);
- }
- sourceRegion = new Rectangle(0, 0, 0, 0);
- destinationRegion = new Rectangle(0, 0, 0, 0);
- computeRegions(param, this.width, this.height,
- param.getDestination(),
- sourceRegion,
- destinationRegion);
- scaleX = param.getSourceXSubsampling();
- scaleY = param.getSourceYSubsampling();
- // If the destination band is set used it
- sourceBands = param.getSourceBands();
- destBands = param.getDestinationBands();
- seleBand = (sourceBands != null) && (destBands != null);
- noTransform =
- destinationRegion.equals(new Rectangle(0, 0, width, height)) ||
- seleBand;
- if (!seleBand) {
- sourceBands = new int[numBands];
- destBands = new int[numBands];
- for (int i = 0; i < numBands; i++)
- destBands[i] = sourceBands[i] = i;
- }
- // If the destination is provided, then use it. Otherwise, create new one
- bi = param.getDestination();
- // Get the image data.
- WritableRaster raster = null;
- if (bi == null) {
- if (sampleModel != null && colorModel != null) {
- sampleModel =
- sampleModel.createCompatibleSampleModel(destinationRegion.x +
- destinationRegion.width,
- destinationRegion.y +
- destinationRegion.height);
- if (seleBand)
- sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
- raster = Raster.createWritableRaster(sampleModel, new Point());
- bi = new BufferedImage(colorModel, raster, false, null);
- }
- } else {
- raster = bi.getWritableTile(0, 0);
- sampleModel = bi.getSampleModel();
- colorModel = bi.getColorModel();
- noTransform &= destinationRegion.equals(raster.getBounds());
- }
- byte bdata[] = null; // buffer for byte data
- short sdata[] = null; // buffer for short data
- int idata[] = null; // buffer for int data
- // the sampleModel can be null in case of embedded image
- if (sampleModel != null) {
- if (sampleModel.getDataType() == DataBuffer.TYPE_BYTE)
- bdata = (byte[])
- ((DataBufferByte)raster.getDataBuffer()).getData();
- else if (sampleModel.getDataType() == DataBuffer.TYPE_USHORT)
- sdata = (short[])
- ((DataBufferUShort)raster.getDataBuffer()).getData();
- else if (sampleModel.getDataType() == DataBuffer.TYPE_INT)
- idata = (int[])
- ((DataBufferInt)raster.getDataBuffer()).getData();
- }
- // There should only be one tile.
- switch(imageType) {
- case VERSION_2_1_BIT:
- // no compression
- read1Bit(bdata);
- break;
- case VERSION_2_4_BIT:
- // no compression
- read4Bit(bdata);
- break;
- case VERSION_2_8_BIT:
- // no compression
- read8Bit(bdata);
- break;
- case VERSION_2_24_BIT:
- // no compression
- read24Bit(bdata);
- break;
- case VERSION_3_1_BIT:
- // 1-bit images cannot be compressed.
- read1Bit(bdata);
- break;
- case VERSION_3_4_BIT:
- switch((int)compression) {
- case BI_RGB:
- read4Bit(bdata);
- break;
- case BI_RLE4:
- readRLE4(bdata);
- break;
- default:
- throw new
- IIOException(I18N.getString("BMPImageReader1"));
- }
- break;
- case VERSION_3_8_BIT:
- switch((int)compression) {
- case BI_RGB:
- read8Bit(bdata);
- break;
- case BI_RLE8:
- readRLE8(bdata);
- break;
- default:
- throw new
- IIOException(I18N.getString("BMPImageReader1"));
- }
- break;
- case VERSION_3_24_BIT:
- // 24-bit images are not compressed
- read24Bit(bdata);
- break;
- case VERSION_3_NT_16_BIT:
- read16Bit(sdata);
- break;
- case VERSION_3_NT_32_BIT:
- read32Bit(idata);
- break;
- case VERSION_3_XP_EMBEDDED:
- case VERSION_4_XP_EMBEDDED:
- case VERSION_5_XP_EMBEDDED:
- bi = readEmbedded((int)compression, bi, param);
- break;
- case VERSION_4_1_BIT:
- read1Bit(bdata);
- break;
- case VERSION_4_4_BIT:
- switch((int)compression) {
- case BI_RGB:
- read4Bit(bdata);
- break;
- case BI_RLE4:
- readRLE4(bdata);
- break;
- default:
- throw new
- IIOException(I18N.getString("BMPImageReader1"));
- }
- case VERSION_4_8_BIT:
- switch((int)compression) {
- case BI_RGB:
- read8Bit(bdata);
- break;
- case BI_RLE8:
- readRLE8(bdata);
- break;
- default:
- throw new
- IIOException(I18N.getString("BMPImageReader1"));
- }
- break;
- case VERSION_4_16_BIT:
- read16Bit(sdata);
- break;
- case VERSION_4_24_BIT:
- read24Bit(bdata);
- break;
- case VERSION_4_32_BIT:
- read32Bit(idata);
- break;
- }
- if (abortRequested())
- processReadAborted();
- else
- processImageComplete();
- return bi;
- }
- public boolean canReadRaster() {
- return true;
- }
- public Raster readRaster(int imageIndex,
- ImageReadParam param) throws IOException {
- BufferedImage bi = read(imageIndex, param);
- return bi.getData();
- }
- private void resetHeaderInfo() {
- gotHeader = false;
- bi = null;
- sampleModel = originalSampleModel = null;
- colorModel = originalColorModel = null;
- }
- public void reset() {
- super.reset();
- iis = null;
- resetHeaderInfo();
- }
- // Deal with 1 Bit images using IndexColorModels
- private void read1Bit(byte[] bdata) throws IOException {
- int bytesPerScanline = (width + 7) / 8;
- int padding = bytesPerScanline % 4;
- if (padding != 0) {
- padding = 4 - padding;
- }
- int lineLength = bytesPerScanline + padding;
- if (noTransform) {
- int j = isBottomUp ? (height -1)*bytesPerScanline : 0;
- for (int i=0; i<height; i++) {
- if (abortRequested()) {
- break;
- }
- iis.readFully(bdata, j, bytesPerScanline);
- iis.skipBytes(padding);
- j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
- processImageUpdate(bi, 0, i,
- destinationRegion.width, 1, 1, 1,
- new int[]{0});
- processImageProgress(100.0F * i/destinationRegion.height);
- }
- } else {
- byte[] buf = new byte[lineLength];
- int lineStride =
- ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
- if (isBottomUp) {
- int lastLine =
- sourceRegion.y + (destinationRegion.height - 1) * scaleY;
- iis.skipBytes(lineLength * (height - 1 - lastLine));
- } else
- iis.skipBytes(lineLength * sourceRegion.y);
- int skipLength = lineLength * (scaleY - 1);
- // cache the values to avoid duplicated computation
- int[] srcOff = new int[destinationRegion.width];
- int[] destOff = new int[destinationRegion.width];
- int[] srcPos = new int[destinationRegion.width];
- int[] destPos = new int[destinationRegion.width];
- for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
- i < destinationRegion.x + destinationRegion.width;
- i++, j++, x += scaleX) {
- srcPos[j] = x >> 3;
- srcOff[j] = 7 - (x & 7);
- destPos[j] = i >> 3;
- destOff[j] = 7 - (i & 7);
- }
- int k = destinationRegion.y * lineStride;
- if (isBottomUp)
- k += (destinationRegion.height - 1) * lineStride;
- for (int j = 0, y = sourceRegion.y;
- j < destinationRegion.height; j++, y+=scaleY) {
- if (abortRequested())
- break;
- iis.read(buf, 0, lineLength);
- for (int i = 0; i < destinationRegion.width; i++) {
- //get the bit and assign to the data buffer of the raster
- int v = (buf[srcPos[i]] >> srcOff[i]) & 1;
- bdata[k + destPos[i]] |= v << destOff[i];
- }
- k += isBottomUp ? -lineStride : lineStride;
- iis.skipBytes(skipLength);
- processImageUpdate(bi, 0, j,
- destinationRegion.width, 1, 1, 1,
- new int[]{0});
- processImageProgress(100.0F*j/destinationRegion.height);
- }
- }
- }
- // Method to read a 4 bit BMP image data
- private void read4Bit(byte[] bdata) throws IOException {
- int bytesPerScanline = (width + 1) / 2;
- // Padding bytes at the end of each scanline
- int padding = bytesPerScanline % 4;
- if (padding != 0)
- padding = 4 - padding;
- int lineLength = bytesPerScanline + padding;
- if (noTransform) {
- int j = isBottomUp ? (height -1) * bytesPerScanline : 0;
- for (int i=0; i<height; i++) {
- if (abortRequested()) {
- break;
- }
- iis.readFully(bdata, j, bytesPerScanline);
- iis.skipBytes(padding);
- j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
- processImageUpdate(bi, 0, i,
- destinationRegion.width, 1, 1, 1,
- new int[]{0});
- processImageProgress(100.0F * i/destinationRegion.height);
- }
- } else {
- byte[] buf = new byte[lineLength];
- int lineStride =
- ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
- if (isBottomUp) {
- int lastLine =
- sourceRegion.y + (destinationRegion.height - 1) * scaleY;
- iis.skipBytes(lineLength * (height - 1 - lastLine));
- } else
- iis.skipBytes(lineLength * sourceRegion.y);
- int skipLength = lineLength * (scaleY - 1);
- // cache the values to avoid duplicated computation
- int[] srcOff = new int[destinationRegion.width];
- int[] destOff = new int[destinationRegion.width];
- int[] srcPos = new int[destinationRegion.width];
- int[] destPos = new int[destinationRegion.width];
- for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
- i < destinationRegion.x + destinationRegion.width;
- i++, j++, x += scaleX) {
- srcPos[j] = x >> 1;
- srcOff[j] = (1 - (x & 1)) << 2;
- destPos[j] = i >> 1;
- destOff[j] = (1 - (i & 1)) << 2;
- }
- int k = destinationRegion.y * lineStride;
- if (isBottomUp)
- k += (destinationRegion.height - 1) * lineStride;
- for (int j = 0, y = sourceRegion.y;
- j < destinationRegion.height; j++, y+=scaleY) {
- if (abortRequested())
- break;
- iis.read(buf, 0, lineLength);
- for (int i = 0; i < destinationRegion.width; i++) {
- //get the bit and assign to the data buffer of the raster
- int v = (buf[srcPos[i]] >> srcOff[i]) & 0x0F;
- bdata[k + destPos[i]] |= v << destOff[i];
- }
- k += isBottomUp ? -lineStride : lineStride;
- iis.skipBytes(skipLength);
- processImageUpdate(bi, 0, j,
- destinationRegion.width, 1, 1, 1,
- new int[]{0});
- processImageProgress(100.0F*j/destinationRegion.height);
- }
- }
- }
- // Method to read 8 bit BMP image data
- private void read8Bit(byte[] bdata) throws IOException {
- // Padding bytes at the end of each scanline
- int padding = width % 4;
- if (padding != 0) {
- padding = 4 - padding;
- }
- int lineLength = width + padding;
- if (noTransform) {
- int j = isBottomUp ? (height -1) * width : 0;
- for (int i=0; i<height; i++) {
- if (abortRequested()) {
- break;
- }
- iis.readFully(bdata, j, width);
- iis.skipBytes(padding);
- j += isBottomUp ? -width : width;
- processImageUpdate(bi, 0, i,
- destinationRegion.width, 1, 1, 1,
- new int[]{0});
- processImageProgress(100.0F * i/destinationRegion.height);
- }
- } else {
- byte[] buf = new byte[lineLength];
- int lineStride =
- ((ComponentSampleModel)sampleModel).getScanlineStride();
- if (isBottomUp) {
- int lastLine =
- sourceRegion.y + (destinationRegion.height - 1) * scaleY;
- iis.skipBytes(lineLength * (height - 1 - lastLine));
- } else
- iis.skipBytes(lineLength * sourceRegion.y);
- int skipLength = lineLength * (scaleY - 1);
- int k = destinationRegion.y * lineStride;
- if (isBottomUp)
- k += (destinationRegion.height - 1) * lineStride;
- k += destinationRegion.x;
- for (int j = 0, y = sourceRegion.y;
- j < destinationRegion.height; j++, y+=scaleY) {
- if (abortRequested())
- break;
- iis.read(buf, 0, lineLength);
- for (int i = 0, m = sourceRegion.x;
- i < destinationRegion.width; i++, m += scaleX) {
- //get the bit and assign to the data buffer of the raster
- bdata[k + i] = buf[m];
- }
- k += isBottomUp ? -lineStride : lineStride;
- iis.skipBytes(skipLength);
- processImageUpdate(bi, 0, j,
- destinationRegion.width, 1, 1, 1,
- new int[]{0});
- processImageProgress(100.0F*j/destinationRegion.height);
- }
- }
- }
- // Method to read 24 bit BMP image data
- private void read24Bit(byte[] bdata) throws IOException {
- // Padding bytes at the end of each scanline
- // width * bitsPerPixel should be divisible by 32
- int padding = width * 3 % 4;
- if ( padding != 0)
- padding = 4 - padding;
- int lineStride = width * 3;
- int lineLength = lineStride + padding;
- if (noTransform) {
- int j = isBottomUp ? (height -1) * width * 3 : 0;
- for (int i=0; i<height; i++) {
- if (abortRequested()) {
- break;
- }
- iis.readFully(bdata, j, lineStride);
- iis.skipBytes(padding);
- j += isBottomUp ? -lineStride : lineStride;
- processImageUpdate(bi, 0, i,
- destinationRegion.width, 1, 1, 1,
- new int[]{0});
- processImageProgress(100.0F * i/destinationRegion.height);
- }
- } else {
- byte[] buf = new byte[lineLength];
- lineStride =
- ((ComponentSampleModel)sampleModel).getScanlineStride();
- if (isBottomUp) {
- int lastLine =
- sourceRegion.y + (destinationRegion.height - 1) * scaleY;
- iis.skipBytes(lineLength * (height - 1 - lastLine));
- } else
- iis.skipBytes(lineLength * sourceRegion.y);
- int skipLength = lineLength * (scaleY - 1);
- int k = destinationRegion.y * lineStride;
- if (isBottomUp)
- k += (destinationRegion.height - 1) * lineStride;
- k += destinationRegion.x * 3;
- for (int j = 0, y = sourceRegion.y;
- j < destinationRegion.height; j++, y+=scaleY) {
- if (abortRequested())
- break;
- iis.read(buf, 0, lineLength);
- for (int i = 0, m = 3 * sourceRegion.x;
- i < destinationRegion.width; i++, m += 3 * scaleX) {
- //get the bit and assign to the data buffer of the raster
- int n = 3 * i + k;
- for (int b = 0; b < destBands.length; b++)
- bdata[n + destBands[b]] = buf[m + sourceBands[b]];
- }
- k += isBottomUp ? -lineStride : lineStride;
- iis.skipBytes(skipLength);
- processImageUpdate(bi, 0, j,
- destinationRegion.width, 1, 1, 1,
- new int[]{0});
- processImageProgress(100.0F*j/destinationRegion.height);
- }
- }
- }
- private void read16Bit(short sdata[]) throws IOException {
- // Padding bytes at the end of each scanline
- // width * bitsPerPixel should be divisible by 32
- int padding = width * 2 % 4;
- if ( padding != 0)
- padding = 4 - padding;
- int lineLength = width + padding / 2;
- if (noTransform) {
- int j = isBottomUp ? (height -1) * width : 0;
- for (int i=0; i<height; i++) {
- if (abortRequested()) {
- break;
- }
- iis.readFully(sdata, j, width);
- iis.skipBytes(padding);
- j += isBottomUp ? -width : width;
- processImageUpdate(bi, 0, i,
- destinationRegion.width, 1, 1, 1,
- new int[]{0});
- processImageProgress(100.0F * i/destinationRegion.height);
- }
- } else {
- short[] buf = new short[lineLength];
- int lineStride =
- ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
- if (isBottomUp) {
- int lastLine =
- sourceRegion.y + (destinationRegion.height - 1) * scaleY;
- iis.skipBytes(lineLength * (height - 1 - lastLine) << 1);
- } else
- iis.skipBytes(lineLength * sourceRegion.y << 1);
- int skipLength = lineLength * (scaleY - 1) << 1;
- int k = destinationRegion.y * lineStride;
- if (isBottomUp)
- k += (destinationRegion.height - 1) * lineStride;
- k += destinationRegion.x;
- for (int j = 0, y = sourceRegion.y;
- j < destinationRegion.height; j++, y+=scaleY) {
- if (abortRequested())
- break;
- iis.readFully(buf, 0, lineLength);
- for (int i = 0, m = sourceRegion.x;
- i < destinationRegion.width; i++, m += scaleX) {
- //get the bit and assign to the data buffer of the raster
- sdata[k + i] = buf[m];
- }
- k += isBottomUp ? -lineStride : lineStride;
- iis.skipBytes(skipLength);
- processImageUpdate(bi, 0, j,
- destinationRegion.width, 1, 1, 1,
- new int[]{0});
- processImageProgress(100.0F*j/destinationRegion.height);
- }
- }
- }
- private void read32Bit(int idata[]) throws IOException {
- if (noTransform) {
- int j = isBottomUp ? (height -1) * width : 0;
- for (int i=0; i<height; i++) {
- if (abortRequested()) {
- break;
- }
- iis.readFully(idata, j, width);
- j += isBottomUp ? -width : width;
- processImageUpdate(bi, 0, i,
- destinationRegion.width, 1, 1, 1,
- new int[]{0});
- processImageProgress(100.0F * i/destinationRegion.height);
- }
- } else {
- int[] buf = new int[width];
- int lineStride =
- ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
- if (isBottomUp) {
- int lastLine =
- sourceRegion.y + (destinationRegion.height - 1) * scaleY;
- iis.skipBytes(width * (height - 1 - lastLine) << 2);
- } else
- iis.skipBytes(width * sourceRegion.y << 2);
- int skipLength = width * (scaleY - 1) << 2;
- int k = destinationRegion.y * lineStride;
- if (isBottomUp)
- k += (destinationRegion.height - 1) * lineStride;
- k += destinationRegion.x;
- for (int j = 0, y = sourceRegion.y;
- j < destinationRegion.height; j++, y+=scaleY) {
- if (abortRequested())
- break;
- iis.readFully(buf, 0, width);
- for (int i = …
Large files files are truncated, but you can click here to view the full file