1
+ <?php
2
+
3
+ /*
4
+ :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
5
+ :: Formerly known as:::
6
+ :: GIFEncoder Version 2.0 by László Zsidi, http://gifs.hu
7
+ ::
8
+ :: This class is a rewritten 'GifMerge.class.php' version.
9
+ ::
10
+ :: Modification:
11
+ :: - Simplified and easy code,
12
+ :: - Ultra fast encoding,
13
+ :: - Built-in errors,
14
+ :: - Stable working
15
+ ::
16
+ ::
17
+ :: Updated at 2007. 02. 13. '00.05.AM'
18
+ ::
19
+ ::
20
+ ::
21
+ :: Try on-line GIFBuilder Form demo based on GIFEncoder.
22
+ ::
23
+ :: http://gifs.hu/phpclasses/demos/GifBuilder/
24
+ ::
25
+ :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
26
+ */
27
+
28
+ /**
29
+ * Encode animated gifs
30
+ */
31
+ class AnimatedGif {
32
+ /**
33
+ * The built gif image
34
+ * @var resource
35
+ */
36
+ private $ image = '' ;
37
+
38
+ /**
39
+ * The array of images to stack
40
+ * @var array
41
+ */
42
+ private $ buffer = Array ();
43
+
44
+ /**
45
+ * How many times to loop? 0 = infinite
46
+ * @var int
47
+ */
48
+ private $ number_of_loops = 0 ;
49
+
50
+ /**
51
+ *
52
+ * @var int
53
+ */
54
+ private $ DIS = 2 ;
55
+
56
+ /**
57
+ * Which colour is transparent
58
+ * @var int
59
+ */
60
+ private $ transparent_colour = -1 ;
61
+
62
+ /**
63
+ * Is this the first frame
64
+ * @var int
65
+ */
66
+ private $ first_frame = TRUE ;
67
+
68
+ /**
69
+ * Encode an animated gif
70
+ * @param array $source_images An array of binary source images
71
+ * @param array $image_delays The delays associated with the source images
72
+ * @param type $number_of_loops The number of times to loop
73
+ * @param int $transparent_colour_red
74
+ * @param int $transparent_colour_green
75
+ * @param int $transparent_colour_blue
76
+ */
77
+ function __construct (array $ source_images , array $ image_delays , $ number_of_loops , $ transparent_colour_red = -1 , $ transparent_colour_green = -1 , $ transparent_colour_blue = -1 ) {
78
+ /**
79
+ * I have no idea what these even do, they appear to do nothing to the image so far
80
+ */
81
+ $ transparent_colour_red = 0 ;
82
+ $ transparent_colour_green = 0 ;
83
+ $ transparent_colour_blue = 0 ;
84
+
85
+ $ this ->number_of_loops = ( $ number_of_loops > -1 ) ? $ number_of_loops : 0 ;
86
+ $ this ->set_transparent_colour ($ transparent_colour_red , $ transparent_colour_green , $ transparent_colour_blue );
87
+ $ this ->buffer_images ($ source_images );
88
+
89
+ $ this ->addHeader ();
90
+ for ($ i = 0 ; $ i < count ($ this ->buffer ); $ i ++) {
91
+ $ this ->addFrame ($ i , $ image_delays [$ i ]);
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Set the transparent colour
97
+ * @param int $red
98
+ * @param int $green
99
+ * @param int $blue
100
+ */
101
+ private function set_transparent_colour ($ red , $ green , $ blue ){
102
+ $ this ->transparent_colour = ( $ red > -1 && $ green > -1 && $ blue > -1 ) ?
103
+ ( $ red | ( $ green << 8 ) | ( $ blue << 16 ) ) : -1 ;
104
+ }
105
+
106
+ /**
107
+ * Buffer the images and check to make sure they are vaild
108
+ * @param array $source_images the array of source images
109
+ * @throws Exception
110
+ */
111
+ private function buffer_images ($ source_images ) {
112
+ for ($ i = 0 ; $ i < count ($ source_images ); $ i ++) {
113
+ $ this ->buffer [] = $ source_images [$ i ];
114
+ if (substr ($ this ->buffer [$ i ], 0 , 6 ) != "GIF87a " && substr ($ this ->buffer [$ i ], 0 , 6 ) != "GIF89a " ) {
115
+ throw new Exception ('Image at position ' . $ i . ' is not a gif ' );
116
+ }
117
+ for ($ j = ( 13 + 3 * ( 2 << ( ord ($ this ->buffer [$ i ] { 10 }) & 0x07 ) ) ), $ k = TRUE ; $ k ; $ j ++) {
118
+ switch ($ this ->buffer [$ i ] { $ j }) {
119
+ case "! " :
120
+ if (( substr ($ this ->buffer [$ i ], ( $ j + 3 ), 8 ) ) == "NETSCAPE " ) {
121
+ throw new Exception ('You cannot make an animation from an animated gif. ' );
122
+ }
123
+ break ;
124
+ case ";":
125
+ $ k = FALSE;
126
+ break;
127
+ }
128
+ }
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Add the gif header to the image
134
+ */
135
+ private function addHeader() {
136
+ $ cmap = 0;
137
+ $ this ->image = 'GIF89a';
138
+ if (ord( $ this ->buffer [0] { 10 }) & 0x80) {
139
+ $ cmap = 3 * ( 2 << ( ord( $ this ->buffer [0] { 10 }) & 0x07 ) );
140
+ $ this ->image .= substr( $ this ->buffer [0], 6, 7);
141
+ $ this ->image .= substr( $ this ->buffer [0], 13, $ cmap);
142
+ $ this ->image .= " !\377 \13 NETSCAPE2 .0 \3 \1 " . $ this ->word ($ this ->number_of_loops ) . "\0" ;
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Add a frame to the animation
148
+ * @param int $frame The frame to be added
149
+ * @param int $delay The delay associated with the frame
150
+ */
151
+ private function addFrame($ frame , $ delay ) {
152
+ $ Locals_str = 13 + 3 * ( 2 << ( ord ($ this ->buffer [$ frame ] { 10 }) & 0x07 ) );
153
+
154
+ $ Locals_end = strlen ($ this ->buffer [$ frame ]) - $ Locals_str - 1 ;
155
+ $ Locals_tmp = substr ($ this ->buffer [$ frame ], $ Locals_str , $ Locals_end );
156
+
157
+ $ Global_len = 2 << ( ord ($ this ->buffer [0 ] { 10 }) & 0x07 );
158
+ $ Locals_len = 2 << ( ord ($ this ->buffer [$ frame ] { 10 }) & 0x07 );
159
+
160
+ $ Global_rgb = substr ($ this ->buffer [0 ], 13 , 3 * ( 2 << ( ord ($ this ->buffer [0 ] { 10 }) & 0x07 ) ));
161
+ $ Locals_rgb = substr ($ this ->buffer [$ frame ], 13 , 3 * ( 2 << ( ord ($ this ->buffer [$ frame ] { 10 }) & 0x07 ) ));
162
+
163
+ $ Locals_ext = "! \xF9\x04" . chr (( $ this ->DIS << 2 ) + 0 ) .
164
+ chr (( $ delay >> 0 ) & 0xFF ) . chr (( $ delay >> 8 ) & 0xFF ) . "\x0\x0" ;
165
+
166
+ if ($ this ->transparent_colour > -1 && ord ($ this ->buffer [$ frame ] { 10 }) & 0x80 ) {
167
+ for ($ j = 0 ; $ j < ( 2 << ( ord ($ this ->buffer [$ frame ] { 10 }) & 0x07 ) ); $ j ++) {
168
+ if (
169
+ ord($ Locals_rgb { 3 * $ j + 0 }) == ( ( $ this ->transparent_colour >> 16 ) & 0xFF ) &&
170
+ ord($ Locals_rgb { 3 * $ j + 1 }) == ( ( $ this ->transparent_colour >> 8 ) & 0xFF ) &&
171
+ ord ($ Locals_rgb { 3 * $ j + 2 }) == ( ( $ this ->transparent_colour >> 0 ) & 0xFF )
172
+ ) {
173
+ $ Locals_ext = "! \xF9\x04" . chr (( $ this ->DIS << 2 ) + 1 ) .
174
+ chr (( $ delay >> 0 ) & 0xFF ) . chr (( $ delay >> 8 ) & 0xFF ) . chr ($ j ) . "\x0" ;
175
+ break ;
176
+ }
177
+ }
178
+ }
179
+ switch ($ Locals_tmp { 0 }) {
180
+ case "! " :
181
+ $ Locals_img = substr ($ Locals_tmp , 8 , 10 );
182
+ $ Locals_tmp = substr ($ Locals_tmp , 18 , strlen ($ Locals_tmp ) - 18 );
183
+ break ;
184
+ case ", " :
185
+ $ Locals_img = substr ($ Locals_tmp , 0 , 10 );
186
+ $ Locals_tmp = substr ($ Locals_tmp , 10 , strlen ($ Locals_tmp ) - 10 );
187
+ break ;
188
+ }
189
+ if (ord ($ this ->buffer [$ frame ] { 10 }) & 0x80 && $ this ->first_frame === FALSE ) {
190
+ if ($ Global_len == $ Locals_len ) {
191
+ if ($ this ->blockCompare ($ Global_rgb , $ Locals_rgb , $ Global_len )) {
192
+ $ this ->image .= ( $ Locals_ext . $ Locals_img . $ Locals_tmp );
193
+ } else {
194
+ $ byte = ord($ Locals_img { 9 });
195
+ $ byte |= 0x80 ;
196
+ $ byte &= 0xF8 ;
197
+ $ byte |= ( ord ($ this ->buffer [0 ] { 10 }) & 0x07 );
198
+ $ Locals_img { 9 } = chr ($ byte );
199
+ $ this ->image .= ( $ Locals_ext . $ Locals_img . $ Locals_rgb . $ Locals_tmp );
200
+ }
201
+ } else {
202
+ $ byte = ord($ Locals_img { 9 });
203
+ $ byte |= 0x80 ;
204
+ $ byte &= 0xF8 ;
205
+ $ byte |= ( ord ($ this ->buffer [$ frame ] { 10 }) & 0x07 );
206
+ $ Locals_img { 9 } = chr ($ byte );
207
+ $ this ->image .= ( $ Locals_ext . $ Locals_img . $ Locals_rgb . $ Locals_tmp );
208
+ }
209
+ } else {
210
+ $ this ->image .= ( $ Locals_ext . $ Locals_img . $ Locals_tmp );
211
+ }
212
+ $ this ->first_frame = FALSE ;
213
+ }
214
+
215
+ /**
216
+ * Add the gif footer
217
+ */
218
+ private function addFooter () {
219
+ $ this ->image .= "; " ;
220
+ }
221
+
222
+ /**
223
+ * Compare gif blocks? What is a block?
224
+ * @param type $GlobalBlock
225
+ * @param type $LocalBlock
226
+ * @param type $Len
227
+ * @return type
228
+ */
229
+ private function blockCompare ($ GlobalBlock , $ LocalBlock , $ Len ) {
230
+ for ($ i = 0 ; $ i < $ Len ; $ i ++) {
231
+ if (
232
+ $ GlobalBlock { 3 * $ i + 0 } != $ LocalBlock { 3 * $ i + 0 } ||
233
+ $ GlobalBlock { 3 * $ i + 1 } != $ LocalBlock { 3 * $ i + 1 } ||
234
+ $ GlobalBlock { 3 * $ i + 2 } != $ LocalBlock { 3 * $ i + 2 }
235
+ ) {
236
+ return ( 0 );
237
+ }
238
+ }
239
+
240
+ return ( 1 );
241
+ }
242
+
243
+ /**
244
+ * No clue
245
+ * @param int $int
246
+ * @return string the char you meant?
247
+ */
248
+ private function word ($ int ) {
249
+ return ( chr ($ int & 0xFF ) . chr (( $ int >> 8 ) & 0xFF ) );
250
+ }
251
+
252
+ /**
253
+ * Return the animated gif
254
+ * @return type
255
+ */
256
+ function getAnimation () {
257
+ return $ this ->image ;
258
+ }
259
+
260
+ /**
261
+ * Return the animated gif
262
+ * @return type
263
+ */
264
+ function display () {
265
+ //late footer add
266
+ $ this ->addFooter ();
267
+ header ('Content-type:image/gif ' );
268
+ echo $ this ->image ;
269
+ }
270
+
271
+ }
0 commit comments