comparison mupdf-source/source/fitz/load-gif.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // Copyright (C) 2004-2021 Artifex Software, Inc.
2 //
3 // This file is part of MuPDF.
4 //
5 // MuPDF is free software: you can redistribute it and/or modify it under the
6 // terms of the GNU Affero General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or (at your option)
8 // any later version.
9 //
10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17 //
18 // Alternative licensing terms are available from the licensor.
19 // For commercial licensing, see <https://www.artifex.com/> or contact
20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21 // CA 94129, USA, for further information.
22
23 #include "mupdf/fitz.h"
24
25 #include "pixmap-imp.h"
26
27 #include <string.h>
28 #include <limits.h>
29
30 struct info
31 {
32 int gif89a;
33 unsigned int width, height;
34 unsigned char aspect;
35 unsigned int xres, yres;
36
37 unsigned int image_left, image_top;
38 unsigned int image_width, image_height;
39 unsigned int image_interlaced;
40
41 int has_gct;
42 int gct_entries;
43 unsigned char *gct;
44 unsigned int gct_background;
45
46 int has_lct;
47 int lct_entries;
48 unsigned char *lct;
49
50 int has_transparency;
51 unsigned int transparent;
52 unsigned char *mask;
53
54 fz_pixmap *pix;
55 };
56
57 /* default color table, where the first two entries are black and white */
58 static const unsigned char dct[256 * 3] = {
59 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02,
60 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06,
61 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a,
62 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e,
63 0x0f, 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12,
64 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16,
65 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a,
66 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e,
67 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22,
68 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26,
69 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a,
70 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e,
71 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32,
72 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36,
73 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a,
74 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e,
75 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42,
76 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46,
77 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a,
78 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e,
79 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52,
80 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56,
81 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a,
82 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e,
83 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62,
84 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66,
85 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a,
86 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e,
87 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x72, 0x72, 0x72,
88 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76,
89 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7a,
90 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e,
91 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82,
92 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86,
93 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a,
94 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e,
95 0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92,
96 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x95, 0x95, 0x95, 0x96, 0x96, 0x96,
97 0x97, 0x97, 0x97, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x9a, 0x9a, 0x9a,
98 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e,
99 0x9f, 0x9f, 0x9f, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2,
100 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa6,
101 0xa7, 0xa7, 0xa7, 0xa8, 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xaa, 0xaa, 0xaa,
102 0xab, 0xab, 0xab, 0xac, 0xac, 0xac, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae,
103 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2,
104 0xb3, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6,
105 0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba,
106 0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe,
107 0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc1, 0xc1, 0xc1, 0xc2, 0xc2, 0xc2,
108 0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6,
109 0xc7, 0xc7, 0xc7, 0xc8, 0xc8, 0xc8, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca,
110 0xcb, 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce,
111 0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd2, 0xd2, 0xd2,
112 0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd5, 0xd5, 0xd5, 0xd6, 0xd6, 0xd6,
113 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xda, 0xda, 0xda,
114 0xdb, 0xdb, 0xdb, 0xdc, 0xdc, 0xdc, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde,
115 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, 0xe2,
116 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6,
117 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea,
118 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee,
119 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2,
120 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6,
121 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa,
122 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe,
123 };
124
125 static const unsigned char *
126 gif_read_subblocks(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end, fz_buffer *buf)
127 {
128 int len;
129
130 do
131 {
132 if (end - p < 1)
133 fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in data subblocks in gif image");
134 len = *p;
135 p += 1;
136
137 if (len > 0)
138 {
139 if (end - p < len)
140 fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in data subblock in gif image");
141 if (buf)
142 fz_append_data(ctx, buf, p, len);
143 p += len;
144 }
145 } while (len > 0);
146
147 return p;
148 }
149
150 static const unsigned char *
151 gif_read_header(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
152 {
153 if (end - p < 6)
154 fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in header in gif image");
155
156 if (memcmp(&p[0], "GIF", 3))
157 fz_throw(ctx, FZ_ERROR_FORMAT, "invalid signature in gif image");
158 if (memcmp(&p[3], "87a", 3) && memcmp(&p[3], "89a", 3))
159 fz_throw(ctx, FZ_ERROR_FORMAT, "unsupported version in gif image");
160
161 info->gif89a = !memcmp(p, "GIF89a", 6);
162
163 return p + 6;
164 }
165
166 /* coverity[-tainted_data_return] */
167 static unsigned int
168 safe_load_u16(const unsigned char *p)
169 {
170 return p[1] << 8 | p[0];
171 }
172
173 static const unsigned char *
174 gif_read_lsd(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
175 {
176 if (end - p < 7)
177 fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in logical screen descriptor in gif image");
178
179 info->width = safe_load_u16(p);
180 info->height = safe_load_u16(p+2);
181 if (info->width <= 0)
182 fz_throw(ctx, FZ_ERROR_FORMAT, "image width must be > 0");
183 if (info->height <= 0)
184 fz_throw(ctx, FZ_ERROR_FORMAT, "image height must be > 0");
185 if (info->height > UINT_MAX / info->width / 3 /* components */)
186 fz_throw(ctx, FZ_ERROR_LIMIT, "image dimensions might overflow");
187
188 info->has_gct = (p[4] >> 7) & 0x1;
189 if (info->has_gct)
190 {
191 info->gct_entries = 1 << ((p[4] & 0x7) + 1);
192 info->gct_background = fz_clampi(p[5], 0, info->gct_entries - 1);
193 }
194 info->aspect = p[6];
195
196 info->xres = 96;
197 info->yres = 96;
198 if (info->aspect > 0)
199 info->yres = (((float) info->aspect + 15) / 64) * 96;
200
201 return p + 7;
202 }
203
204 static const unsigned char *
205 gif_read_gct(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
206 {
207 if (end - p < info->gct_entries * 3)
208 fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in global color table in gif image");
209
210 info->gct = Memento_label(fz_malloc(ctx, info->gct_entries * 3), "gif_gct");
211 memmove(info->gct, p, info->gct_entries * 3);
212
213 return p + info->gct_entries * 3;
214 }
215
216 static const unsigned char *
217 gif_read_id(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
218 {
219 if (end - p < 10)
220 fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in image descriptor in gif image");
221
222 info->image_left = p[2] << 8 | p[1];
223 info->image_top = p[4] << 8 | p[3];
224 info->image_width = p[6] << 8 | p[5];
225 info->image_height = p[8] << 8 | p[7];
226 info->has_lct = (p[9] >> 7) & 0x1;
227 info->image_interlaced = (p[9] >> 6) & 0x1;
228
229 if (info->has_lct)
230 info->lct_entries = 1 << ((p[9] & 0x7) + 1);
231
232 return p + 10;
233 }
234
235 static const unsigned char *
236 gif_read_lct(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
237 {
238 if (end - p < info->lct_entries * 3)
239 fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in local color table in gif image");
240
241 info->lct = Memento_label(fz_malloc(ctx, info->lct_entries * 3), "gif_lct");
242 memmove(info->lct, p, info->lct_entries * 3);
243
244 return p + info->lct_entries * 3;
245 }
246
247 static void
248 gif_read_line(fz_context *ctx, struct info *info, int ct_entries, const unsigned char *ct, unsigned int y, unsigned char *sp)
249 {
250 unsigned int index = (info->image_top + y) * info->width + info->image_left;
251 unsigned char *samples = fz_pixmap_samples(ctx, info->pix);
252 unsigned char *dp = &samples[index * 4];
253 unsigned char *mp = &info->mask[index];
254 unsigned int x, k;
255
256 if (info->image_top + y >= info->height)
257 return;
258
259 for (x = 0; x < info->image_width && info->image_left + x < info->width; x++, sp++, mp++, dp += 4)
260 if (!info->has_transparency || *sp != info->transparent)
261 {
262 *mp = 0x02;
263 for (k = 0; k < 3; k++)
264 dp[k] = ct[fz_clampi(*sp, 0, ct_entries - 1) * 3 + k];
265 dp[3] = 255;
266 }
267 else if (*mp == 0x01)
268 *mp = 0x00;
269 }
270
271 static const unsigned char *
272 gif_read_tbid(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
273 {
274 fz_stream *stm = NULL, *lzwstm = NULL;
275 unsigned int mincodesize, y;
276 fz_buffer *compressed = NULL, *uncompressed = NULL;
277 const unsigned char *ct;
278 unsigned char *sp;
279 int ct_entries;
280
281 if (end - p < 1)
282 fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in table based image data in gif image");
283
284 mincodesize = *p;
285
286 /* if there is no overlap, avoid pasting image data, just consume it */
287 if (info->image_top >= info->height || info->image_left >= info->width)
288 {
289 p = gif_read_subblocks(ctx, info, p + 1, end, NULL);
290 return p;
291 }
292
293 fz_var(compressed);
294 fz_var(lzwstm);
295 fz_var(stm);
296 fz_var(uncompressed);
297
298 fz_try(ctx)
299 {
300 compressed = fz_new_buffer(ctx, 0);
301 p = gif_read_subblocks(ctx, info, p + 1, end, compressed);
302
303 stm = fz_open_buffer(ctx, compressed);
304 lzwstm = fz_open_lzwd(ctx, stm, 0, mincodesize + 1, 1, 1);
305
306 uncompressed = fz_read_all(ctx, lzwstm, 0);
307 if (uncompressed->len < (size_t)info->image_width * info->image_height)
308 {
309 fz_warn(ctx, "premature end in compressed table based image data in gif image");
310 while (uncompressed->len < (size_t)info->image_width * info->image_height)
311 fz_append_byte(ctx, uncompressed, 0x00);
312 }
313
314 if (info->has_lct)
315 {
316 ct = info->lct;
317 ct_entries = info->lct_entries;
318 }
319 else if (info->has_gct)
320 {
321 ct = info->gct;
322 ct_entries = info->gct_entries;
323 }
324 else
325 {
326 ct = dct;
327 ct_entries = 256;
328 }
329
330 sp = uncompressed->data;
331 if (info->image_interlaced)
332 {
333 for (y = 0; y < info->image_height; y += 8, sp += info->image_width)
334 gif_read_line(ctx, info, ct_entries, ct, y, sp);
335 for (y = 4; y < info->image_height; y += 8, sp += info->image_width)
336 gif_read_line(ctx, info, ct_entries, ct, y, sp);
337 for (y = 2; y < info->image_height; y += 4, sp += info->image_width)
338 gif_read_line(ctx, info, ct_entries, ct, y, sp);
339 for (y = 1; y < info->image_height; y += 2, sp += info->image_width)
340 gif_read_line(ctx, info, ct_entries, ct, y, sp);
341 }
342 else
343 for (y = 0; y < info->image_height; y++, sp += info->image_width)
344 gif_read_line(ctx, info, ct_entries, ct, y, sp);
345 }
346 fz_always(ctx)
347 {
348 fz_drop_buffer(ctx, uncompressed);
349 fz_drop_buffer(ctx, compressed);
350 fz_drop_stream(ctx, lzwstm);
351 fz_drop_stream(ctx, stm);
352 }
353 fz_catch(ctx)
354 {
355 fz_rethrow(ctx);
356 }
357
358 return p;
359 }
360
361 static const unsigned char *
362 gif_read_gce(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
363 {
364 if (end - p < 8)
365 fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in graphic control extension in gif image");
366 if (p[2] != 0x04)
367 fz_throw(ctx, FZ_ERROR_FORMAT, "out of range graphic control extension block size in gif image");
368
369 info->has_transparency = p[3] & 0x1;
370 if (info->has_transparency)
371 info->transparent = p[6];
372
373 return p + 8;
374 }
375
376 static const unsigned char *
377 gif_read_ce(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
378 {
379 return gif_read_subblocks(ctx, info, p + 2, end, NULL);
380 }
381
382 static const unsigned char*
383 gif_read_pte(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
384 {
385 if (end - p < 15)
386 fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in plain text extension in gif image");
387 if (p[2] != 0x0c)
388 fz_throw(ctx, FZ_ERROR_FORMAT, "out of range plain text extension block size in gif image");
389 return gif_read_subblocks(ctx, info, p + 15, end, NULL);
390 }
391
392 static const unsigned char *
393 gif_read_icc(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
394 {
395 #if FZ_ENABLE_ICC
396 fz_colorspace *icc = NULL;
397 fz_buffer *buf = NULL;
398
399 fz_var(p);
400
401 buf = fz_new_buffer(ctx, 0);
402 fz_try(ctx)
403 {
404 p = gif_read_subblocks(ctx, info, p, end, buf);
405 icc = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_RGB, 0, NULL, buf);
406 fz_drop_colorspace(ctx, info->pix->colorspace);
407 info->pix->colorspace = icc;
408 }
409 fz_always(ctx)
410 fz_drop_buffer(ctx, buf);
411 fz_catch(ctx)
412 {
413 fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
414 fz_report_error(ctx);
415 fz_warn(ctx, "ignoring embedded ICC profile in GIF");
416 }
417
418 return p;
419 #else
420 return gif_read_subblocks(ctx, info, p, end, NULL);
421 #endif
422 }
423
424 /*
425 NETSCAPE2.0
426 http://odur.let.rug.nl/~kleiweg/gif/netscape.html
427 http://www.vurdalakov.net/misc/gif/netscape-looping-application-extension
428 http://www.vurdalakov.net/misc/gif/netscape-buffering-application-extension
429 https://code.google.com/p/gifdotnet/source/browse/src/GifDotNet/GifApplicationExtensionBlock.cs#95
430 http://trac.webkit.org/browser/trunk/Source/WebCore/platform/image-decoders/gif/GIFImageReader.cpp#L617
431
432 ANIMEXTS1.0
433 http://www.vurdalakov.net/misc/gif/animexts-looping-application-extension
434 https://code.google.com/p/gifdotnet/source/browse/src/GifDotNet/GifApplicationExtensionBlock.cs#95
435
436 ICCRGBG1012
437 http://www.color.org/icc1V42.pdf
438
439 XMP DataXMP
440 http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf
441
442 fractint
443 http://fractint.net/fractsvn/trunk/fractint/common/loadfile.c
444
445 ZGATEXTI5 ZGATILEI5 ZGACTRLI5 ZGANPIMGI5
446 ZGAVECTI5 ZGAALPHAI5 ZGATITLE4.0 ZGATEXTI4.0
447 Zoner GIF animator 4.0 and 5.0
448 */
449 static const unsigned char *
450 gif_read_ae(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
451 {
452 static char *ignorable[] = {
453 "NETSACPE2.0", "ANIMEXTS1.0", "XMP DataXMP",
454 "ZGATEXTI5\0\0", "ZGATILEI5\0\0", "ZGANPIMGI5\0", "ZGACTRLI5\0\0",
455 "ZGAVECTI5\0\0", "ZGAALPHAI5\0", "ZGATITLE4.0", "ZGATEXTI4.0",
456 };
457 int i, ignored;
458
459 if (end - p < 14)
460 fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in application extension in gif image");
461 if (p[2] != 0x0b)
462 fz_throw(ctx, FZ_ERROR_FORMAT, "out of range application extension block size in gif image");
463
464 ignored = 0;
465 for (i = 0; i < (int)nelem(ignorable); i++)
466 ignored |= memcmp(&p[3], ignorable[i], 8 + 3);
467 if (!ignored)
468 {
469 char extension[9];
470 memmove(extension, &p[3], 8);
471 extension[8] = '\0';
472 fz_warn(ctx, "ignoring unsupported application extension '%s' in gif image", extension);
473 }
474
475 if (!memcmp(&p[3], "ICCRGBG1012", 11))
476 return gif_read_icc(ctx, info, p + 14, end);
477
478 return gif_read_subblocks(ctx, info, p + 14, end, NULL);
479 }
480
481 static void
482 gif_mask_transparency(fz_context *ctx, struct info *info)
483 {
484 unsigned char *mp = info->mask;
485 unsigned char *dp = fz_pixmap_samples(ctx, info->pix);
486 unsigned int x, y;
487
488 for (y = 0; y < info->height; y++)
489 for (x = 0; x < info->width; x++, mp++, dp += 4)
490 if (*mp == 0x00)
491 dp[3] = 0;
492 }
493
494 static fz_pixmap *
495 gif_read_image(fz_context *ctx, struct info *info, const unsigned char *p, size_t total, int only_metadata)
496 {
497 const unsigned char *end = p + total;
498
499 memset(info, 0x00, sizeof (*info));
500
501 /* Read header */
502 p = gif_read_header(ctx, info, p, end);
503
504 /* Read logical screen descriptor */
505 p = gif_read_lsd(ctx, info, p, end);
506
507 if (only_metadata)
508 return NULL;
509
510 info->pix = fz_new_pixmap(ctx, fz_device_rgb(ctx), info->width, info->height, NULL, 1);
511
512 fz_try(ctx)
513 {
514 info->mask = fz_calloc(ctx, (size_t)info->width * info->height, 1);
515
516 /* Read optional global color table */
517 if (info->has_gct)
518 {
519 unsigned char *bp, *dp = fz_pixmap_samples(ctx, info->pix);
520 unsigned int x, y, k;
521
522 p = gif_read_gct(ctx, info, p, end);
523 bp = &info->gct[info->gct_background * 3];
524
525 memset(info->mask, 0x01, (size_t)info->width * info->height);
526
527 for (y = 0; y < info->height; y++)
528 for (x = 0; x < info->width; x++, dp += 4)
529 {
530 for (k = 0; k < 3; k++)
531 dp[k] = bp[k];
532 dp[3] = 255;
533 }
534 }
535
536 while (1)
537 {
538 /* Read block indicator */
539 if (end - p < 1)
540 fz_throw(ctx, FZ_ERROR_FORMAT, "premature end of block indicator in gif image");
541
542 /* Read trailer */
543 if (p[0] == 0x3b)
544 {
545 break;
546 }
547 /* Read extension */
548 else if (p[0] == 0x21)
549 {
550 /* Read extension label */
551 if (end - p < 2)
552 fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in extension label in gif image");
553
554 if (p[1] == 0x01 && info->gif89a)
555 {
556 /* Read plain text extension */
557 p = gif_read_pte(ctx, info, p, end);
558
559 /* Graphic control extension applies only to the graphic rendering block following it */
560 info->transparent = 0;
561 info->has_transparency = 0;
562 }
563 else if (p[1] == 0xf9 && info->gif89a)
564 /* Read graphic control extension */
565 p = gif_read_gce(ctx, info, p, end);
566 else if (p[1] == 0xfe && info->gif89a)
567 /* Read comment extension */
568 p = gif_read_ce(ctx, info, p, end);
569 else if (p[1] == 0xff && info->gif89a)
570 /* Read application extension */
571 p = gif_read_ae(ctx, info, p, end);
572 else
573 {
574 fz_warn(ctx, "ignoring unsupported extension label %02x in gif image", p[1]);
575 p = gif_read_subblocks(ctx, info, p + 2, end, NULL);
576 }
577 }
578 /* Read image descriptor */
579 else if (p[0] == 0x2c)
580 {
581 p = gif_read_id(ctx, info, p, end);
582
583 if (info->has_lct)
584 /* Read local color table */
585 p = gif_read_lct(ctx, info, p, end);
586
587 /* Read table based image data */
588 p = gif_read_tbid(ctx, info, p, end);
589
590 /* Graphic control extension applies only to the graphic rendering block following it */
591 info->transparent = 0;
592 info->has_transparency = 0;
593
594 /* Image descriptor applies only to the table based image data following it */
595 info->image_left = info->image_top = 0;
596 info->image_width = info->width;
597 info->image_height = info->height;
598 info->image_interlaced = 0;
599 fz_free(ctx, info->lct);
600 info->lct = NULL;
601 info->has_lct = 0;
602 }
603 else
604 fz_throw(ctx, FZ_ERROR_FORMAT, "unsupported block indicator %02x in gif image", p[0]);
605 }
606
607 gif_mask_transparency(ctx, info);
608 fz_premultiply_pixmap(ctx, info->pix);
609 }
610 fz_always(ctx)
611 {
612 fz_free(ctx, info->mask);
613 fz_free(ctx, info->lct);
614 fz_free(ctx, info->gct);
615 }
616 fz_catch(ctx)
617 {
618 fz_drop_pixmap(ctx, info->pix);
619 fz_rethrow(ctx);
620 }
621
622 return info->pix;
623 }
624
625 fz_pixmap *
626 fz_load_gif(fz_context *ctx, const unsigned char *p, size_t total)
627 {
628 fz_pixmap *image;
629 struct info gif;
630
631 image = gif_read_image(ctx, &gif, p, total, 0);
632 image->xres = gif.xres;
633 image->yres = gif.yres;
634
635 return image;
636 }
637
638 void
639 fz_load_gif_info(fz_context *ctx, const unsigned char *p, size_t total, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep)
640 {
641 struct info gif;
642
643 gif_read_image(ctx, &gif, p, total, 1);
644 *cspacep = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
645 *wp = gif.width;
646 *hp = gif.height;
647 *xresp = gif.xres;
648 *yresp = gif.yres;
649 }