readgif.c (10249B)
1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <draw.h> 5 #include "imagefile.h" 6 7 typedef struct Entry Entry; 8 typedef struct Header Header; 9 10 struct Entry{ 11 int prefix; 12 int exten; 13 }; 14 15 16 struct Header{ 17 Biobuf *fd; 18 char err[256]; 19 jmp_buf errlab; 20 uchar buf[3*256]; 21 char vers[8]; 22 uchar *globalcmap; 23 int screenw; 24 int screenh; 25 int fields; 26 int bgrnd; 27 int aspect; 28 int flags; 29 int delay; 30 int trindex; 31 int loopcount; 32 Entry tbl[4096]; 33 Rawimage **array; 34 Rawimage *new; 35 36 uchar *pic; 37 }; 38 39 static char readerr[] = "ReadGIF: read error: %r"; 40 static char extreaderr[] = "ReadGIF: can't read extension: %r"; 41 static char memerr[] = "ReadGIF: malloc failed: %r"; 42 43 static Rawimage** readarray(Header*); 44 static Rawimage* readone(Header*); 45 static void readheader(Header*); 46 static void skipextension(Header*); 47 static uchar* readcmap(Header*, int); 48 static uchar* decode(Header*, Rawimage*, Entry*); 49 static void interlace(Header*, Rawimage*); 50 51 static 52 void 53 clear(void *pp) 54 { 55 void **p = (void**)pp; 56 57 if(*p){ 58 free(*p); 59 *p = nil; 60 } 61 } 62 63 static 64 void 65 giffreeall(Header *h, int freeimage) 66 { 67 int i; 68 69 if(h->fd){ 70 Bterm(h->fd); 71 h->fd = nil; 72 } 73 clear(&h->pic); 74 if(h->new){ 75 clear(&h->new->cmap); 76 clear(&h->new->chans[0]); 77 clear(&h->new); 78 } 79 clear(&h->globalcmap); 80 if(freeimage && h->array!=nil){ 81 for(i=0; h->array[i]; i++){ 82 clear(&h->array[i]->cmap); 83 clear(&h->array[i]->chans[0]); 84 } 85 clear(&h->array); 86 } 87 } 88 89 static 90 void 91 giferror(Header *h, char *fmt, ...) 92 { 93 va_list arg; 94 95 va_start(arg, fmt); 96 vseprint(h->err, h->err+sizeof h->err, fmt, arg); 97 va_end(arg); 98 99 werrstr(h->err); 100 giffreeall(h, 1); 101 longjmp(h->errlab, 1); 102 } 103 104 105 Rawimage** 106 readgif(int fd, int colorspace) 107 { 108 Rawimage **a; 109 Biobuf b; 110 Header *h; 111 char buf[ERRMAX]; 112 113 buf[0] = '\0'; 114 USED(colorspace); 115 if(Binit(&b, fd, OREAD) < 0) 116 return nil; 117 h = malloc(sizeof(Header)); 118 if(h == nil){ 119 Bterm(&b); 120 return nil; 121 } 122 memset(h, 0, sizeof(Header)); 123 h->fd = &b; 124 errstr(buf, sizeof buf); /* throw it away */ 125 if(setjmp(h->errlab)) 126 a = nil; 127 else 128 a = readarray(h); 129 giffreeall(h, 0); 130 free(h); 131 return a; 132 } 133 134 static 135 void 136 inittbl(Header *h) 137 { 138 int i; 139 Entry *tbl; 140 141 tbl = h->tbl; 142 for(i=0; i<258; i++) { 143 tbl[i].prefix = -1; 144 tbl[i].exten = i; 145 } 146 } 147 148 static 149 Rawimage** 150 readarray(Header *h) 151 { 152 Entry *tbl; 153 Rawimage *new, **array; 154 int c, nimages; 155 156 tbl = h->tbl; 157 158 readheader(h); 159 160 if(h->fields & 0x80) 161 h->globalcmap = readcmap(h, (h->fields&7)+1); 162 163 array = malloc(sizeof(Rawimage**)); 164 if(array == nil) 165 giferror(h, memerr); 166 nimages = 0; 167 array[0] = nil; 168 h->array = array; 169 170 for(;;){ 171 switch(c = Bgetc(h->fd)){ 172 case Beof: 173 goto Return; 174 175 case 0x21: /* Extension (ignored) */ 176 skipextension(h); 177 break; 178 179 case 0x2C: /* Image Descriptor */ 180 inittbl(h); 181 new = readone(h); 182 if(new->fields & 0x80){ 183 new->cmaplen = 3*(1<<((new->fields&7)+1)); 184 new->cmap = readcmap(h, (new->fields&7)+1); 185 }else{ 186 new->cmaplen = 3*(1<<((h->fields&7)+1)); 187 new->cmap = malloc(new->cmaplen); 188 memmove(new->cmap, h->globalcmap, new->cmaplen); 189 } 190 h->new = new; 191 new->chans[0] = decode(h, new, tbl); 192 if(new->fields & 0x40) 193 interlace(h, new); 194 new->gifflags = h->flags; 195 new->gifdelay = h->delay; 196 new->giftrindex = h->trindex; 197 new->gifloopcount = h->loopcount; 198 array = realloc(h->array, (nimages+2)*sizeof(Rawimage*)); 199 if(array == nil) 200 giferror(h, memerr); 201 array[nimages++] = new; 202 array[nimages] = nil; 203 h->array = array; 204 h->new = nil; 205 break; 206 207 case 0x3B: /* Trailer */ 208 goto Return; 209 210 default: 211 fprint(2, "ReadGIF: unknown block type: 0x%.2x\n", c); 212 goto Return; 213 } 214 } 215 216 Return: 217 if(array[0]==nil || array[0]->chans[0] == nil) 218 giferror(h, "ReadGIF: no picture in file"); 219 220 return array; 221 } 222 223 static 224 void 225 readheader(Header *h) 226 { 227 if(Bread(h->fd, h->buf, 13) != 13) 228 giferror(h, "ReadGIF: can't read header: %r"); 229 memmove(h->vers, h->buf, 6); 230 if(strcmp(h->vers, "GIF87a")!=0 && strcmp(h->vers, "GIF89a")!=0) 231 giferror(h, "ReadGIF: can't recognize format %s", h->vers); 232 h->screenw = h->buf[6]+(h->buf[7]<<8); 233 h->screenh = h->buf[8]+(h->buf[9]<<8); 234 h->fields = h->buf[10]; 235 h->bgrnd = h->buf[11]; 236 h->aspect = h->buf[12]; 237 h->flags = 0; 238 h->delay = 0; 239 h->trindex = 0; 240 h->loopcount = -1; 241 } 242 243 static 244 uchar* 245 readcmap(Header *h, int size) 246 { 247 uchar *map; 248 249 if(size > 8) 250 giferror(h, "ReadGIF: can't handles %d bits per pixel", size); 251 size = 3*(1<<size); 252 if(Bread(h->fd, h->buf, size) != size) 253 giferror(h, "ReadGIF: short read on color map"); 254 map = malloc(size); 255 if(map == nil) 256 giferror(h, memerr); 257 memmove(map, h->buf, size); 258 return map; 259 } 260 261 static 262 Rawimage* 263 readone(Header *h) 264 { 265 Rawimage *i; 266 int left, top, width, height; 267 268 if(Bread(h->fd, h->buf, 9) != 9) 269 giferror(h, "ReadGIF: can't read image descriptor: %r"); 270 i = malloc(sizeof(Rawimage)); 271 if(i == nil) 272 giferror(h, memerr); 273 left = h->buf[0]+(h->buf[1]<<8); 274 top = h->buf[2]+(h->buf[3]<<8); 275 width = h->buf[4]+(h->buf[5]<<8); 276 height = h->buf[6]+(h->buf[7]<<8); 277 i->fields = h->buf[8]; 278 i->r.min.x = left; 279 i->r.min.y = top; 280 i->r.max.x = left+width; 281 i->r.max.y = top+height; 282 i->nchans = 1; 283 i->chandesc = CRGB1; 284 return i; 285 } 286 287 288 static 289 int 290 readdata(Header *h, uchar *data) 291 { 292 int nbytes, n; 293 294 nbytes = Bgetc(h->fd); 295 if(nbytes < 0) 296 giferror(h, "ReadGIF: can't read data: %r"); 297 if(nbytes == 0) 298 return 0; 299 n = Bread(h->fd, data, nbytes); 300 if(n < 0) 301 giferror(h, "ReadGIF: can't read data: %r"); 302 if(n != nbytes) 303 fprint(2, "ReadGIF: short data subblock\n"); 304 return n; 305 } 306 307 static 308 void 309 graphiccontrol(Header *h) 310 { 311 if(Bread(h->fd, h->buf, 5+1) != 5+1) 312 giferror(h, readerr); 313 h->flags = h->buf[1]; 314 h->delay = h->buf[2]+(h->buf[3]<<8); 315 h->trindex = h->buf[4]; 316 } 317 318 static 319 void 320 skipextension(Header *h) 321 { 322 int type, hsize, hasdata, n; 323 uchar data[256]; 324 325 hsize = 0; 326 hasdata = 0; 327 328 type = Bgetc(h->fd); 329 switch(type){ 330 case Beof: 331 giferror(h, extreaderr); 332 break; 333 case 0x01: /* Plain Text Extension */ 334 hsize = 13; 335 hasdata = 1; 336 break; 337 case 0xF9: /* Graphic Control Extension */ 338 graphiccontrol(h); 339 return; 340 case 0xFE: /* Comment Extension */ 341 hasdata = 1; 342 break; 343 case 0xFF: /* Application Extension */ 344 hsize = Bgetc(h->fd); 345 /* standard says this must be 11, but Adobe likes to put out 10-byte ones, 346 * so we pay attention to the field. */ 347 hasdata = 1; 348 break; 349 default: 350 giferror(h, "ReadGIF: unknown extension"); 351 } 352 if(hsize>0 && Bread(h->fd, h->buf, hsize) != hsize) 353 giferror(h, extreaderr); 354 if(!hasdata) 355 return; 356 357 /* loop counter: Application Extension with NETSCAPE2.0 as string and 1 <loop.count> in data */ 358 if(type == 0xFF && hsize==11 && memcmp(h->buf, "NETSCAPE2.0", 11)==0){ 359 n = readdata(h, data); 360 if(n == 0) 361 return; 362 if(n==3 && data[0]==1) 363 h->loopcount = data[1] | (data[2]<<8); 364 } 365 while(readdata(h, data) != 0) 366 ; 367 } 368 369 static 370 uchar* 371 decode(Header *h, Rawimage *i, Entry *tbl) 372 { 373 int c, incode, codesize, CTM, EOD, pici, datai, stacki, nbits, sreg, fc, code, piclen; 374 int csize, nentry, maxentry, first, ocode, ndata, nb; 375 uchar *pic; 376 uchar stack[4096], data[256]; 377 378 if(Bread(h->fd, h->buf, 1) != 1) 379 giferror(h, "ReadGIF: can't read data: %r"); 380 codesize = h->buf[0]; 381 if(codesize>8 || 0>codesize) 382 giferror(h, "ReadGIF: can't handle codesize %d", codesize); 383 if(i->cmap!=nil && i->cmaplen!=3*(1<<codesize) 384 && (codesize!=2 || i->cmaplen!=3*2)) /* peculiar GIF bitmap files... */ 385 giferror(h, "ReadGIF: codesize %d doesn't match color map 3*%d", codesize, i->cmaplen/3); 386 387 CTM =1<<codesize; 388 EOD = CTM+1; 389 390 piclen = (i->r.max.x-i->r.min.x)*(i->r.max.y-i->r.min.y); 391 i->chanlen = piclen; 392 pic = malloc(piclen); 393 if(pic == nil) 394 giferror(h, memerr); 395 h->pic = pic; 396 pici = 0; 397 ndata = 0; 398 datai = 0; 399 nbits = 0; 400 sreg = 0; 401 fc = 0; 402 403 Loop: 404 for(;;){ 405 csize = codesize+1; 406 nentry = EOD+1; 407 maxentry = (1<<csize)-1; 408 first = 1; 409 ocode = -1; 410 411 for(;; ocode = incode) { 412 while(nbits < csize) { 413 if(datai == ndata){ 414 ndata = readdata(h, data); 415 if(ndata == 0) 416 goto Return; 417 datai = 0; 418 } 419 c = data[datai++]; 420 sreg |= c<<nbits; 421 nbits += 8; 422 } 423 code = sreg & ((1<<csize) - 1); 424 sreg >>= csize; 425 nbits -= csize; 426 427 if(code == EOD){ 428 ndata = readdata(h, data); 429 if(ndata != 0) 430 fprint(2, "ReadGIF: unexpected data past EOD"); 431 goto Return; 432 } 433 434 if(code == CTM) 435 goto Loop; 436 437 stacki = (sizeof stack)-1; 438 439 incode = code; 440 441 /* special case for KwKwK */ 442 if(code == nentry) { 443 stack[stacki--] = fc; 444 code = ocode; 445 } 446 447 if(code > nentry) 448 giferror(h, "ReadGIF: bad code %x %x", code, nentry); 449 450 for(c=code; c>=0; c=tbl[c].prefix) 451 stack[stacki--] = tbl[c].exten; 452 453 nb = (sizeof stack)-(stacki+1); 454 if(pici+nb > piclen){ 455 /* this common error is harmless 456 * we have to keep reading to keep the blocks in sync */ 457 ; 458 }else{ 459 memmove(pic+pici, stack+stacki+1, sizeof stack - (stacki+1)); 460 pici += nb; 461 } 462 463 fc = stack[stacki+1]; 464 465 if(first){ 466 first = 0; 467 continue; 468 } 469 #define early 0 /* peculiar tiff feature here for reference */ 470 if(nentry == maxentry-early) { 471 if(csize >= 12) 472 continue; 473 csize++; 474 maxentry = (1<<csize); 475 if(csize < 12) 476 maxentry--; 477 } 478 tbl[nentry].prefix = ocode; 479 tbl[nentry].exten = fc; 480 nentry++; 481 } 482 } 483 484 Return: 485 h->pic = nil; 486 return pic; 487 } 488 489 static 490 void 491 interlace(Header *h, Rawimage *image) 492 { 493 uchar *pic; 494 Rectangle r; 495 int dx, yy, y; 496 uchar *ipic; 497 498 pic = image->chans[0]; 499 r = image->r; 500 dx = r.max.x-r.min.x; 501 ipic = malloc(dx*(r.max.y-r.min.y)); 502 if(ipic == nil) 503 giferror(h, nil); 504 505 /* Group 1: every 8th row, starting with row 0 */ 506 yy = 0; 507 for(y=r.min.y; y<r.max.y; y+=8){ 508 memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx); 509 yy++; 510 } 511 512 /* Group 2: every 8th row, starting with row 4 */ 513 for(y=r.min.y+4; y<r.max.y; y+=8){ 514 memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx); 515 yy++; 516 } 517 518 /* Group 3: every 4th row, starting with row 2 */ 519 for(y=r.min.y+2; y<r.max.y; y+=4){ 520 memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx); 521 yy++; 522 } 523 524 /* Group 4: every 2nd row, starting with row 1 */ 525 for(y=r.min.y+1; y<r.max.y; y+=2){ 526 memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx); 527 yy++; 528 } 529 530 free(image->chans[0]); 531 image->chans[0] = ipic; 532 }