1821 lines · 66.1 KB · Java
RawDownload
/* * Copyright (c) 2003, 2005, 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;    }     public int getWidth(int imageIndex) throws IOException {        checkIndex(imageIndex);        readHeader();        return width;    }     public int getHeight(int imageIndex) throws IOException {        checkIndex(imageIndex);        readHeader();        return height;    }     private void checkIndex(int imageIndex) {        if (imageIndex != 0) {            throw new IndexOutOfBoundsException(I18N.getString("BMPImageReader0"));        }    }     public void readHeader() throws IOException {        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                    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                        RuntimeException(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                    RuntimeException(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();

Lines 1–500 of 1821.