source: trunk/JPGPROC/source/gbmsrc/gbmgif.c@ 2

Last change on this file since 2 was 2, checked in by stevenhl, 8 years ago

Import sources from cwmm-full.zip dated 2005-03-21

File size: 20.5 KB
Line 
1/*
2
3gbmgif.c - Graphics Interchange Format support
4
5Input options: index=# to get a given image in the file
6Output options: xscreen=#,yscreen=#,background=#,xpos=#,ypos=#,transcol=#,ilace.
7
8Fixed bugs in LZW compressor.
91. Don't need to write 'tail' at end, if no unprocessed input.
102. Writing 'tail' at end may increase code size.
11
12*/
13
14/*...sincludes:0:*/
15#include <stdio.h>
16#include <ctype.h>
17#include <stddef.h>
18#include <stdlib.h>
19#include <string.h>
20#include "gbm.h"
21#include "gbmhelp.h"
22
23/*...vgbm\46\h:0:*/
24/*...vgbmhelp\46\h:0:*/
25/*...e*/
26
27/*...suseful:0:*/
28#define low_byte(w) ((byte) ( (w)&0x00ffU) )
29#define high_byte(w) ((byte) (((unsigned)(w)&0xff00U)>>8))
30#define make_word(a,b) (((word)a) + (((word)b) << 8))
31/*...e*/
32
33static GBMFT gif_gbmft =
34 {
35 "GIF",
36 "CompuServe Graphics Interchange Format",
37 "GIF",
38 GBM_FT_R1|GBM_FT_R4|GBM_FT_R8|
39 GBM_FT_W1|GBM_FT_W4|GBM_FT_W8,
40 };
41
42#define GBM_ERR_GIF_BPP ((GBM_ERR) 1100)
43#define GBM_ERR_GIF_TERM ((GBM_ERR) 1101)
44#define GBM_ERR_GIF_CODE_SIZE ((GBM_ERR) 1102)
45#define GBM_ERR_GIF_CORRUPT ((GBM_ERR) 1103)
46#define GBM_ERR_GIF_HEADER ((GBM_ERR) 1104)
47
48typedef struct
49 {
50 BOOLEAN ilace, errok;
51 int bpp;
52 byte pal[0x100*3];
53 } GIF_PRIV;
54
55typedef unsigned int cword;
56
57/*...sstep_ilace:0:*/
58/* Pass 0 is all lines where y%8 == 0
59 Pass 1 is all lines where (y-4)%8 == 0
60 Pass 2 is all lines where (y-2)%4 == 0
61 Pass 3 is all lines where (y-1)%2 == 0
62 The complexity comes in when you realise there can be < 8 lines in total! */
63
64static int step_ilace(int y, int h, int *pass)
65 {
66 switch ( *pass )
67 {
68 case 0: y += 8; break;
69 case 1: y += 8; break;
70 case 2: y += 4; break;
71 case 3: y += 2; break;
72 }
73 if ( y < h ) return y;
74 if ( *pass == 0 ) { *pass = 1; y = 4; if ( y < h ) return y; }
75 if ( *pass == 1 ) { *pass = 2; y = 2; if ( y < h ) return y; }
76 if ( *pass == 2 ) { *pass = 3; y = 1; }
77 return y;
78 }
79/*...e*/
80
81/*...sgif_qft:0:*/
82GBM_ERR gif_qft(GBMFT *gbmft)
83 {
84 *gbmft = gif_gbmft;
85 return GBM_ERR_OK;
86 }
87/*...e*/
88/*...sgif_rhdr:0:*/
89GBM_ERR gif_rhdr(const char *fn, int fd, GBM *gbm, const char *opt)
90 {
91 GIF_PRIV *gif_priv = (GIF_PRIV *) gbm->priv;
92 byte signiture[6], scn_desc[7], image_desc[10];
93 const char *index;
94 int img = -1, img_want = 0;
95 int bits_gct;
96
97 fn=fn; /* Suppress 'unref arg' compiler warnings */
98
99 /* Discover which image in GIF file we want */
100
101 if ( (index = gbm_find_word_prefix(opt, "index=")) != NULL )
102 sscanf(index + 6, "%u", &img_want);
103
104 gif_priv->errok = ( gbm_find_word(opt, "errok") != NULL );
105
106 /* Read and validate signiture block */
107
108 if ( gbm_file_read(fd, signiture, 6) != 6 )
109 return GBM_ERR_READ;
110 if ( memcmp(signiture, "GIF87a", 6) &&
111 memcmp(signiture, "GIF89a", 6) )
112 return GBM_ERR_BAD_MAGIC;
113
114 /* Read screen descriptor */
115
116 if ( gbm_file_read(fd, scn_desc, 7) != 7 )
117 return GBM_ERR_READ;
118 gif_priv->bpp = bits_gct = (scn_desc[4] & 7) + 1;
119
120 if ( scn_desc[4] & 0x80 )
121 /* Global colour table follows screen descriptor */
122 {
123 if ( gbm_file_read(fd, gif_priv->pal, 3 << bits_gct) != (3 << bits_gct) )
124 return GBM_ERR_READ;
125 }
126 else
127 /* Blank out palette, but make entry 1 white */
128 {
129 memset(gif_priv->pal, 0, 3 << bits_gct);
130 gif_priv->pal[3] =
131 gif_priv->pal[4] =
132 gif_priv->pal[5] = 0xff;
133 }
134
135 /* Expected image descriptors / extension blocks / terminator */
136
137 while ( img < img_want )
138 {
139 if ( gbm_file_read(fd, image_desc, 1) != 1 )
140 return GBM_ERR_READ;
141 switch ( image_desc[0] )
142 {
143/*...s0x2c \45\ image descriptor:24:*/
144case 0x2c:
145 if ( gbm_file_read(fd, image_desc + 1, 9) != 9 )
146 return GBM_ERR_READ;
147 gbm->w = make_word(image_desc[5], image_desc[6]);
148 gbm->h = make_word(image_desc[7], image_desc[8]);
149 gif_priv->ilace = ( (image_desc[9] & 0x40) != 0 );
150
151 if ( image_desc[9] & 0x80 )
152 /* Local colour table follows */
153 {
154 gif_priv->bpp = (image_desc[9] & 7) + 1;
155 if ( gbm_file_read(fd, gif_priv->pal, 3 << gif_priv->bpp) != (3 << gif_priv->bpp) )
156 return GBM_ERR_READ;
157 }
158
159 if ( ++img != img_want )
160 /* Skip the image data */
161 {
162 byte code_size, block_size;
163
164 if ( gbm_file_read(fd, &code_size, 1) != 1 )
165 return GBM_ERR_READ;
166 do
167 {
168 if ( gbm_file_read(fd, &block_size, 1) != 1 )
169 return GBM_ERR_READ;
170 gbm_file_lseek(fd, block_size, SEEK_CUR);
171 }
172 while ( block_size );
173 }
174
175 break;
176/*...e*/
177/*...s0x21 \45\ extension block:24:*/
178/* Ignore all extension blocks */
179
180case 0x21:
181 {
182 byte func_code, byte_count;
183
184 if ( gbm_file_read(fd, &func_code, 1) != 1 )
185 return GBM_ERR_READ;
186 do
187 {
188 if ( gbm_file_read(fd, &byte_count, 1) != 1 )
189 return GBM_ERR_READ;
190 gbm_file_lseek(fd, byte_count, SEEK_CUR);
191 }
192 while ( byte_count );
193 }
194 break;
195/*...e*/
196/*...s0x3b \45\ terminator:24:*/
197/* Oi, we were hoping to get an image descriptor! */
198
199case 0x3b:
200 return GBM_ERR_GIF_TERM;
201/*...e*/
202/*...sdefault:24:*/
203default:
204 return GBM_ERR_GIF_HEADER;
205/*...e*/
206 }
207 }
208
209 switch ( gif_priv->bpp )
210 {
211 case 1: gbm->bpp = 1; break;
212 case 2:
213 case 3:
214 case 4: gbm->bpp = 4; break;
215 case 5:
216 case 6:
217 case 7:
218 case 8: gbm->bpp = 8; break;
219 default: return GBM_ERR_GIF_BPP;
220 }
221
222 return GBM_ERR_OK;
223 }
224/*...e*/
225/*...sgif_rpal:0:*/
226GBM_ERR gif_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
227 {
228 GIF_PRIV *gif_priv = (GIF_PRIV *) gbm->priv;
229 byte *pal = gif_priv->pal;
230 int i;
231
232 fd=fd; /* Suppress 'unref arg' compiler warning */
233
234 memset(gbmrgb, 0x80, (sizeof(GBMRGB) << gbm->bpp));
235
236 for ( i = 0; i < (1 << gif_priv->bpp); i++ )
237 {
238 gbmrgb[i].r = *pal++;
239 gbmrgb[i].g = *pal++;
240 gbmrgb[i].b = *pal++;
241 }
242
243 return GBM_ERR_OK;
244 }
245/*...e*/
246/*...sgif_rdata:0:*/
247/*...sread context:0:*/
248typedef struct
249 {
250 int fd; /* File descriptor to read */
251 int inx, size; /* Index and size in bits */
252 byte buf[255+3]; /* Buffer holding bits */
253 int code_size; /* Number of bits to return at once */
254 cword read_mask; /* 2^code_size-1 */
255 } READ_CONTEXT;
256
257static cword read_code(READ_CONTEXT *c)
258 {
259 dword raw_code; int byte_inx;
260
261 while ( c->inx + c->code_size > c->size )
262/*...snot enough bits in buffer\44\ refill it:16:*/
263/* Not very efficient, but infrequently called */
264
265{
266int bytes_to_lose = ((unsigned) c->inx >> 3);
267byte bytes;
268
269/* Note biggest code size is 12 bits */
270/* And this can at worst span 3 bytes */
271memcpy(c->buf, c->buf + bytes_to_lose, 3);
272(c->inx) &= 7;
273(c->size) -= (bytes_to_lose << 3);
274if ( gbm_file_read(c->fd, &bytes, 1) != 1 )
275 return 0xffff;
276if ( gbm_file_read(c->fd, c->buf + ((unsigned) c->size >> 3), bytes) != bytes )
277 return 0xffff;
278(c->size) += (bytes << 3);
279}
280/*...e*/
281
282 byte_inx = ((unsigned) c->inx >> 3);
283 raw_code = c->buf[byte_inx] + ((c->buf[byte_inx + 1]) << 8);
284 if ( c->code_size > 8 )
285 raw_code += ((c->buf[byte_inx + 2]) << 16);
286 raw_code >>= ((c->inx) & 7U);
287 (c->inx) += (byte) (c->code_size);
288
289 return (cword) raw_code & c->read_mask;
290 }
291/*...e*/
292/*...soutput context:0:*/
293typedef struct
294 {
295 int x, y, w, h, bpp, pass;
296 BOOLEAN ilace;
297 int stride;
298 byte *data, *data_this_line;
299 } OUTPUT_CONTEXT;
300
301static void output(byte value, OUTPUT_CONTEXT *o)
302 {
303 if ( o->y >= o->h )
304 return;
305
306 switch ( o->bpp )
307 {
308 case 1:
309 if ( (o->x) & 7U )
310 o->data_this_line[(unsigned)(o->x) >> 3] |= (value << (7 - (((unsigned)o->x) & 7U)));
311 else
312 o->data_this_line[(unsigned)(o->x) >> 3] = (value << 7);
313 break;
314 case 4:
315 if ( (o->x) & 1U )
316 o->data_this_line[(unsigned)(o->x) >> 1] |= value;
317 else
318 o->data_this_line[(unsigned)(o->x) >> 1] = (value << 4);
319 break;
320 case 8:
321 o->data_this_line[o->x] = value;
322 break;
323 }
324
325 if ( ++(o->x) < o->w )
326 return;
327
328 o->x = 0;
329 if ( o->ilace )
330 {
331 o->y = step_ilace(o->y, o->h, &(o->pass));
332 o->data_this_line = o->data + (o->h - 1 - o->y) * o->stride;
333 }
334 else
335 {
336 (o->y)++;
337 o->data_this_line -= (o->stride);
338 }
339 }
340/*...e*/
341
342GBM_ERR gif_rdata(int fd, GBM *gbm, byte *data)
343 {
344 GIF_PRIV *gif_priv = (GIF_PRIV *) gbm->priv;
345 byte min_code_size; /* As read from the file */
346 int init_code_size; /* Initial code size */
347 cword max_code; /* 1 << code_size */
348 cword clear_code; /* Code to clear table */
349 cword eoi_code; /* End of information code */
350 cword first_free_code; /* First free code */
351 cword free_code; /* Next available free code slot */
352 word bit_mask; /* Output pixel mask */
353 int i, out_count = 0;
354 cword code, cur_code, old_code, in_code, fin_char;
355 cword *prefix, *suffix, *outcode;
356 READ_CONTEXT c;
357 OUTPUT_CONTEXT o;
358 BOOLEAN table_full = FALSE; /* To help implement deferred clear */
359
360 if ( (prefix = (cword *) malloc((size_t) (4096 * sizeof(cword)))) == NULL )
361 return GBM_ERR_MEM;
362 if ( (suffix = (cword *) malloc((size_t) (4096 * sizeof(cword)))) == NULL )
363 {
364 free(prefix);
365 return GBM_ERR_MEM;
366 }
367 if ( (outcode = (cword *) malloc((size_t) (4097 * sizeof(cword)))) == NULL )
368 {
369 free(suffix);
370 free(prefix);
371 return GBM_ERR_MEM;
372 }
373
374 if ( gbm_file_read(fd, &min_code_size, 1) != 1 )
375 {
376 free(outcode);
377 free(suffix);
378 free(prefix);
379 return GBM_ERR_READ;
380 }
381
382 if ( min_code_size < 2 || min_code_size > 9 )
383 {
384 free(outcode);
385 free(suffix);
386 free(prefix);
387 return GBM_ERR_GIF_CODE_SIZE;
388 }
389
390 /* Initial read context */
391
392 c.inx = 0;
393 c.size = 0;
394 c.fd = fd;
395 c.code_size = min_code_size + 1;
396 c.read_mask = (cword) (( 1 << c.code_size ) - 1);
397
398 /* Initialise pixel-output context */
399
400 o.x = 0;
401 o.y = 0;
402 o.pass = 0;
403 o.w = gbm->w;
404 o.h = gbm->h;
405 o.bpp = gbm->bpp;
406 o.ilace = gif_priv->ilace;
407 o.stride = ( (gbm->w * gbm->bpp + 31) / 32 ) * 4;
408 o.data = data;
409 o.data_this_line = data + (gbm->h - 1) * o.stride;
410
411 bit_mask = (word) ((1 << gif_priv->bpp) - 1);
412
413 /* 2^min_code size accounts for all colours in file */
414
415 clear_code = (cword) ( 1 << min_code_size );
416 eoi_code = (cword) (clear_code + 1);
417 free_code = first_free_code = (cword) (clear_code + 2);
418
419 /* 2^(min_code_size+1) includes clear and eoi code and space too */
420
421 init_code_size = c.code_size;
422 max_code = (cword) ( 1 << c.code_size );
423
424 while ( o.y < o.h && (code = read_code(&c)) != eoi_code && code != 0xffff )
425 {
426 if ( code == clear_code )
427 {
428 c.code_size = init_code_size;
429 max_code = (cword) ( 1 << c.code_size );
430 c.read_mask = (cword) (max_code - 1);
431 free_code = first_free_code;
432 cur_code = old_code = code = read_code(&c);
433 if ( code == 0xffff )
434 break;
435 if ( code & ~bit_mask )
436 {
437 free(outcode);
438 free(suffix);
439 free(prefix);
440 return gif_priv->errok ? GBM_ERR_OK : GBM_ERR_GIF_CORRUPT;
441 }
442 fin_char = (cur_code & bit_mask);
443 output((byte) fin_char, &o);
444 table_full = FALSE;
445 }
446 else
447 {
448 cur_code = in_code = code;
449 if ( cur_code >= free_code )
450 {
451 cur_code = old_code;
452 outcode[out_count++] = fin_char;
453 }
454 while ( cur_code > bit_mask )
455 {
456 if ( out_count > 4096 )
457 {
458 free(outcode);
459 free(suffix);
460 free(prefix);
461 return gif_priv->errok ? GBM_ERR_OK : GBM_ERR_GIF_CORRUPT;
462 }
463 outcode[out_count++] = suffix[cur_code];
464 cur_code = prefix[cur_code];
465 }
466 fin_char = (cur_code & bit_mask);
467 outcode[out_count++] = fin_char;
468 for ( i = out_count - 1; i >= 0; i-- )
469 output((byte) outcode[i], &o);
470 out_count = 0;
471
472 /* Update dictionary */
473
474 if ( !table_full )
475 {
476 prefix[free_code] = old_code;
477 suffix[free_code] = fin_char;
478
479 /* Advance to next free slot */
480
481 if ( ++free_code >= max_code )
482 {
483 if ( c.code_size < 12 )
484 {
485 c.code_size++;
486 max_code <<= 1;
487 c.read_mask = (cword) (( 1 << c.code_size ) - 1);
488 }
489 else
490 table_full = TRUE;
491 }
492 }
493 old_code = in_code;
494 }
495 }
496
497 free(outcode);
498 free(suffix);
499 free(prefix);
500
501 if ( o.y < o.h && code == 0xffff )
502 /* If ran out of data and hadn't got to the end */
503 return gif_priv->errok ? GBM_ERR_OK : GBM_ERR_READ;
504
505 return GBM_ERR_OK;
506 }
507/*...e*/
508/*...sgif_w:0:*/
509/*
510We won't write any GIF89a or higher extensions into file.
511Write palette as global colour table, not local.
512*/
513
514/*...swrite context:0:*/
515typedef struct
516 {
517 int fd; /* Open file descriptor to write to */
518 int inx; /* Bit index into buf */
519 int code_size; /* Code size in bits */
520 byte buf[255+2]; /* Biggest block + overflow space */
521 } WRITE_CONTEXT;
522
523static BOOLEAN write_code(cword code, WRITE_CONTEXT *w)
524 {
525 byte *buf = w->buf + ((unsigned)w->inx >> 3);
526
527 code <<= ((w->inx) & 7);
528 *buf++ |= (byte) code ;
529 *buf++ = (byte) (code >> 8);
530 *buf = (byte) (code >> 16);
531
532 (w->inx) += (w->code_size);
533 if ( w->inx >= 255 * 8 )
534 /* Flush out full buffer */
535 {
536 byte bytes = 255;
537
538 if ( gbm_file_write(w->fd, &bytes, 1) != 1 )
539 return FALSE;
540 if ( gbm_file_write(w->fd, w->buf, 255) != 255 )
541 return FALSE;
542
543 memcpy(w->buf, w->buf + 255, 2);
544 memset(w->buf + 2, 0, 255);
545 (w->inx) -= (255 * 8);
546 }
547
548 return TRUE;
549 }
550
551static BOOLEAN flush_code(WRITE_CONTEXT *w)
552 {
553 byte bytes = ((unsigned)(w->inx + 7) >> 3);
554
555 if ( bytes )
556 {
557 if ( gbm_file_write(w->fd, &bytes, 1) != 1 )
558 return FALSE;
559 if ( gbm_file_write(w->fd, w->buf, bytes) != bytes )
560 return FALSE;
561 }
562
563 /* Data block terminator - a block of zero size */
564
565 bytes = 0;
566 return gbm_file_write(w->fd, &bytes, 1) == 1;
567 }
568/*...e*/
569
570typedef struct { cword tail; byte col; } DICT;
571
572GBM_ERR gif_w(const char *fn, int fd, const GBM *gbm, const GBMRGB *gbmrgb, const byte *data, const char *opt)
573 {
574 int xpos = 0, ypos = 0;
575 int xscreen = gbm->w, yscreen = gbm->h;
576 int inx_background = 0, inx_transcol = -1;
577 BOOLEAN ilace;
578
579/*...shandle options:8:*/
580{
581const char *s;
582
583fn=fn; /* Suppress 'unref arg' compiler warnings */
584
585if ( gbm->bpp != 1 && gbm->bpp != 4 && gbm->bpp != 8 )
586 return GBM_ERR_NOT_SUPP;
587
588ilace = ( gbm_find_word(opt, "ilace") != NULL );
589
590if ( (s = gbm_find_word_prefix(opt, "xscreen=")) != NULL )
591 sscanf(s + 8, "%d", &xscreen);
592
593if ( (s = gbm_find_word_prefix(opt, "yscreen=")) != NULL )
594 sscanf(s + 8, "%d", &yscreen);
595
596if ( (s = gbm_find_word_prefix(opt, "background=")) != NULL )
597 sscanf(s + 11, "%d", &inx_background);
598
599if ( (s = gbm_find_word_prefix(opt, "xpos=")) != NULL )
600 sscanf(s + 5, "%d", &xpos);
601
602if ( (s = gbm_find_word_prefix(opt, "ypos=")) != NULL )
603 sscanf(s + 5, "%d", &ypos);
604
605if ( (s = gbm_find_word_prefix(opt, "transcol=")) != NULL )
606 {
607 if ( gbm_same(s+9, "edge", 4) )
608 switch ( gbm->bpp )
609 {
610 case 8: inx_transcol = *data; break;
611 case 4: inx_transcol = *data >> 4; break;
612 case 1: inx_transcol = *data >> 7; break;
613 }
614 else
615 sscanf(s + 9, "%d", &inx_transcol);
616 }
617}
618/*...e*/
619/*...swrite header etc\46\:8:*/
620{
621byte scn_desc[7], image_desc[10]; int p;
622char *sig = ( inx_transcol != -1 ) ? "GIF89a" : "GIF87a";
623
624/* Write signiture */
625
626if ( gbm_file_write(fd, sig, 6) != 6 )
627 return GBM_ERR_WRITE;
628
629/* Write screen descriptor */
630
631scn_desc[0] = low_byte(xscreen);
632scn_desc[1] = high_byte(xscreen);
633scn_desc[2] = low_byte(yscreen);
634scn_desc[3] = high_byte(yscreen);
635scn_desc[4] = (0x80 | ((gbm->bpp - 1) * 0x11));
636 /* Global colour table follows */
637 /* Quality bpp == gct bpp == gbm->bpp */
638scn_desc[5] = (byte) inx_background;
639scn_desc[6] = 0;
640if ( gbm_file_write(fd, scn_desc, 7) != 7 )
641 return GBM_ERR_WRITE;
642
643/* Write global colour table */
644
645for ( p = 0; p < (1 << gbm->bpp); p++ )
646 {
647 byte pal[3];
648
649 pal[0] = gbmrgb[p].r;
650 pal[1] = gbmrgb[p].g;
651 pal[2] = gbmrgb[p].b;
652 if ( gbm_file_write(fd, pal, 3) != 3 )
653 return GBM_ERR_WRITE;
654 }
655
656if ( inx_transcol != -1 )
657 /* Do GIF89a "Graphic Control Extension" application extension block */
658 {
659 char gce[8];
660 gce[0] = 0x21; /* Extension Introducer */
661 gce[1] = (char) 0xf9; /* Graphic Control Label */
662 gce[2] = 4; /* Block size */
663 gce[3] = 0x01; /* No 'disposal', no 'user input' */
664 /* Just transparent index present */
665 gce[4] = 0; /* Delay time, 0 => not set */
666 gce[5] = 0; /* Delay time, 0 => not set */
667 gce[6] = (char) inx_transcol; /* Transparent colour index */
668 gce[7] = 0; /* Block size, 0 => end of extension */
669 if ( gbm_file_write(fd, gce, 8) != 8 )
670 return GBM_ERR_WRITE;
671 }
672
673/* Do image descriptor block */
674
675image_desc[0] = (byte) 0x2c;
676image_desc[1] = low_byte(xpos);
677image_desc[2] = high_byte(xpos);
678image_desc[3] = low_byte(ypos);
679image_desc[4] = high_byte(ypos);
680image_desc[5] = low_byte(gbm->w);
681image_desc[6] = high_byte(gbm->w);
682image_desc[7] = low_byte(gbm->h);
683image_desc[8] = high_byte(gbm->h);
684image_desc[9] = gbm->bpp - 1;
685 /* Non-interlaced, no local colour map, no sorted palette */
686if ( ilace )
687 image_desc[9] |= 0x40; /* Interlaced */
688if ( gbm_file_write(fd, image_desc, 10) != 10 )
689 return GBM_ERR_WRITE;
690}
691/*...e*/
692/*...sLZW encode data\44\ tail\43\col lookup version:8:*/
693/*
694hashvalue is calculated from a string of pixels cumulatively.
695hashtable is searched starting at index hashvalue for to find the entry.
696hashtable is big enough so that MAX_HASH > 4*MAX_DICT.
697*/
698
699#define MAX_HASH 17777 /* Probably prime and > 4096 */
700#define MAX_DICT 4096 /* Dictionary size */
701#define INIT_HASH(p) (((p)+3)*301) /* Initial hash value */
702
703{
704int stride = ((gbm->w * gbm->bpp + 31) / 32) * 4;
705byte min_code_size;
706int init_code_size, x, y, pass;
707cword clear_code, eoi_code, last_code, max_code, tail;
708unsigned int hashvalue, lenstring, j;
709DICT *dict, **hashtable;
710WRITE_CONTEXT w;
711
712/* Now LZW encode data */
713
714if ( (dict = (DICT *) malloc((size_t) (MAX_DICT * sizeof(DICT)))) == NULL )
715 return GBM_ERR_MEM;
716
717if ( (hashtable = (DICT **) malloc((size_t) (MAX_HASH * sizeof(DICT *)))) == NULL )
718 {
719 free(dict);
720 return GBM_ERR_MEM;
721 }
722
723/* Initialise encoder variables */
724
725init_code_size = gbm->bpp + 1;
726if ( init_code_size == 2 )
727 /* Room for col0, col1, cc, eoi, but no others! */
728 init_code_size++;
729
730min_code_size = init_code_size - 1;
731if ( gbm_file_write(fd, &min_code_size, 1) != 1 )
732 {
733 free(hashtable);
734 free(dict);
735 return GBM_ERR_WRITE;
736 }
737
738clear_code = ( 1 << min_code_size );
739eoi_code = clear_code + 1;
740last_code = eoi_code;
741max_code = ( 1 << init_code_size );
742lenstring = 0;
743
744/* Setup write context */
745
746w.fd = fd;
747w.inx = 0;
748w.code_size = init_code_size;
749memset(w.buf, 0, sizeof(w.buf));
750
751if ( !write_code(clear_code, &w) )
752 {
753 free(hashtable);
754 free(dict);
755 return GBM_ERR_WRITE;
756 }
757
758for ( j = 0; j < MAX_HASH; j++ )
759 hashtable[j] = NULL;
760
761data += ( (gbm->h - 1) * stride );
762for ( y = pass = 0; y < gbm->h; )
763 {
764 const byte *pdata = data - y * stride;
765 for ( x = 0; x < gbm->w; x++ )
766 {
767 byte col;
768/*...sget col:24:*/
769switch ( gbm->bpp )
770 {
771 case 8:
772 col = *pdata++;
773 break;
774 case 4:
775 if ( x & 1 )
776 col = (*pdata++ & 0x0f);
777 else
778 col = (*pdata >> 4);
779 break;
780 default: /* must be 1 */
781 if ( (x & 7) == 7 )
782 col = (*pdata++ & 0x01);
783 else
784 col = ((*pdata >> (7-(x&7))) & 0x01);
785 break;
786 }
787/*...e*/
788/*...sLZW encode:24:*/
789if ( ++lenstring == 1 )
790 {
791 tail = col;
792 hashvalue = INIT_HASH(col);
793 }
794else
795 {
796 hashvalue *= ( col + lenstring + 4 );
797 j = ( hashvalue %= MAX_HASH );
798 while ( hashtable[j] != NULL &&
799 ( hashtable[j]->tail != tail ||
800 hashtable[j]->col != col ) )
801 if ( ++j >= MAX_HASH )
802 j = 0;
803 if ( hashtable[j] != NULL )
804 /* Found in the strings table */
805 tail = (hashtable[j]-dict);
806 else
807 /* Not found */
808 {
809 if ( !write_code(tail, &w) )
810 {
811 free(hashtable);
812 free(dict);
813 return GBM_ERR_WRITE;
814 }
815 hashtable[j] = dict + ++last_code;
816 hashtable[j]->tail = tail;
817 hashtable[j]->col = col;
818 tail = col;
819 hashvalue = INIT_HASH(col);
820 lenstring = 1;
821
822 if ( last_code >= max_code )
823 /* Next code will be written longer */
824 {
825 max_code <<= 1;
826 w.code_size++;
827 }
828 else if ( last_code >= MAX_DICT-2 )
829 /* Reset tables */
830 {
831 if ( !write_code(tail , &w) ||
832 !write_code(clear_code, &w) )
833 {
834 free(hashtable);
835 free(dict);
836 return GBM_ERR_WRITE;
837 }
838 lenstring = 0;
839 last_code = eoi_code;
840 w.code_size = init_code_size;
841 max_code = ( 1 << init_code_size );
842 for ( j = 0; j < MAX_HASH; j++ )
843 hashtable[j] = NULL;
844 }
845 }
846 }
847/*...e*/
848 }
849 if ( ilace )
850 y = step_ilace(y, gbm->h, &pass);
851 else
852 y++;
853 }
854
855free(hashtable);
856free(dict);
857
858if ( lenstring != 0 )
859 {
860 if ( !write_code(tail, &w) )
861 return GBM_ERR_WRITE;
862 if ( ++last_code >= max_code )
863 /* Next code will be written longer */
864 w.code_size++;
865 }
866
867if ( !write_code(eoi_code, &w) ||
868 !flush_code( &w) )
869 return GBM_ERR_WRITE;
870}
871/*...e*/
872/*...swrite terminator:8:*/
873{
874byte term = (byte) 0x3b;
875if ( gbm_file_write(fd, &term, 1) != 1 )
876 return GBM_ERR_WRITE;
877}
878/*...e*/
879
880 return GBM_ERR_OK;
881 }
882/*...e*/
883/*...sgif_err:0:*/
884const char *gif_err(GBM_ERR rc)
885 {
886 switch ( (int) rc )
887 {
888 case GBM_ERR_GIF_BPP:
889 return "bad bits per pixel";
890 case GBM_ERR_GIF_TERM:
891 return "terminator found before requested image descriptor";
892 case GBM_ERR_GIF_CODE_SIZE:
893 return "code size not in range 2 to 9";
894 case GBM_ERR_GIF_CORRUPT:
895 return "encoded data is corrupt";
896 case GBM_ERR_GIF_HEADER:
897 return "bad header";
898 }
899 return NULL;
900 }
901/*...e*/
Note: See TracBrowser for help on using the repository browser.