Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-7131823

bug in GIFImageReader

XMLWordPrintable

    • b23
    • x86
    • windows_7

        FULL PRODUCT VERSION :
        java version "1.7.0_02"
        Java(TM) SE Runtime Environment (build 1.7.0_02-b13)
        Java HotSpot(TM) 64-Bit Server VM (build 22.0-b10, mixed mode)

        ADDITIONAL OS VERSION INFORMATION :
        Microsoft Windows [Version 6.1.7601]

        A DESCRIPTION OF THE PROBLEM :
        GIFImageReader can not read some GIF images,
        because GIFImageReader has two bugs in LZW decoder.

        1. LZW encoder can output the codes after the tree becomes full, without outputting the clearCode(for example it is 256, in 256-color gif image).

        Good LZW encoder determines the timing of outputting the clearCode by the compression rate. if useing the old tree becomes good compression rate, Good LZW encoder does not output the clearCode. if not so, Good LZW encoder outputs the clearCode.

        however, GIFImageReader is based on the wrong assumption, that is LZW encoder always outputs the clearCode before tree becomes overflow.

        when GIFImageReader reads a image which is created by Good LZW encoder, it causes ArrayIndexOutOfBoundsException.


        2. textbookish LZW decoder is drop the first code. it does not attach to the tree.

        however, GIFImageReader attachs first code to the tree. so tree is always broken.

        I understand the part which should be corrected.
        however I don't understand why GIFImageReader can read images with broken tree.

        show other implementation of GIF decoder, you will be able to be judged whether I am right or wrong.

        http://www.java2s.com/Code/Java/2D-Graphics-GUI/GiffileEncoder.htm
        http://mxr.mozilla.org/mozilla-central/source/image/decoders/nsGIFDecoder2.cpp

        both implementations assign NullCode(-1) to oldCode at first, and they drop the first code.


        paste part of corrected GIFImageReader#read(int, ImageReadParam)

                    final int NULL_CODE = -1;
                    int code, oldCode = NULL_CODE;

                    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);
                            oldCode = NULL_CODE;
                            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!");
                                }
                            }

                            if (NULL_CODE != oldCode && tableIndex < 4096) {
                                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;
                                }
                            }
                        }

                        // Reverse code
                        int c = code;
                        int len = length[c];
                        for (int i = len - 1; i >= 0; i--) {
                            string[i] = suffix[c];
                            c = prefix[c];
                        }

                        outputPixels(string, len);
                        oldCode = code;
                    }



        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        I have some gif images which reproduce this bug.
        I can mail it.


        REPRODUCIBILITY :
        This bug can be reproduced always.

        CUSTOMER SUBMITTED WORKAROUND :
        case 1 no workaround.
        case 2 use GifDecoder in
        http://www.java2s.com/Code/Java/2D-Graphics-GUI/GiffileEncoder.htm

              phh Paul Hohensee
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              10 Start watching this issue

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: