Home  >  Article  >  Backend Development  >  Troubleshooting and modification of GIFDecoder is attached with complete code and demo

Troubleshooting and modification of GIFDecoder is attached with complete code and demo

WBOY
WBOYOriginal
2016-08-08 09:23:541253browse

Foreword

I haven’t written a technical blog for a long time. I have some small gains today. I will record them and keep them as backups

Gif image processing

Due to business needs, the first frame of the gif animation needs to be intercepted. Then I searched and found a class like GIFDecoder, which is used to process gif images. However, the blogging environment in China is still so poor. Various websites and blogs copy it everywhere, but there is no complete content. After many The site's information has been sorted out and is finally ready for use.

An exception occurred

When running the demo, I encountered a display error problem

Notice: Undefined offset: 4 in /Applications/XAMPP/xamppfiles/htdocs/giftest/gifdecoder.class.php on line 83

Looking at the source code, I found that line 83 is like this

<code><span><span>function</span><span>GIFReadExtensions</span><span>()</span> {</span>
            GIFDecoder::GIFGetByte(<span>1</span>);
            <span>if</span> (<span>$this</span>->GIF_buffer [<span>0</span>] == <span>0xff</span>) {
                <span>for</span> (;;) {
                    GIFDecoder::GIFGetByte(<span>1</span>);
                    <span>if</span> (( <span>$u</span> = <span>$this</span>->GIF_buffer [<span>0</span>] ) == <span>0x00</span>) {
                        <span>break</span>;
                    }
                    GIFDecoder::GIFGetByte(<span>$u</span>);
                    <span>if</span> (<span>$u</span> == <span>0x03</span>) {
                        <span>$this</span>->GIF_anloop = ( <span>$this</span>->GIF_buffer [<span>1</span>] | <span>$this</span>->GIF_buffer [<span>2</span>] << <span>8</span> );
                    }
                }
            } <span>else</span> {
                <span>for</span> (;;) {
                    GIFDecoder::GIFGetByte(<span>1</span>);
                    <span>if</span> (( <span>$u</span> = <span>$this</span>->GIF_buffer [<span>0</span>] ) == <span>0x00</span>) {
                        <span>break</span>;
                    }
                    GIFDecoder::GIFGetByte(<span>$u</span>);
                    <span>if</span> (<span>$u</span> == <span>0x04</span>) {
                        <span>if</span> (<span>$this</span>->GIF_buffer [<span>4</span>] & <span>0x80</span>) {   <span>//这里是第83行</span><span>$this</span>->GIF_dispos [] = ( <span>$this</span>->GIF_buffer [<span>0</span>] >> <span>2</span> ) - <span>1</span>;
                        } <span>else</span> {
                            <span>$this</span>->GIF_dispos [] = ( <span>$this</span>->GIF_buffer [<span>0</span>] >> <span>2</span> ) - <span>0</span>;
                        }
                        <span>$this</span>->GIF_delays [] = ( <span>$this</span>->GIF_buffer [<span>1</span>] | <span>$this</span>->GIF_buffer [<span>2</span>] << <span>8</span> );
                        <span>if</span> (<span>$this</span>->GIF_buffer [<span>3</span>]) {
                            <span>$this</span>->GIF_TransparentI = <span>$this</span>->GIF_buffer [<span>3</span>];
                        }
                    }
                }
            }
        }</code>

The reason

After the efforts of search engines, the more formal explanation I got is

offset: The next number is the wrong array subscript, which is usually exceeded The value range of the array, if the array A[]has10 each yuannumber,such asfruit Out Now A[10] will cause an error (Notice: Undefined offset: 10 ....), because the lower part of the array The mark is from It starts with 0, so the subscript of this array can only be 0~9.

So, the reason is

The array cannot find the element with subscript 4

Solution

We need to determine the subscript Does it exist

