/* tiff.c * TIFF image decoding * (c) 2002 Petr 'Brain' Kulhavy * This file is a part of the Links program, released under GPL. * * Compiles in graphics mode only and only when HAVE_TIFF. */ #include "cfg.h" #ifdef G #include "links.h" #ifdef HAVE_TIFF #include #include "bits.h" struct tiff_decoder{ unsigned char *tiff_data; /* undecoded data */ int tiff_size; /* size of undecoded file */ int tiff_pos; int tiff_open; /* 1 if tiff was open, means: tiff_data, tiff_size and tiff_pos are valid */ }; void tiff_start(struct cached_image *cimg) { struct tiff_decoder * deco; deco=mem_alloc(sizeof(struct tiff_decoder)); cimg->decoder=deco; deco->tiff_size=0; deco->tiff_data=NULL; deco->tiff_open=0; deco->tiff_pos=0; } void tiff_restart(struct cached_image *cimg, unsigned char *data, int length) { struct tiff_decoder * deco=(struct tiff_decoder*)cimg->decoder; unsigned char *p; if (!deco->tiff_data) { if ((unsigned)length > MAXINT) overalloc(); p=mem_alloc(length); } else { if ((unsigned)length + (unsigned)deco->tiff_size > MAXINT) overalloc(); if ((unsigned)length + (unsigned)deco->tiff_size < (unsigned)length) overalloc(); p=mem_realloc(deco->tiff_data,deco->tiff_size+length); } deco->tiff_data=p; memcpy(deco->tiff_data+deco->tiff_size,data,length); deco->tiff_size+=length; } static toff_t tiff_size(thandle_t data) { struct cached_image *cimg=(struct cached_image *)data; struct tiff_decoder *deco=(struct tiff_decoder*)cimg->decoder; if (!deco->tiff_open)internal_error("BUG IN LIBTIFF: sizeproc called on closed file. Contact the libtiff authors.\n"); return deco->tiff_size; } static tsize_t tiff_read(thandle_t data, tdata_t dest, tsize_t count) { struct cached_image *cimg=(struct cached_image *)data; struct tiff_decoder *deco=(struct tiff_decoder*)cimg->decoder; if (!deco->tiff_open)internal_error("BUG IN LIBTIFF: readproc called on closed file. Contact the libtiff authors.\n"); if (count < 0) return 0; if (count > deco->tiff_size-deco->tiff_pos) count = deco->tiff_size-deco->tiff_pos; memcpy(dest,deco->tiff_data+deco->tiff_pos,count); deco->tiff_pos+=(int)count; return count; } static tsize_t tiff_write(thandle_t data, tdata_t dest, tsize_t count) { internal_error("BUG IN LIBTIFF: writeproc called on read-only file. Contact the libtiff authors.\n"); return 0; } static toff_t tiff_seek(thandle_t data, toff_t offset, int whence) { struct cached_image *cimg=(struct cached_image *)data; struct tiff_decoder *deco=(struct tiff_decoder*)cimg->decoder; long pos; if (!deco->tiff_open)internal_error("BUG IN LIBTIFF: seekproc called on closed file. Contact the libtiff authors.\n"); switch(whence) { case SEEK_SET: pos = offset; break; case SEEK_CUR: pos = (unsigned long)deco->tiff_pos + offset; break; case SEEK_END: pos = (unsigned long)deco->tiff_size + offset; break; default: pos = deco->tiff_pos; break; } if (pos > deco->tiff_size) pos = deco->tiff_size; if (pos < 0) pos = 0; deco->tiff_pos = (int)pos; return deco->tiff_pos; } static int tiff_close(void *data) { struct cached_image *cimg=(struct cached_image *)data; struct tiff_decoder *deco=(struct tiff_decoder*)cimg->decoder; if (!deco->tiff_open)internal_error("BUG IN LIBTIFF: closeproc called on closed file. Contact the libtiff authors.\n"); tiff_destroy_decoder(cimg); return 0; } static int tiff_mmap(thandle_t data, tdata_t *dest, toff_t *len) { struct cached_image *cimg=(struct cached_image *)data; struct tiff_decoder *deco=(struct tiff_decoder*)cimg->decoder; if (!deco->tiff_open)internal_error("BUG IN LIBTIFF: mapproc called on closed file. Contact the libtiff authors.\n"); *dest=deco->tiff_data; *len=deco->tiff_size; return 0; } static void tiff_munmap(thandle_t data, tdata_t dest, toff_t len) { struct cached_image *cimg=(struct cached_image *)data; struct tiff_decoder *deco=(struct tiff_decoder*)cimg->decoder; if (!deco->tiff_open)internal_error("BUG IN LIBTIFF: unmapproc called on closed file. Contact the libtiff authors.\n"); } static void tiff_error_handler(const char* module, const char* fmt, va_list ap) { } static void flip_buffer(void *buf, int width, int height) { if (!big_endian) { /* little endian --- ja to chci na intelu rychly!!! */ #ifdef t4c t4c* buffer=(t4c*)buf; register t4c a,b; t4c *p,*q; int i,l; for (l=0,p=buffer,q=buffer+width*(height-1);l<(height>>1);l++,q-=(width<<1)) for (i=0;i MAXINT) overalloc(); tmp=mem_alloc(w); /* tohle je pomalejsi, protoze se kopiruje pamet->pamet, pamet->pamet */ /* kdyz mame 4B typek, tak se kopiruje pamet->reg, reg->pamet */ for (l=0,p=buffer,q=buffer+w*(height-1);l<(height>>1);l++,q-=w,p+=w) memcpy(tmp,p,w),memcpy(p,q,w),memcpy(q,tmp,w); mem_free(tmp); #endif } else { /* big endian */ unsigned char zakazany_uvolneni[4]; unsigned char* buffer=(unsigned char*)buf; int w=width<<2; /* 4 bytes per pixel */ unsigned char *p,*q; int i,l; for (l=0,p=buffer,q=buffer+w*(height-1);l<(height>>1);l++,q-=(w<<1)) for (i=0;idecoder; int bla, x, y; TIFF *t; if (!deco->tiff_size){img_end(cimg);return;} deco->tiff_open=1; TIFFSetErrorHandler(tiff_error_handler); TIFFSetWarningHandler(tiff_error_handler); t=TIFFClientOpen( "Prave si rek' svy posledni slova. A vybral sis k tomu prihodny misto.", "r", cimg, (TIFFReadWriteProc)tiff_read, (TIFFReadWriteProc)tiff_write, (TIFFSeekProc)tiff_seek, (TIFFCloseProc)tiff_close, (TIFFSizeProc)tiff_size, (TIFFMapFileProc)tiff_mmap, (TIFFUnmapFileProc)tiff_munmap ); if (!t) { img_end(cimg); return; } bla = TIFFGetField(t, TIFFTAG_IMAGEWIDTH, &x); if (!bla) { TIFFClose(t); img_end(cimg); return; } cimg->width = x; bla = TIFFGetField(t, TIFFTAG_IMAGELENGTH, &y); if (!bla){ TIFFClose(t); img_end(cimg); return; } cimg->height = y; cimg->buffer_bytes_per_pixel = 4; cimg->red_gamma=cimg->green_gamma=cimg->blue_gamma=(float)sRGB_gamma; cimg->strip_optimized=0; if (header_dimensions_known(cimg)){TIFFClose(t);img_end(cimg);return;} /* int TIFFReadRGBAImage(TIFF* tif, u_long width, u_long height, u_long* raster, int stopOnError) from man page */ /*TIFFReadRGBAImage(t,cimg->width,cimg->height,(unsigned long*)(cimg->buffer),1);*/ /* 231: warning: passing arg 4 of `TIFFReadRGBAImage' from incompatible pointer type */ TIFFReadRGBAImage(t, (unsigned)cimg->width, (unsigned)cimg->height, (void *)cimg->buffer, 1); TIFFClose(t); /* For some reason the TIFFReadRGBAImage() function chooses the lower * left corner as the origin. Vertically mirror scanlines. */ flip_buffer((void*)cimg->buffer, (int)cimg->width, (int)cimg->height); img_end(cimg); } void tiff_destroy_decoder(struct cached_image *cimg) { struct tiff_decoder *deco=(struct tiff_decoder *)cimg->decoder; if (deco->tiff_data) mem_free(deco->tiff_data), deco->tiff_data = NULL; deco->tiff_open=0; } void add_tiff_version(unsigned char **s, int *l) { unsigned char *p, *pp; int pl; add_to_str(s, l, cast_uchar "TIFF ("); p = (unsigned char *)TIFFGetVersion(); pp = cast_uchar strstr(cast_const_char p, "LIBTIFF, "); if (pp) p = pp + 9; pp = cast_uchar strstr(cast_const_char p, "Version "); if (pp) p = pp + 8; pl = (int)strcspn(cast_const_char p, " \n"); add_bytes_to_str(s, l, p, pl); add_chr_to_str(s, l, ')'); } #endif /* #ifdef HAVE_TIFF */ #endif /* #ifdef G */