Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 533|回复: 0

使用Thumbnailator处理gif图片时遇到java.lang.ArrayIndexOutOfBoundsException: 4096异常处理

[复制链接]
  • TA的每日心情
    奋斗
    6 天前
  • 签到天数: 795 天

    [LV.10]以坛为家III

    2050

    主题

    2108

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    724084
    发表于 2021-6-2 00:02:46 | 显示全部楼层 |阅读模式

    环境

    1.7.0_80
    

    在使用Thumbnailator处理gif图片时,遇到问题:

    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4096
    	at com.sun.imageio.plugins.gif.GIFImageReader.read(GIFImageReader.java:958)
    	at net.coobird.thumbnailator.tasks.io.InputStreamImageSource.read(Unknown Source)
    	at net.coobird.thumbnailator.tasks.SourceSinkThumbnailTask.read(Unknown Source)
    	at net.coobird.thumbnailator.Thumbnailator.createThumbnail(Unknown Source)
    	at net.coobird.thumbnailator.Thumbnails$Builder.toOutputStream(Unknown Source)
    	at App.main(App.java:10)
    

    查找一些资料后了解到,gif是有不同类型的,JDK自带的图片处理库不支持部分类型的gif的处理,所以就报错了。参考:

    1. https://stackoverflow.com/questions/22259714/arrayindexoutofboundsexception-4096-while-reading-gif-file
    2. https://docs.oracle.com/javase/7/docs/api/javax/imageio/spi/IIORegistry.html

    我这里处理这个问题的方法比较投机取巧(见下面代码PatchedGIFImageReaderSpi):
    继承了原有的GIFImageReaderSpi得到一个新的ImageReaderSpi,然后在onRegistration时把jdk自带的GIFImageReaderSpi给移除掉了。


    App.java

    // <dependency>
    //    <groupId>net.coobird</groupId>
    //    <artifactId>thumbnailator</artifactId>
    //    <version>0.4.8</version>
    // </dependency>
    InputStream inputStream = null;
    FileOutputStream outputStream = null;
    try {
        inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("example.gif");
        outputStream = new FileOutputStream(new File("example_resize.gif"));
        Thumbnails.of(inputStream).scale(0.9).toOutputStream(outputStream);
        outputStream.flush();
    } finally {
        if (outputStream != null) {
            outputStream.close();
        }
        if (inputStream != null) {
            inputStream.close();
        }
    }
    

    PatchedGIFImageReaderSpi.java (META-INF/services/javax.imageio.spi.ImageReaderSpi)

    import com.sun.imageio.plugins.gif.GIFImageReaderSpi;
    import de.onyxbits.giftedmotion.PatchedGIFImageReader;
    
    import javax.imageio.ImageReader;
    import javax.imageio.spi.ImageReaderSpi;
    import javax.imageio.spi.ServiceRegistry;
    
    public class PatchedGIFImageReaderSpi extends GIFImageReaderSpi {
    
        @Override
        public ImageReader createReaderInstance(Object extension) {
            return new PatchedGIFImageReader(this);
        }
    
        @Override
        public void onRegistration(ServiceRegistry registry, Class<?> category) {
            // 移除jdk自带的GIFImageReaderSpi
            GIFImageReaderSpi gifImageReaderSpi = registry.getServiceProviderByClass(GIFImageReaderSpi.class);
            if (gifImageReaderSpi != null) {
                registry.deregisterServiceProvider(gifImageReaderSpi, (Class<ImageReaderSpi>) category);
            }
        }
    }
    

    PatchedGIFImageReader.java (PatchedGIFImageReader代码来自:https://pastebin.com/h58zjT8K)

    package de.onyxbits.giftedmotion;
    
    import java.awt.Point;
    import java.awt.Rectangle;
    import java.awt.image.BufferedImage;
    import java.awt.image.DataBuffer;
    import java.awt.image.WritableRaster;
    import java.io.EOFException;
    import java.io.IOException;
    import java.nio.ByteOrder;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Iterator;
    import java.util.List;
    
    import javax.imageio.IIOException;
    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 com.sun.imageio.plugins.common.ReaderUtil;
    import com.sun.imageio.plugins.gif.GIFImageMetadata;
    import com.sun.imageio.plugins.gif.GIFStreamMetadata;
    
    public class PatchedGIFImageReader extends ImageReader {
    
        public PatchedGIFImageReader(ImageReaderSpi originatingProvider) {
            super(originatingProvider);
        }
    
        // The current ImageInputStream source.
        ImageInputStream stream = null;
    
        // Per-stream settings
    
        // True if the file header including stream metadata has been read.
        boolean gotHeader = false;
    
        // Global metadata, read once per input setting.
        GIFStreamMetadata streamMetadata = null;
    
        // The current image index
        int currIndex = -1;
    
        // Metadata for image at 'currIndex', or null.
        GIFImageMetadata imageMetadata = null;
    
        // A List of Longs indicating the stream positions of the
        // start of the metadata for each image.  Entries are added
        // as needed.
        List imageStartPosition = new ArrayList();
    
        // Length of metadata for image at 'currIndex', valid only if
        // imageMetadata != null.
        int imageMetadataLength;
    
        // The number of images in the stream, if known, otherwise -1.
        int numImages = -1;
    
        // Variables used by the LZW decoding process
        byte[] block = new byte[255];
        int blockLength = 0;
        int bitPos = 0;
        int nextByte = 0;
        int initCodeSize;
        int clearCode;
        int eofCode;
    
        // 32-bit lookahead buffer
        int next32Bits = 0;
    
        // Try if the end of the data blocks has been found,
        // and we are simply draining the 32-bit buffer
        boolean lastBlockFound = false;
    
        // The image to be written.
        BufferedImage theImage = null;
    
        // The image's tile.
        WritableRaster theTile = null;
    
        // The image dimensions (from the stream).
        int width = -1, height = -1;
    
        // The pixel currently being decoded (in the stream's coordinates).
        int streamX = -1, streamY = -1;
    
        // The number of rows decoded
        int rowsDone = 0;
    
        // The current interlace pass, starting with 0.
        int interlacePass = 0;
    
        // End per-stream settings
    
        // Constants used to control interlacing.
        static final int[] interlaceIncrement = {8, 8, 4, 2, -1};
        static final int[] interlaceOffset = {0, 4, 2, 1, -1};
    
        // Take input from an ImageInputStream
        public void setInput(Object input,
                             boolean seekForwardOnly,
                             boolean ignoreMetadata) {
            super.setInput(input, seekForwardOnly, ignoreMetadata);
            if (input != null) {
                if (!(input instanceof ImageInputStream)) {
                    throw new IllegalArgumentException
                            ("input not an ImageInputStream!");
                }
                this.stream = (ImageInputStream) input;
            } else {
                this.stream = null;
            }
    
            // Clear all values based on the previous stream contents
            resetStreamSettings();
        }
    
        public int getNumImages(boolean allowSearch) throws IIOException {
            if (stream == null) {
                throw new IllegalStateException("Input not set!");
            }
            if (seekForwardOnly && allowSearch) {
                throw new IllegalStateException
                        ("seekForwardOnly and allowSearch can't both be true!");
            }
    
            if (numImages > 0) {
                return numImages;
            }
            if (allowSearch) {
                this.numImages = locateImage(Integer.MAX_VALUE) + 1;
            }
            return numImages;
        }
    
        // Throw an IndexOutOfBoundsException if index < minIndex,
        // and bump minIndex if required.
        private void checkIndex(int imageIndex) {
            if (imageIndex < minIndex) {
                throw new IndexOutOfBoundsException("imageIndex < minIndex!");
            }
            if (seekForwardOnly) {
                minIndex = imageIndex;
            }
        }
    
        public int getWidth(int imageIndex) throws IIOException {
            checkIndex(imageIndex);
    
            int index = locateImage(imageIndex);
            if (index != imageIndex) {
                throw new IndexOutOfBoundsException();
            }
            readMetadata();
            return imageMetadata.imageWidth;
        }
    
        public int getHeight(int imageIndex) throws IIOException {
            checkIndex(imageIndex);
    
            int index = locateImage(imageIndex);
            if (index != imageIndex) {
                throw new IndexOutOfBoundsException();
            }
            readMetadata();
            return imageMetadata.imageHeight;
        }
    
        public Iterator getImageTypes(int imageIndex) throws IIOException {
            checkIndex(imageIndex);
    
            int index = locateImage(imageIndex);
            if (index != imageIndex) {
                throw new IndexOutOfBoundsException();
            }
            readMetadata();
    
            List l = new ArrayList(1);
    
            byte[] colorTable;
            if (imageMetadata.localColorTable != null) {
                colorTable = imageMetadata.localColorTable;
            } else {
                colorTable = streamMetadata.globalColorTable;
            }
    
            // Normalize color table length to 2^1, 2^2, 2^4, or 2^8
            int length = colorTable.length / 3;
            int bits;
            if (length == 2) {
                bits = 1;
            } else if (length == 4) {
                bits = 2;
            } else if (length == 8 || length == 16) {
                // Bump from 3 to 4 bits
                bits = 4;
            } else {
                // Bump to 8 bits
                bits = 8;
            }
            int lutLength = 1 << bits;
            byte[] r = new byte[lutLength];
            byte[] g = new byte[lutLength];
            byte[] b = new byte[lutLength];
    
            // Entries from length + 1 to lutLength - 1 will be 0
            int rgbIndex = 0;
            for (int i = 0; i < length; i++) {
                r = colorTable[rgbIndex++];
                g = colorTable[rgbIndex++];
                b = colorTable[rgbIndex++];
            }
    
            byte[] a = null;
            if (imageMetadata.transparentColorFlag) {
                a = new byte[lutLength];
                Arrays.fill(a, (byte) 255);
    
                // Some files erroneously have a transparent color index
                // of 255 even though there are fewer than 256 colors.
                int idx = Math.min(imageMetadata.transparentColorIndex,
                        lutLength - 1);
                a[idx] = (byte) 0;
            }
    
            int[] bitsPerSample = new int[1];
            bitsPerSample[0] = bits;
            l.add(ImageTypeSpecifier.createIndexed(r, g, b, a, bits,
                    DataBuffer.TYPE_BYTE));
            return l.iterator();
        }
    
        public ImageReadParam getDefaultReadParam() {
            return new ImageReadParam();
        }
    
        public IIOMetadata getStreamMetadata() throws IIOException {
            readHeader();
            return streamMetadata;
        }
    
        public IIOMetadata getImageMetadata(int imageIndex) throws IIOException {
            checkIndex(imageIndex);
    
            int index = locateImage(imageIndex);
            if (index != imageIndex) {
                throw new IndexOutOfBoundsException("Bad image index!");
            }
            readMetadata();
            return imageMetadata;
        }
    
        // BEGIN LZW STUFF
    
        private void initNext32Bits() {
            next32Bits = block[0] & 0xff;
            next32Bits |= (block[1] & 0xff) << 8;
            next32Bits |= (block[2] & 0xff) << 16;
            next32Bits |= block[3] << 24;
            nextByte = 4;
        }
    
        // Load a block (1-255 bytes) at a time, and maintain
        // a 32-bit lookahead buffer that is filled from the left
        // and extracted from the right.
        //
        // When the last block is found, we continue to
        //
        private int getCode(int codeSize, int codeMask) throws IOException {
            if (bitPos + codeSize > 32) {
                return eofCode; // No more data available
            }
    
            int code = (next32Bits >> bitPos) & codeMask;
            bitPos += codeSize;
    
            // Shift in a byte of new data at a time
            while (bitPos >= 8 && !lastBlockFound) {
                next32Bits >>>= 8;
                bitPos -= 8;
    
                // Check if current block is out of bytes
                if (nextByte >= blockLength) {
                    // Get next block size
                    blockLength = stream.readUnsignedByte();
                    if (blockLength == 0) {
                        lastBlockFound = true;
                        return code;
                    } else {
                        int left = blockLength;
                        int off = 0;
                        while (left > 0) {
                            int nbytes = stream.read(block, off, left);
                            off += nbytes;
                            left -= nbytes;
                        }
                        nextByte = 0;
                    }
                }
    
                next32Bits |= block[nextByte++] << 24;
            }
    
            return code;
        }
    
        public void initializeStringTable(int[] prefix,
                                          byte[] suffix,
                                          byte[] initial,
                                          int[] length) {
            int numEntries = 1 << initCodeSize;
            for (int i = 0; i < numEntries; i++) {
                prefix = -1;
                suffix = (byte) i;
                initial = (byte) i;
                length = 1;
            }
    
            // Fill in the entire table for robustness against
            // out-of-sequence codes.
            for (int i = numEntries; i < 4096; i++) {
                prefix = -1;
                length = 1;
            }
    
            // tableIndex = numEntries + 2;
            // codeSize = initCodeSize + 1;
            // codeMask = (1 << codeSize) - 1;
        }
    
        Rectangle sourceRegion;
        int sourceXSubsampling;
        int sourceYSubsampling;
        int sourceMinProgressivePass;
        int sourceMaxProgressivePass;
    
        Point destinationOffset;
        Rectangle destinationRegion;
    
        // Used only if IIOReadUpdateListeners are present
        int updateMinY;
        int updateYStep;
    
        boolean decodeThisRow = true;
        int destY = 0;
    
        byte[] rowBuf;
    
        private void outputRow() {
            // Clip against ImageReadParam
            int width = Math.min(sourceRegion.width,
                    destinationRegion.width * sourceXSubsampling);
            int destX = destinationRegion.x;
    
            if (sourceXSubsampling == 1) {
                theTile.setDataElements(destX, destY, width, 1, rowBuf);
            } else {
                for (int x = 0; x < width; x += sourceXSubsampling, destX++) {
                    theTile.setSample(destX, destY, 0, rowBuf[x] & 0xff);
                }
            }
    
            // Update IIOReadUpdateListeners, if any
            if (updateListeners != null) {
                int[] bands = {0};
                // updateYStep will have been initialized if
                // updateListeners is non-null
                processImageUpdate(theImage,
                        destX, destY,
                        width, 1, 1, updateYStep,
                        bands);
            }
        }
    
        private void computeDecodeThisRow() {
            this.decodeThisRow =
                    (destY < destinationRegion.y + destinationRegion.height) &&
                            (streamY >= sourceRegion.y) &&
                            (streamY < sourceRegion.y + sourceRegion.height) &&
                            (((streamY - sourceRegion.y) % sourceYSubsampling) == 0);
        }
    
        private void outputPixels(byte[] string, int len) {
            if (interlacePass < sourceMinProgressivePass ||
                    interlacePass > sourceMaxProgressivePass) {
                return;
            }
    
            for (int i = 0; i < len; i++) {
                if (streamX >= sourceRegion.x) {
                    rowBuf[streamX - sourceRegion.x] = string;
                }
    
                // Process end-of-row
                ++streamX;
                if (streamX == width) {
                    // Update IIOReadProgressListeners
                    ++rowsDone;
                    processImageProgress(100.0F * rowsDone / height);
    
                    if (decodeThisRow) {
                        outputRow();
                    }
    
                    streamX = 0;
                    if (imageMetadata.interlaceFlag) {
                        streamY += interlaceIncrement[interlacePass];
                        if (streamY >= height) {
                            // Inform IIOReadUpdateListeners of end of pass
                            if (updateListeners != null) {
                                processPassComplete(theImage);
                            }
    
                            ++interlacePass;
                            if (interlacePass > sourceMaxProgressivePass) {
                                return;
                            }
                            streamY = interlaceOffset[interlacePass];
                            startPass(interlacePass);
                        }
                    } else {
                        ++streamY;
                    }
    
                    // Determine whether pixels from this row will
                    // be written to the destination
                    this.destY = destinationRegion.y +
                            (streamY - sourceRegion.y) / sourceYSubsampling;
                    computeDecodeThisRow();
                }
            }
        }
    
        // END LZW STUFF
    
        private void readHeader() throws IIOException {
            if (gotHeader) {
                return;
            }
            if (stream == null) {
                throw new IllegalStateException("Input not set!");
            }
    
            // Create an object to store the stream metadata
            this.streamMetadata = new GIFStreamMetadata();
    
            try {
                stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
    
                byte[] signature = new byte[6];
                stream.readFully(signature);
    
                StringBuffer version = new StringBuffer(3);
                version.append((char) signature[3]);
                version.append((char) signature[4]);
                version.append((char) signature[5]);
                streamMetadata.version = version.toString();
    
                streamMetadata.logicalScreenWidth = stream.readUnsignedShort();
                streamMetadata.logicalScreenHeight = stream.readUnsignedShort();
    
                int packedFields = stream.readUnsignedByte();
                boolean globalColorTableFlag = (packedFields & 0x80) != 0;
                streamMetadata.colorResolution = ((packedFields >> 4) & 0x7) + 1;
                streamMetadata.sortFlag = (packedFields & 0x8) != 0;
                int numGCTEntries = 1 << ((packedFields & 0x7) + 1);
    
                streamMetadata.backgroundColorIndex = stream.readUnsignedByte();
                streamMetadata.pixelAspectRatio = stream.readUnsignedByte();
    
                if (globalColorTableFlag) {
                    streamMetadata.globalColorTable = new byte[3 * numGCTEntries];
                    stream.readFully(streamMetadata.globalColorTable);
                } else {
                    streamMetadata.globalColorTable = null;
                }
    
                // Found position of metadata for image 0
                imageStartPosition.add(Long.valueOf(stream.getStreamPosition()));
            } catch (IOException e) {
                throw new IIOException("I/O error reading header!", e);
            }
    
            gotHeader = true;
        }
    
        private boolean skipImage() throws IIOException {
            // Stream must be at the beginning of an image descriptor
            // upon exit
    
            try {
                while (true) {
                    int blockType = stream.readUnsignedByte();
    
                    if (blockType == 0x2c) {
                        stream.skipBytes(8);
    
                        int packedFields = stream.readUnsignedByte();
                        if ((packedFields & 0x80) != 0) {
                            // Skip color table if any
                            int bits = (packedFields & 0x7) + 1;
                            stream.skipBytes(3 * (1 << bits));
                        }
    
                        stream.skipBytes(1);
    
                        int length = 0;
                        do {
                            length = stream.readUnsignedByte();
                            stream.skipBytes(length);
                        } while (length > 0);
    
                        return true;
                    } else if (blockType == 0x3b) {
                        return false;
                    } else if (blockType == 0x21) {
                        int label = stream.readUnsignedByte();
    
                        int length = 0;
                        do {
                            length = stream.readUnsignedByte();
                            stream.skipBytes(length);
                        } while (length > 0);
                    } else if (blockType == 0x0) {
                        // EOF
                        return false;
                    } else {
                        int length = 0;
                        do {
                            length = stream.readUnsignedByte();
                            stream.skipBytes(length);
                        } while (length > 0);
                    }
                }
            } catch (EOFException e) {
                return false;
            } catch (IOException e) {
                throw new IIOException("I/O error locating image!", e);
            }
        }
    
        private int locateImage(int imageIndex) throws IIOException {
            readHeader();
    
            try {
                // Find closest known index
                int index = Math.min(imageIndex, imageStartPosition.size() - 1);
    
                // Seek to that position
                Long l = (Long) imageStartPosition.get(index);
                stream.seek(l.longValue());
    
                // Skip images until at desired index or last image found
                while (index < imageIndex) {
                    if (!skipImage()) {
                        --index;
                        return index;
                    }
    
                    Long l1 = new Long(stream.getStreamPosition());
                    imageStartPosition.add(l1);
                    ++index;
                }
            } catch (IOException e) {
                throw new IIOException("Couldn't seek!", e);
            }
    
            if (currIndex != imageIndex) {
                imageMetadata = null;
            }
            currIndex = imageIndex;
            return imageIndex;
        }
    
        // Read blocks of 1-255 bytes, stop at a 0-length block
        private byte[] concatenateBlocks() throws IOException {
            byte[] data = new byte[0];
            while (true) {
                int length = stream.readUnsignedByte();
                if (length == 0) {
                    break;
                }
                byte[] newData = new byte[data.length + length];
                System.arraycopy(data, 0, newData, 0, data.length);
                stream.readFully(newData, data.length, length);
                data = newData;
            }
    
            return data;
        }
    
        // Stream must be positioned at start of metadata for 'currIndex'
        private void readMetadata() throws IIOException {
            if (stream == null) {
                throw new IllegalStateException("Input not set!");
            }
    
            try {
                // Create an object to store the image metadata
                this.imageMetadata = new GIFImageMetadata();
    
                long startPosition = stream.getStreamPosition();
                while (true) {
                    int blockType = stream.readUnsignedByte();
                    if (blockType == 0x2c) { // Image Descriptor
                        imageMetadata.imageLeftPosition =
                                stream.readUnsignedShort();
                        imageMetadata.imageTopPosition =
                                stream.readUnsignedShort();
                        imageMetadata.imageWidth = stream.readUnsignedShort();
                        imageMetadata.imageHeight = stream.readUnsignedShort();
    
                        int idPackedFields = stream.readUnsignedByte();
                        boolean localColorTableFlag =
                                (idPackedFields & 0x80) != 0;
                        imageMetadata.interlaceFlag = (idPackedFields & 0x40) != 0;
                        imageMetadata.sortFlag = (idPackedFields & 0x20) != 0;
                        int numLCTEntries = 1 << ((idPackedFields & 0x7) + 1);
    
                        if (localColorTableFlag) {
                            // Read color table if any
                            imageMetadata.localColorTable =
                                    new byte[3 * numLCTEntries];
                            stream.readFully(imageMetadata.localColorTable);
                        } else {
                            imageMetadata.localColorTable = null;
                        }
    
                        // Record length of this metadata block
                        this.imageMetadataLength =
                                (int) (stream.getStreamPosition() - startPosition);
    
                        // Now positioned at start of LZW-compressed pixels
                        return;
                    } else if (blockType == 0x21) { // Extension block
                        int label = stream.readUnsignedByte();
    
                        if (label == 0xf9) { // Graphics Control Extension
                            int gceLength = stream.readUnsignedByte(); // 4
                            int gcePackedFields = stream.readUnsignedByte();
                            imageMetadata.disposalMethod =
                                    (gcePackedFields >> 2) & 0x3;
                            imageMetadata.userInputFlag =
                                    (gcePackedFields & 0x2) != 0;
                            imageMetadata.transparentColorFlag =
                                    (gcePackedFields & 0x1) != 0;
    
                            imageMetadata.delayTime = stream.readUnsignedShort();
                            imageMetadata.transparentColorIndex
                                    = stream.readUnsignedByte();
    
                            int terminator = stream.readUnsignedByte();
                        } else if (label == 0x1) { // Plain text extension
                            int length = stream.readUnsignedByte();
                            imageMetadata.hasPlainTextExtension = true;
                            imageMetadata.textGridLeft =
                                    stream.readUnsignedShort();
                            imageMetadata.textGridTop =
                                    stream.readUnsignedShort();
                            imageMetadata.textGridWidth =
                                    stream.readUnsignedShort();
                            imageMetadata.textGridHeight =
                                    stream.readUnsignedShort();
                            imageMetadata.characterCellWidth =
                                    stream.readUnsignedByte();
                            imageMetadata.characterCellHeight =
                                    stream.readUnsignedByte();
                            imageMetadata.textForegroundColor =
                                    stream.readUnsignedByte();
                            imageMetadata.textBackgroundColor =
                                    stream.readUnsignedByte();
                            imageMetadata.text = concatenateBlocks();
                        } else if (label == 0xfe) { // Comment extension
                            byte[] comment = concatenateBlocks();
                            if (imageMetadata.comments == null) {
                                imageMetadata.comments = new ArrayList();
                            }
                            imageMetadata.comments.add(comment);
                        } else if (label == 0xff) { // Application extension
                            int blockSize = stream.readUnsignedByte();
                            byte[] applicationID = new byte[8];
                            byte[] authCode = new byte[3];
    
                            // read available data
                            byte[] blockData = new byte[blockSize];
                            stream.readFully(blockData);
    
                            int offset = copyData(blockData, 0, applicationID);
                            offset = copyData(blockData, offset, authCode);
    
                            byte[] applicationData = concatenateBlocks();
    
                            if (offset < blockSize) {
                                int len = blockSize - offset;
                                byte[] data =
                                        new byte[len + applicationData.length];
    
                                System.arraycopy(blockData, offset, data, 0, len);
                                System.arraycopy(applicationData, 0, data, len,
                                        applicationData.length);
    
                                applicationData = data;
                            }
    
                            // Init lists if necessary
                            if (imageMetadata.applicationIDs == null) {
                                imageMetadata.applicationIDs = new ArrayList();
                                imageMetadata.authenticationCodes =
                                        new ArrayList();
                                imageMetadata.applicationData = new ArrayList();
                            }
                            imageMetadata.applicationIDs.add(applicationID);
                            imageMetadata.authenticationCodes.add(authCode);
                            imageMetadata.applicationData.add(applicationData);
                        } else {
                            // Skip over unknown extension blocks
                            int length = 0;
                            do {
                                length = stream.readUnsignedByte();
                                stream.skipBytes(length);
                            } while (length > 0);
                        }
                    } else if (blockType == 0x3b) { // Trailer
                        throw new IndexOutOfBoundsException
                                ("Attempt to read past end of image sequence!");
                    } else {
                        throw new IIOException("Unexpected block type " +
                                blockType + "!");
                    }
                }
            } catch (IIOException iioe) {
                throw iioe;
            } catch (IOException ioe) {
                throw new IIOException("I/O error reading image metadata!", ioe);
            }
        }
    
        private int copyData(byte[] src, int offset, byte[] dst) {
            int len = dst.length;
            int rest = src.length - offset;
            if (len > rest) {
                len = rest;
            }
            System.arraycopy(src, offset, dst, 0, len);
            return offset + len;
        }
    
        private void startPass(int pass) {
            if (updateListeners == null) {
                return;
            }
    
            int y = 0;
            int yStep = 1;
            if (imageMetadata.interlaceFlag) {
                y = interlaceOffset[interlacePass];
                yStep = interlaceIncrement[interlacePass];
            }
    
            int[] vals = ReaderUtil.
                    computeUpdatedPixels(sourceRegion,
                            destinationOffset,
                            destinationRegion.x,
                            destinationRegion.y,
                            destinationRegion.x +
                                    destinationRegion.width - 1,
                            destinationRegion.y +
                                    destinationRegion.height - 1,
                            sourceXSubsampling,
                            sourceYSubsampling,
                            0,
                            y,
                            destinationRegion.width,
                            (destinationRegion.height + yStep - 1) / yStep,
                            1,
                            yStep);
    
            // Initialized updateMinY and updateYStep
            this.updateMinY = vals[1];
            this.updateYStep = vals[5];
    
            // Inform IIOReadUpdateListeners of new pass
            int[] bands = {0};
    
            processPassStarted(theImage,
                    interlacePass,
                    sourceMinProgressivePass,
                    sourceMaxProgressivePass,
                    0,
                    updateMinY,
                    1,
                    updateYStep,
                    bands);
        }
    
        public BufferedImage read(int imageIndex, ImageReadParam param)
                throws IIOException {
            if (stream == null) {
                throw new IllegalStateException("Input not set!");
            }
            checkIndex(imageIndex);
    
            int index = locateImage(imageIndex);
            if (index != imageIndex) {
                throw new IndexOutOfBoundsException("imageIndex out of bounds!");
            }
    
            clearAbortRequest();
            readMetadata();
    
            // A null ImageReadParam means we use the default
            if (param == null) {
                param = getDefaultReadParam();
            }
    
            // Initialize the destination image
            Iterator imageTypes = getImageTypes(imageIndex);
            this.theImage = getDestination(param,
                    imageTypes,
                    imageMetadata.imageWidth,
                    imageMetadata.imageHeight);
            this.theTile = theImage.getWritableTile(0, 0);
            this.width = imageMetadata.imageWidth;
            this.height = imageMetadata.imageHeight;
            this.streamX = 0;
            this.streamY = 0;
            this.rowsDone = 0;
            this.interlacePass = 0;
    
            // Get source region, taking subsampling offsets into account,
            // and clipping against the true source bounds
    
            this.sourceRegion = new Rectangle(0, 0, 0, 0);
            this.destinationRegion = new Rectangle(0, 0, 0, 0);
            computeRegions(param, width, height, theImage,
                    sourceRegion, destinationRegion);
            this.destinationOffset = new Point(destinationRegion.x,
                    destinationRegion.y);
    
            this.sourceXSubsampling = param.getSourceXSubsampling();
            this.sourceYSubsampling = param.getSourceYSubsampling();
            this.sourceMinProgressivePass =
                    Math.max(param.getSourceMinProgressivePass(), 0);
            this.sourceMaxProgressivePass =
                    Math.min(param.getSourceMaxProgressivePass(), 3);
    
            this.destY = destinationRegion.y +
                    (streamY - sourceRegion.y) / sourceYSubsampling;
            computeDecodeThisRow();
    
            // Inform IIOReadProgressListeners of start of image
            processImageStarted(imageIndex);
            startPass(0);
    
            this.rowBuf = new byte[width];
    
            try {
                // Read and decode the image data, fill in theImage
                this.initCodeSize = stream.readUnsignedByte();
    
                // Read first data block
                this.blockLength = stream.readUnsignedByte();
                int left = blockLength;
                int off = 0;
                while (left > 0) {
                    int nbytes = stream.read(block, off, left);
                    left -= nbytes;
                    off += nbytes;
                }
    
                this.bitPos = 0;
                this.nextByte = 0;
                this.lastBlockFound = false;
                this.interlacePass = 0;
    
                // Init 32-bit buffer
                initNext32Bits();
    
                this.clearCode = 1 << initCodeSize;
                this.eofCode = clearCode + 1;
    
                int code, oldCode = 0;
    
                int[] prefix = new int[4096];
                byte[] suffix = new byte[4096];
                byte[] initial = new byte[4096];
                int[] length = new int[4096];
                byte[] string = new byte[4096];
    
                initializeStringTable(prefix, suffix, initial, length);
                int tableIndex = (1 << initCodeSize) + 2;
                int codeSize = initCodeSize + 1;
                int codeMask = (1 << codeSize) - 1;
    
                while (!abortRequested()) {
                    code = getCode(codeSize, codeMask);
    
                    if (code == clearCode) {
                        initializeStringTable(prefix, suffix, initial, length);
                        tableIndex = (1 << initCodeSize) + 2;
                        codeSize = initCodeSize + 1;
                        codeMask = (1 << codeSize) - 1;
    
                        code = getCode(codeSize, codeMask);
                        if (code == eofCode) {
                            // Inform IIOReadProgressListeners of end of image
                            processImageComplete();
                            return theImage;
                        }
                    } else if (code == eofCode) {
                        // Inform IIOReadProgressListeners of end of image
                        processImageComplete();
                        return theImage;
                    } else {
                        int newSuffixIndex;
                        if (code < tableIndex) {
                            newSuffixIndex = code;
                        } else { // code == tableIndex
                            newSuffixIndex = oldCode;
                            if (code != tableIndex) {
                                // warning - code out of sequence
                                // possibly data corruption
                                processWarningOccurred("Out-of-sequence code!");
                            }
                        }
    
                        try {
                            int ti = tableIndex;
    
                            int oc = oldCode;
    
                            prefix[ti] = oc;
                            suffix[ti] = initial[newSuffixIndex];
                            initial[ti] = initial[oc];
                            length[ti] = length[oc] + 1;
    
                            ++tableIndex;
                            if ((tableIndex == (1 << codeSize)) &&
                                    (tableIndex < 4096)) {
                                ++codeSize;
                                codeMask = (1 << codeSize) - 1;
                            }
                        } catch (ArrayIndexOutOfBoundsException e) {
                            //Die.
                            //Pretend that the clearcode was found.
                            initializeStringTable(prefix, suffix, initial, length);
                            tableIndex = (1 << initCodeSize) + 2;
                            codeSize = initCodeSize + 1;
                            codeMask = (1 << codeSize) - 1;
    
                            code = getCode(codeSize, codeMask);
                            if (code == eofCode) {
                                // Inform IIOReadProgressListeners of end of image
                                processImageComplete();
                                return theImage;
                            }
                        }
                    }
    
                    // Reverse code
                    int c = code;
                    int len = length[c];
                    for (int i = len - 1; i >= 0; i--) {
                        string = suffix[c];
                        c = prefix[c];
                    }
    
                    outputPixels(string, len);
                    oldCode = code;
                }
    
                processReadAborted();
                return theImage;
            } catch (IOException e) {
                e.printStackTrace();
                throw new IIOException("I/O error reading image!", e);
            }
        }
    
        /**
         * Remove all settings including global settings such as
         * <code>Locale</code>s and listeners, as well as stream settings.
         */
        public void reset() {
            super.reset();
            resetStreamSettings();
        }
    
        /**
         * Remove local settings based on parsing of a stream.
         */
        private void resetStreamSettings() {
            gotHeader = false;
            streamMetadata = null;
            currIndex = -1;
            imageMetadata = null;
            imageStartPosition = new ArrayList();
            numImages = -1;
    
            // No need to reinitialize 'block'
            blockLength = 0;
            bitPos = 0;
            nextByte = 0;
    
            next32Bits = 0;
            lastBlockFound = false;
    
            theImage = null;
            theTile = null;
            width = -1;
            height = -1;
            streamX = -1;
            streamY = -1;
            rowsDone = 0;
            interlacePass = 0;
        }
    }
    
    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-9-28 11:23 , Processed in 0.075381 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表