<code><span>if</span> (<span>isset</span>(<span>$this</span>->GIF_buffer [<span>4</span>]) & <span>0x80</span>) { </code>

Jiang Zi will do it, la la la~

Source code

<code><span><span><span><?php</span>/**
 * GIFDecoder  <br/>
 * 
 * 日期: 2015年05月21日   <br/>
 * 原作者: 不详           <br/>
 * 修改: CalvinLee       <br/>
 * 
 * 
 * <code>
 * require_once("gifdecoder.class.php");
 *
 * $FIC = "test.gif";
 * //获取gif的第一帧进行保存
 * if (file_exists($FIC)) {
 *      $GIF_frame = fread(fopen($FIC, 'rb'), filesize($FIC));
 *      $decoder = new GIFDecoder($GIF_frame);
 *      $frames = $decoder->GIFGetFrames();
 *      $i = 0; 
 *      $fname =  rand(1000, 9999). $FIC . "_0$i.png"; 
 *      $hfic = fopen("" . $fname, "wb");
 *      fwrite($hfic, $frames [$i]);
 *      fclose($hfic);
 * } 
 *  </code>
 * 
 * 
 *<span> @copyright</span> (c) 2015, Calvin Lee
 *<span> @author</span> Calvin Lee <diandianxiyu_@live.cn>

 */</span><span><span>Class</span><span>GIFDecoder</span> {</span><span>public</span><span>$GIF_TransparentR</span> = -<span>1</span>;
    <span>public</span><span>$GIF_TransparentG</span> = -<span>1</span>;
    <span>public</span><span>$GIF_TransparentB</span> = -<span>1</span>;
    <span>public</span><span>$GIF_TransparentI</span> = <span>0</span>;
    <span>public</span><span>$GIF_buffer</span> = <span>array</span>();
    <span>public</span><span>$GIF_arrays</span> = <span>array</span>();
    <span>public</span><span>$GIF_delays</span> = <span>array</span>();
    <span>public</span><span>$GIF_dispos</span> = <span>array</span>();
    <span>public</span><span>$GIF_stream</span> = <span>""</span>;
    <span>public</span><span>$GIF_string</span> = <span>""</span>;
    <span>public</span><span>$GIF_bfseek</span> = <span>0</span>;
    <span>public</span><span>$GIF_anloop</span> = <span>0</span>;
    <span>public</span><span>$GIF_screen</span> = <span>array</span>();
    <span>public</span><span>$GIF_global</span> = <span>array</span>();
    <span>public</span><span>$GIF_sorted</span>;
    <span>public</span><span>$GIF_colorS</span>;
    <span>public</span><span>$GIF_colorC</span>;
    <span>public</span><span>$GIF_colorF</span>;

    <span><span>function</span><span>GIFDecoder</span><span>(<span>$GIF_pointer</span>)</span> {</span><span>$this</span>->GIF_stream = <span>$GIF_pointer</span>;

        GIFDecoder::GIFGetByte(<span>6</span>);
        GIFDecoder::GIFGetByte(<span>7</span>);

        <span>$this</span>->GIF_screen = <span>$this</span>->GIF_buffer;
        <span>$this</span>->GIF_colorF = <span>$this</span>->GIF_buffer [<span>4</span>] & <span>0x80</span> ? <span>1</span> : <span>0</span>;
        <span>$this</span>->GIF_sorted = <span>$this</span>->GIF_buffer [<span>4</span>] & <span>0x08</span> ? <span>1</span> : <span>0</span>;
        <span>$this</span>->GIF_colorC = <span>$this</span>->GIF_buffer [<span>4</span>] & <span>0x07</span>;
        <span>$this</span>->GIF_colorS = <span>2</span> << <span>$this</span>->GIF_colorC;

        <span>if</span> (<span>$this</span>->GIF_colorF == <span>1</span>) {
            GIFDecoder::GIFGetByte(<span>3</span> * <span>$this</span>->GIF_colorS);
            <span>$this</span>->GIF_global = <span>$this</span>->GIF_buffer;
        }
        <span>for</span> (<span>$cycle</span> = <span>1</span>; <span>$cycle</span>;) {
            <span>if</span> (GIFDecoder::GIFGetByte(<span>1</span>)) {
                <span>switch</span> (<span>$this</span>->GIF_buffer [<span>0</span>]) {
                    <span>case</span><span>0x21</span>:
                        GIFDecoder::GIFReadExtensions();
                        <span>break</span>;
                    <span>case</span><span>0x2C</span>:
                        GIFDecoder::GIFReadDescriptor();
                        <span>break</span>;
                    <span>case</span><span>0x3B</span>:
                        <span>$cycle</span> = <span>0</span>;
                        <span>break</span>;
                }
            } <span>else</span> {
                <span>$cycle</span> = <span>0</span>;
            }
        }
    }

    <span><span>function</span><span>GIFReadExtensions</span><span>()</span> {</span>
        GIFDecoder::GIFGetByte(<span>1</span>);
        <span>if</span> (<span>$this</span>->GIF_buffer [<span>0</span>] == <span>0xff</span>) {
            <span>for</span> (;;) {
                GIFDecoder::GIFGetByte(<span>1</span>);
                <span>if</span> (( <span>$u</span> = <span>$this</span>->GIF_buffer [<span>0</span>] ) == <span>0x00</span>) {
                    <span>break</span>;
                }
                GIFDecoder::GIFGetByte(<span>$u</span>);
                <span>if</span> (<span>$u</span> == <span>0x03</span>) {
                    <span>$this</span>->GIF_anloop = ( <span>$this</span>->GIF_buffer [<span>1</span>] | <span>$this</span>->GIF_buffer [<span>2</span>] << <span>8</span> );
                }
            }
        } <span>else</span> {
            <span>for</span> (;;) {
                GIFDecoder::GIFGetByte(<span>1</span>);
                <span>if</span> (( <span>$u</span> = <span>$this</span>->GIF_buffer [<span>0</span>] ) == <span>0x00</span>) {
                    <span>break</span>;
                }
                GIFDecoder::GIFGetByte(<span>$u</span>);
                <span>if</span> (<span>$u</span> == <span>0x04</span>) {
                    <span>if</span> (<span>isset</span>(<span>$this</span>->GIF_buffer [<span>4</span>]) & <span>0x80</span>) {
                        <span>$this</span>->GIF_dispos [] = ( <span>$this</span>->GIF_buffer [<span>0</span>] >> <span>2</span> ) - <span>1</span>;
                    } <span>else</span> {
                        <span>$this</span>->GIF_dispos [] = ( <span>$this</span>->GIF_buffer [<span>0</span>] >> <span>2</span> ) - <span>0</span>;
                    }
                    <span>$this</span>->GIF_delays [] = ( <span>$this</span>->GIF_buffer [<span>1</span>] | <span>$this</span>->GIF_buffer [<span>2</span>] << <span>8</span> );
                    <span>if</span> (<span>$this</span>->GIF_buffer [<span>3</span>]) {
                        <span>$this</span>->GIF_TransparentI = <span>$this</span>->GIF_buffer [<span>3</span>];
                    }
                }
            }
        }
    }

    <span><span>function</span><span>GIFReadDescriptor</span><span>()</span> {</span><span>$GIF_screen</span> = <span>Array</span>();

        GIFDecoder::GIFGetByte(<span>9</span>);
        <span>$GIF_screen</span> = <span>$this</span>->GIF_buffer;
        <span>$GIF_colorF</span> = <span>$this</span>->GIF_buffer [<span>8</span>] & <span>0x80</span> ? <span>1</span> : <span>0</span>;
        <span>if</span> (<span>$GIF_colorF</span>) {
            <span>$GIF_code</span> = <span>$this</span>->GIF_buffer [<span>8</span>] & <span>0x07</span>;
            <span>$GIF_sort</span> = <span>$this</span>->GIF_buffer [<span>8</span>] & <span>0x20</span> ? <span>1</span> : <span>0</span>;
        } <span>else</span> {
            <span>$GIF_code</span> = <span>$this</span>->GIF_colorC;
            <span>$GIF_sort</span> = <span>$this</span>->GIF_sorted;
        }
        <span>$GIF_size</span> = <span>2</span> << <span>$GIF_code</span>;
        <span>$this</span>->GIF_screen [<span>4</span>] &= <span>0x70</span>;
        <span>$this</span>->GIF_screen [<span>4</span>] |= <span>0x80</span>;
        <span>$this</span>->GIF_screen [<span>4</span>] |= <span>$GIF_code</span>;
        <span>if</span> (<span>$GIF_sort</span>) {
            <span>$this</span>->GIF_screen [<span>4</span>] |= <span>0x08</span>;
        }

        <span>//GIF Data Begin</span><span>if</span> (<span>$this</span>->GIF_TransparentI) {
            <span>$this</span>->GIF_string = <span>"GIF89a"</span>;
        } <span>else</span> {
            <span>$this</span>->GIF_string = <span>"GIF87a"</span>;
        }
        GIFDecoder::GIFPutByte(<span>$this</span>->GIF_screen);
        <span>if</span> (<span>$GIF_colorF</span> == <span>1</span>) {
            GIFDecoder::GIFGetByte(<span>3</span> * <span>$GIF_size</span>);
            <span>if</span> (<span>$this</span>->GIF_TransparentI) {
                <span>$this</span>->GIF_TransparentR = <span>$this</span>->GIF_buffer [<span>3</span> * <span>$this</span>->GIF_TransparentI + <span>0</span>];
                <span>$this</span>->GIF_TransparentG = <span>$this</span>->GIF_buffer [<span>3</span> * <span>$this</span>->GIF_TransparentI + <span>1</span>];
                <span>$this</span>->GIF_TransparentB = <span>$this</span>->GIF_buffer [<span>3</span> * <span>$this</span>->GIF_TransparentI + <span>2</span>];
            }
            GIFDecoder::GIFPutByte(<span>$this</span>->GIF_buffer);
        } <span>else</span> {
            <span>if</span> (<span>$this</span>->GIF_TransparentI) {
                <span>$this</span>->GIF_TransparentR = <span>$this</span>->GIF_global [<span>3</span> * <span>$this</span>->GIF_TransparentI + <span>0</span>];
                <span>$this</span>->GIF_TransparentG = <span>$this</span>->GIF_global [<span>3</span> * <span>$this</span>->GIF_TransparentI + <span>1</span>];
                <span>$this</span>->GIF_TransparentB = <span>$this</span>->GIF_global [<span>3</span> * <span>$this</span>->GIF_TransparentI + <span>2</span>];
            }
            GIFDecoder::GIFPutByte(<span>$this</span>->GIF_global);
        }
        <span>if</span> (<span>$this</span>->GIF_TransparentI) {
            <span>$this</span>->GIF_string .= <span>"!\xF9\x04\x1\x0\x0"</span> . chr(<span>$this</span>->GIF_TransparentI) . <span>"\x0"</span>;
        }
        <span>$this</span>->GIF_string .= chr(<span>0x2C</span>);
        <span>$GIF_screen</span> [<span>8</span>] &= <span>0x40</span>;
        GIFDecoder::GIFPutByte(<span>$GIF_screen</span>);
        GIFDecoder::GIFGetByte(<span>1</span>);
        GIFDecoder::GIFPutByte(<span>$this</span>->GIF_buffer);
        <span>for</span> (;;) {
            GIFDecoder::GIFGetByte(<span>1</span>);
            GIFDecoder::GIFPutByte(<span>$this</span>->GIF_buffer);
            <span>if</span> (( <span>$u</span> = <span>$this</span>->GIF_buffer [<span>0</span>] ) == <span>0x00</span>) {
                <span>break</span>;
            }
            GIFDecoder::GIFGetByte(<span>$u</span>);
            GIFDecoder::GIFPutByte(<span>$this</span>->GIF_buffer);
        }
        <span>$this</span>->GIF_string .= chr(<span>0x3B</span>);
        <span>//GIF Data End</span><span>$gif_array</span> = &<span>$this</span>->GIF_arrays;
        <span>$gif_array</span>[] = <span>$this</span>->GIF_string;
    }

    <span><span>function</span><span>GIFGetByte</span><span>(<span>$len</span>)</span> {</span><span>$this</span>->GIF_buffer = <span>Array</span>();
        <span>for</span> (<span>$i</span> = <span>0</span>; <span>$i</span> < <span>$len</span>; <span>$i</span>++) {
            <span>if</span> (<span>$this</span>->GIF_bfseek > strlen(<span>$this</span>->GIF_stream)) {
                <span>return</span><span>0</span>;
            }
            <span>$this</span>->GIF_buffer[] = ord(<span>$this</span>->GIF_stream { <span>$this</span>->GIF_bfseek++});
        }
        <span>return</span><span>1</span>;
    }

    <span><span>function</span><span>GIFPutByte</span><span>(<span>$bytes</span>)</span> {</span><span>foreach</span> (<span>$bytes</span><span>as</span><span>$byte</span>) {
            <span>$this</span>->GIF_string .= chr(<span>$byte</span>);
        }
    }

    <span><span>function</span><span>GIFGetFrames</span><span>()</span> {</span><span>return</span> ( <span>$this</span>->GIF_arrays );
    }

    <span><span>function</span><span>GIFGetDelays</span><span>()</span> {</span><span>return</span> ( <span>$this</span>->GIF_delays );
    }

    <span><span>function</span><span>GIFGetLoop</span><span>()</span> {</span><span>return</span> ( <span>$this</span>->GIF_anloop );
    }

    <span><span>function</span><span>GIFGetDisposal</span><span>()</span> {</span><span>return</span> ( <span>$this</span>->GIF_dispos );
    }

    <span><span>function</span><span>GIFGetTransparentR</span><span>()</span> {</span><span>return</span> ( <span>$this</span>->GIF_TransparentR );
    }

    <span><span>function</span><span>GIFGetTransparentG</span><span>()</span> {</span><span>return</span> ( <span>$this</span>->GIF_TransparentG );
    }

    <span><span>function</span><span>GIFGetTransparentB</span><span>()</span> {</span><span>return</span> ( <span>$this</span>->GIF_TransparentB );
    }

}

<span>?></span></span></span></code>

Postscript

  • Small accumulation of knowledge will eventually lead to qualitative changes
  • It never hurts to be good at summarizing
  • A function will change after writing it three times It’s different. If it’s still the same, it’s your own problem

The above introduces the troubleshooting and modification of GIFDecoder. Attached is the complete code and demo, including the content. I hope it will be helpful to friends who are interested in PHP tutorials.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:PHP file read into arrayNext article:PHP file read into array