• jdk中解析BMP图片的过程


    在com.sun.imageio.plugins.bmp包中的BMPImageReader类中


     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();
                iis.skipBytes(profileData - size);
                byte[] profile = new byte[profileSize];
                iis.readFully(profile, 0, profileSize);
                iis.reset();
    
                try {
                    if (metadata.colorSpace == PROFILE_LINKED)
                        colorSpace =
                            new ICC_ColorSpace(ICC_Profile.getInstance(new String(profile)));
                    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 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
            readHeader();
    
            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
                        RuntimeException(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
                        RuntimeException(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
                        RuntimeException(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
                        RuntimeException(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;
        }

    当然这里还有对gif,jpg,bmp等常用图片的解析,有兴趣的可以去看下。



  • 相关阅读:
    深入了解Go Playground
    计算机程序设计艺术学习笔记1
    Docker 和一个正常的虚拟机有何区别?
    现代计算机架构常见时延(摘自计算机系统结构--量化研究方法)
    内核开发时应该注意的点
    gem5线程相关的类—SimpleThread类,ThreadState类(src/cpu/thread_state.*)
    GEM5中模拟的系统调用(部分没实现)
    字典树(trie)
    UML类图几种关系的总结
    C,C++宏中#与##的讲解
  • 原文地址:https://www.cnblogs.com/secbook/p/2655142.html
Copyright © 2020-2023  润新知