#pragma warn -use static char *sccsid = "@(#)TIFF/tif_picio.c 1.21, Copyright (c) Sam Leffler, Dieter Linde, "__DATE__; #pragma warn .use /* * Copyright (c) 1988, 1990 by Sam Leffler, Oct 8 1990 * All rights reserved. * * This file is provided for unrestricted use provided that this legend is included on all tape media and as a part of the * software program in whole or part. Users may copy, modify or distribute this file at will. * * TIFF Library. * * Pixar Picio RLE Algorithm Support * * NB: This algorithm is not (currently) very effective because the state is reset at each scanline. This * was done to avoid having dangling pointers into the raw data buffer that are invalidated by the flushing * that occurs in TIFFWriteScanline(). To fix this problem we need to add an encodestrip routine (to reset * state) and maintain state during decoding so that runs and such can be restarted when they cross scanline * boundaries. However, since LZW already works on a strip basis and seems to be more effective, there's * not much reason to go to the trouble. */ #include #include "tiffio.h" /* * Each image is composed of a sequence of dumps, runs, partial dumps, and partial runs. The first two * bytes of a sequence contain a flag indicator and a count. Flags are encoded in the upper 4 bits * of the first byte while the lower 12 bits contain the count. */ /* * Tile flag indicators. */ #define PT_FILL 0 /* fill input buffer */ #define PT_FULLDUMP 1 /* full dump, use count */ #define PT_FULLRUN 2 /* full run, length precedes pixel */ #define PT_PARTDUMP 3 /* part dump, alpha constant */ #define PT_PARTRUN 4 /* part run, alpha constant */ #define MAXPACKETSIZE 8 /* picio encoding state */ /* * Macros for unrolling loops. */ #define REPEAT4(n, op) switch (n) { \ case 4: \ op; \ case 3: \ op; \ case 2: \ op; \ case 1: \ op; \ } #define REPEAT8(n, op) switch (n) { \ case 8: \ op; \ case 7: \ op; \ case 6: \ op; \ case 5: \ op; \ case 4: \ op; \ case 3: \ op; \ case 2: \ op; \ case 1: \ op; \ } #define SPRAY4(nc, op) switch (nc) { \ case 4: \ op[3]; \ case 3: \ op[2]; \ case 2: \ op[1]; \ case 1: \ op[0]; \ } struct piciostate { u_char *startptr; u_char *lptr; /* pointer to length byte in run */ u_short len; /* length of run when in 16-bit mode */ short count; /* repeat count of data in packet */ short amark; /* index to alpha channel */ int type; /* 4-bit packet type */ int fulldisklength; /* size of data + alpha unit */ int infodisklength; /* size of data unit */ u_char *fulleobuffer; /* output buffer fencepost for full packet */ u_char *infoeobuffer; /* output buffer fencepost for info packet */ /*** temp buffers of data going to disk ***/ u_char disk0buffer[MAXPACKETSIZE]; u_char disk1buffer[MAXPACKETSIZE]; /*** temp buffers of data in memory ***/ u_short core0buffer[MAXPACKETSIZE / 2]; u_short core1buffer[MAXPACKETSIZE / 2]; }; static u_char *newdisk, *olddisk; static u_short *newcore, *oldcore; #pragma warn -par /**************************************************************************** * */ static int pic8DecodeScanline( TIFF *tif, register u_char *op, int cc ) { register u_char *bp, *sp, *ep; register int npixels; u_char spare[4]; short nc, flag, word, count, length; static char module[] = "PicioDecode"; bp = tif->tif_rawcp; ep = bp + tif->tif_rawcc; npixels = tif->tif_dir.td_imagewidth; nc = (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG ? tif->tif_dir.td_samplesperpixel : 1); while (bp < ep && npixels > 0) { word = (bp[1] << 8) | bp[0]; bp += 2; count = (word & 0xfff) + 1; switch (flag = (word >> 12)) { case PT_FULLRUN: while (count-- > 0) { /* * The first byte holds a count. The next bytes hold data to be repeated. */ length = (*bp++) + 1; sp = spare + nc; REPEAT4(nc, *--sp = *bp++); npixels -= length; for (sp = spare; length-- > 0;) SPRAY4(nc, *op++ = sp); } break; case PT_FULLDUMP: npixels -= count; for (count *= nc; count-- > 0; *op++ = *bp++) ; break; case PT_PARTRUN: spare[0] = *bp++; while (count-- > 0) { /* * The first byte is a count. The next bytes are data to be repeated. */ length = (*bp++) + 1; sp = spare + nc; REPEAT4(nc - 1, *--sp = *bp++); npixels -= length; for (sp = spare; length-- > 0;) SPRAY4(nc, *op++ = sp); } break; case PT_PARTDUMP: /* * The fixed value (normally alpha) is stored in the first byte. */ (sp = spare)[0] = *bp++; npixels -= count; while (count-- > 0) { REPEAT4(nc - 1, *op++ = *bp++); *op++ = sp[0]; } break; default: TIFFError(module, "%s: Unknown flag 0x%x at scanline %d", tif->tif_name, flag, tif->tif_row); return(0); } } tif->tif_rawcc -= (bp - tif->tif_rawcp); tif->tif_rawcp = bp; if (npixels > 0) { TIFFError(module, "%s: Not enough data for scanline %d", tif->tif_name, tif->tif_row); return(0); } return(1); } #pragma warn .par #pragma warn -par /**************************************************************************** * */ static int pic16DecodeScanline( TIFF *tif, register u_char *op, int cc ) { register u_char *bp, *ep; register int npixels; register u_short *sp; short nc, flag, word, count, length; u_short spare[4]; static char module[] = "PicioDecode"; bp = tif->tif_rawcp; ep = bp + tif->tif_rawcc; npixels = tif->tif_dir.td_imagewidth; nc = (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG ? tif->tif_dir.td_samplesperpixel : 1); while (bp < ep && npixels > 0) { word = (bp[1] << 8) | bp[0]; bp += 2; count = (word & 0xfff) + 1; switch (flag = (word >> 12)) { case PT_FULLRUN: while (count-- > 0) { /* * The first byte holds a count. The next bytes hold data to be repeated. */ length = ((bp[1] << 8) | bp[0]) + 1; bp += 2; sp = spare + nc; REPEAT4(nc, *--sp = bp[0]|(bp[1] << 8); bp += 2); npixels -= length; for (sp = spare; length-- > 0;) SPRAY4(nc, *((u_short *)op)++ = sp); } break; case PT_FULLDUMP: npixels -= count; while (count-- > 0) REPEAT4(nc, *((u_short *)op)++ = bp[0]|(bp[1] << 8); bp += 2); break; case PT_PARTRUN: spare[0] = bp[0]|(bp[1] << 8); bp += 2; while (count-- > 0) { /* * The first byte is a count. The next bytes are data to be repeated. */ length = ((bp[1] << 8) | bp[0]) + 1; bp += 2; sp = spare + nc; REPEAT4(nc - 1, *--sp = bp[0]|(bp[1] << 8); bp +=2); npixels -= length; for (sp = spare; length-- > 0;) SPRAY4(nc, *((u_short *)op)++ = sp); } break; case PT_PARTDUMP: /* * The fixed value (normally alpha) is stored in the first byte. */ (sp = spare)[0] = bp[0]|(bp[1] << 8); bp += 2; npixels -= count; while (count-- > 0) { REPEAT4(nc - 1, *((u_short *)op)++ = bp[0]|(bp[1] << 8); bp +=2); *((u_short *)op)++ = sp[0]; } break; default: TIFFError(module, "%s: Unknown flag 0x%x at scanline %d", tif->tif_name, flag, tif->tif_row); return(0); } } tif->tif_rawcc -= (bp - tif->tif_rawcp); tif->tif_rawcp = bp; if (npixels > 0) { TIFFError(module, "%s: Not enough data for scanline %d", tif->tif_name, tif->tif_row); return(0); } return(1); } #pragma warn .par /**************************************************************************** * */ static int PicioDecodeStrip( TIFF *tif ) { switch (tif->tif_dir.td_bitspersample) { case 8: tif->tif_decoderow = pic8DecodeScanline; break; case 16: tif->tif_decoderow = pic16DecodeScanline; break; default: TIFFError("PicioDecode", "Can't handle %d-bit pictures", tif->tif_dir.td_bitspersample); return(0); } return(1); } /**************************************************************************** * Startpacket takes the old and new pixels and starts the requested packet using them. */ static u_char * startpacket( TIFF *tif, u_char *ptr, short type ) { register struct piciostate *ps; register u_char *dp; /* * Set up packet type and count. The packet count is incremented as the data is repeated. These * two values are merged and written when ending the packet. */ ps = (struct piciostate *)tif->tif_data; if (ptr > ps->fulleobuffer) { tif->tif_rawcc += ptr - (u_char *)tif->tif_rawcp; if (!TIFFFlushData(tif)) return(NULL); ptr = (u_char *)tif->tif_rawcp; } ps->type = type; ps->count = 0; ps->startptr = ptr; ptr += 2; /* skip packet header */ switch (type) { case 0: ps->type = PT_FULLDUMP; dp = newdisk; REPEAT8(ps->fulldisklength, *ptr++ = *dp++); break; case PT_FULLDUMP: case PT_FULLRUN: if (type == PT_FULLRUN) { ps->lptr = ptr; *ptr++ = 1; if (tif->tif_dir.td_bitspersample == 16) { ps->len = 1; *ptr++ = 0; } } dp = olddisk; REPEAT8(ps->fulldisklength, *ptr++ = *dp++); break; case PT_PARTRUN: case PT_PARTDUMP: dp = olddisk + ps->infodisklength; REPEAT8(ps->fulldisklength - ps->infodisklength, *ptr++ = *dp++); if (type == PT_PARTRUN) { ps->lptr = ptr; *ptr++ = 1; if (tif->tif_dir.td_bitspersample == 16) { ps->len = 1; *ptr++ = 0; } } dp = olddisk; REPEAT8(ps->infodisklength, *ptr++ = *dp++); break; } return(ptr); } /**************************************************************************** * Set the packet header from the accumulated state information. */ static void endpacket( register struct piciostate *ps ) { ps->count |= ps->type << 12; ps->startptr[1] = ps->count >> 8; ps->startptr[0] = ps->count; } /* * Yech -- this knows about bp & runstatus. */ #define startnewbuffer(tif, pt) { \ endpacket((struct piciostate *)tif->tif_data); \ tif->tif_rawcc += bp - (u_char *)tif->tif_rawcp; \ if (!TIFFFlushData(tif)) \ return(-1); \ bp = startpacket(tif, tif->tif_rawcp, runstatus = pt); \ if (bp == NULL) \ return(-1); \ } /* * State indicators used in encoding. */ #define PT_UNKNOWN -1 #define PT_CFULLRUN -2 #define PT_STARTUP -3 #define PT_CPARTRUN -4 /* * To encode tile type + same-pixel + same-alpha into a single value, we use the following magic constants. */ #define SP_FALSE (0 * (PT_PARTRUN - PT_CPARTRUN + 1)) #define SP_TRUE (1 * (PT_PARTRUN - PT_CPARTRUN + 1)) #define SA_FALSE (2 * SP_FALSE) #define SA_TRUE (4 * SP_TRUE) /**************************************************************************** * Setup encoding state. */ static int PicioStripEncode( register TIFF *tif ) { register struct piciostate *ps; int bytespersample; if (tif->tif_data != NULL) return(1); if (tif->tif_dir.td_bitspersample != 8 && tif->tif_dir.td_bitspersample != 16) { TIFFError("PicioEncode", "Can't handle %d-bit pictures", tif->tif_dir.td_bitspersample); return(0); } if ((tif->tif_data = malloc(sizeof(struct piciostate))) == NULL) { TIFFError("PicioEncode", "No space for picio state block"); return(0); } bzero(tif->tif_data, sizeof(struct piciostate)); ps = (struct piciostate *)tif->tif_data; if (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG) { ps->fulldisklength = tif->tif_dir.td_samplesperpixel; if ((ps->infodisklength = tif->tif_dir.td_samplesperpixel) > 3) ps->infodisklength = 3; ps->amark = tif->tif_dir.td_matteing ? tif->tif_dir.td_samplesperpixel - 1 : 3; } else { ps->fulldisklength = ps->infodisklength = 1; ps->amark = 0; } bytespersample = tif->tif_dir.td_bitspersample <= 8 ? 1 : tif->tif_dir.td_bitspersample <= 16 ? 2 : 4; ps->fulldisklength *= bytespersample; ps->infodisklength *= bytespersample; /* * fulleobuffer & infoeobuffer mark the last spot in the buffer at which a packet can be placed * (either a fulldisklength or infodisklength packet). The 2+ is for the 2 byte packet type and length. */ ps->fulleobuffer = (u_char *)tif->tif_rawdata + tif->tif_rawdatasize - (2 + ps->fulldisklength) - 1; ps->infoeobuffer = (u_char *)tif->tif_rawdata + tif->tif_rawdatasize - (2 + ps->infodisklength) - 1; return(1); } /**************************************************************************** * Encode a scanline of pixels. */ static int PicioEncode( TIFF *tif, register u_char *ip, int cc ) { register u_char *bp; register struct piciostate *ps; u_char *dp, *ep; int cmpstatus, runstatus, nc, hasalphachannel; u_short *cp1, *cp2, *wp; ps = (struct piciostate *)tif->tif_data; ep = ip + cc; bp = (u_char *)tif->tif_rawcp; if (tif->tif_dir.td_planarconfig == PLANARCONFIG_CONTIG) { nc = tif->tif_dir.td_samplesperpixel; hasalphachannel = tif->tif_dir.td_matteing; } else { nc = 1; hasalphachannel = 0; } oldcore = ps->core0buffer; newcore = ps->core1buffer; olddisk = ps->disk0buffer; newdisk = ps->disk1buffer; /* * Setup initial alpha to be different. */ oldcore[ps->amark] = 0; newcore[ps->amark] = -1; /* * Process each pixel with a finite state machine with one-pixel look-ahead. The look-ahead is used to compress * identical pixels into "pixel runs". The states of encoding process include all the packet types, filled * out with a startup state (used only at startup) and an unknown state (used when we have no packet open and * do not know yet what kind of packet this last pixel will start. Also needed are temporary runlength states * which are needed, for example, when we have just finished one run in a runlength packet and do not know whether this * last pixel is the start of a new run or the start of a whole new (dump) packet. */ runstatus = PT_STARTUP; while (ip < ep) { /* * Swap pointers to new and old data buffers. */ #define SWAP(t, a, b) { \ t tmp; \ tmp = a; \ a = b; \ b = tmp; \ } SWAP(u_short *, oldcore, newcore); SWAP(u_char *, olddisk, newdisk); /* * Next move the new pixel from the user buffer into the local array and set up the cmpstatus flag to * indicate if the new and old pixels agree fully, or just in the flat field (alpha) component. */ cmpstatus = SP_TRUE; cp1 = newcore; cp2 = oldcore; dp = newdisk; if (tif->tif_dir.td_bitspersample == 8) { REPEAT4(nc, *cp1 = *ip++; if (*cp2++ != *cp1) cmpstatus = SP_FALSE; *dp++ = *cp1++); } else { wp = (u_short *)ip; /* XXX for non-pcc compilers */ REPEAT4(nc, *cp1 = *wp++; if (*cp2++ != *cp1) cmpstatus = SP_FALSE; *dp++ = *cp1; *dp++ = *cp1++ >> 8); ip = (u_char *)wp; } cmpstatus += oldcore[ps->amark] == newcore[ps->amark] ? SA_TRUE : SA_FALSE; /* * Here is the main loop that decides how to handle the new pixel based on the current state. */ switch (runstatus + cmpstatus) { /* * Continue the full run because the new pixel matches the old. */ case PT_FULLRUN + SP_TRUE + SA_FALSE: case PT_FULLRUN + SP_TRUE + SA_TRUE: /* * The run count just overflowed. Go to the CFULLRUN state, because this run is done, and we do not * know whether to start a new packet or just a new run. */ if (tif->tif_dir.td_bitspersample == 16) { ps->lptr[0] = ++(ps->len); ps->lptr[1] = ps->len >> 8; if (ps->len != 0) break; ps->lptr[0] = --(ps->len); ps->lptr[1] = ps->len >> 8; } else { if (++(*ps->lptr) != 0) break; (*ps->lptr)--; } /*** fall thru... ***/ case PT_FULLRUN + SP_FALSE + SA_FALSE: case PT_FULLRUN + SP_FALSE + SA_TRUE: /* * Terminate the current run and go to CFULLRUN to decide whether to start a new run with this * pixel or to start a whole new packet. */ runstatus = PT_CFULLRUN; break; /* * In the middle of a fullrun packet; wait to see whether to start a new run, or whether to end this * packet and start a new packet. */ case PT_CFULLRUN + SP_TRUE + SA_FALSE: case PT_CFULLRUN + SP_TRUE + SA_TRUE: /* * Start a new run. Increment the packet count which holds the number of runs in this packet. * Put out the run length (1, meaning 1 repetition or 2 instances) and the full component information. */ if (bp > ps->fulleobuffer) { startnewbuffer(tif, PT_FULLRUN); } else { ps->count++; ps->lptr = bp; *bp++ = 1; if (tif->tif_dir.td_bitspersample == 16) { ps->len = 1; *bp++ = 0; } dp = newdisk; REPEAT8(ps->fulldisklength, *bp++ = *dp++); } runstatus = PT_FULLRUN; break; case PT_CFULLRUN + SP_FALSE + SA_TRUE: /* * End this packet and start a partial dump packet, because at least the alpha stayed constant. */ endpacket(ps); bp = startpacket(tif, bp, runstatus = PT_PARTDUMP); if (bp == 0) return(-1); break; case PT_CFULLRUN + SP_FALSE + SA_FALSE: endpacket(ps); bp = startpacket(tif, bp, runstatus = PT_FULLDUMP); if (bp == 0) return(-1); break; case PT_FULLDUMP + SP_TRUE + SA_TRUE: case PT_FULLDUMP + SP_TRUE + SA_FALSE: /* * End this full dump packet and start a full run because of the match. */ endpacket(ps); bp = startpacket(tif, bp, runstatus = PT_FULLRUN); if (bp == 0) return(-1); break; case PT_FULLDUMP + SP_FALSE + SA_TRUE: endpacket(ps); bp = startpacket(tif, bp, runstatus = PT_PARTDUMP); if (bp == 0) return(-1); break; case PT_FULLDUMP + SP_FALSE + SA_FALSE: /* * Continue the dump packet. Write the full component information into the buffer. */ if (bp > ps->fulleobuffer) { startnewbuffer(tif, PT_FULLDUMP); } else { ps->count++; dp = olddisk; REPEAT8(ps->fulldisklength, *bp++ = *dp++); } break; case PT_PARTRUN + SP_TRUE + SA_FALSE: case PT_PARTRUN + SP_TRUE + SA_TRUE: /* * Continue the part run packet. */ if (tif->tif_dir.td_bitspersample == 16) { ps->lptr[0] = ++(ps->len); ps->lptr[1] = ps->len >> 8; if (ps->len != 0) break; ps->lptr[0] = --(ps->len); ps->lptr[1] = ps->len >> 8; } else { if (++(*ps->lptr) != 0) break; (*ps->lptr)--; } /*** fall thru... ***/ case PT_PARTRUN + SP_FALSE + SA_TRUE: /* * Go to CPARTRUN because this may just be the start of a new run for this packet. */ runstatus = PT_CPARTRUN; break; case PT_PARTRUN + SP_FALSE + SA_FALSE: /* * With no match at all, we have to end this part run packet. With only this last pixel to start with, we do not * know what packet to start next. Thus we go to the UNKNOWN state. */ endpacket(ps); runstatus = PT_UNKNOWN; break; case PT_CPARTRUN + SP_TRUE + SA_FALSE: case PT_CPARTRUN + SP_TRUE + SA_TRUE: if (bp > ps->infoeobuffer) { startnewbuffer(tif, PT_PARTRUN); } else { ps->count++; ps->lptr = bp; *bp++ = 1; if (tif->tif_dir.td_bitspersample == 16) { ps->len = 1; *bp++ = 0; } dp = newdisk; REPEAT8(ps->infodisklength, *bp++ = *dp++); } runstatus = PT_PARTRUN; break; case PT_CPARTRUN + SP_FALSE + SA_TRUE: endpacket(ps); bp = startpacket(tif, bp, runstatus = PT_PARTDUMP); if (bp == 0) return(-1); break; case PT_CPARTRUN + SP_FALSE + SA_FALSE: endpacket(ps); bp = startpacket(tif, bp, runstatus = PT_FULLDUMP); if (bp == 0) return(-1); break; case PT_PARTDUMP + SP_TRUE + SA_FALSE: case PT_PARTDUMP + SP_TRUE + SA_TRUE: /* * This dump packet ends and a partial run packet begins with these last two pixels. */ endpacket(ps); bp = startpacket(tif, bp, runstatus = PT_PARTRUN); if (bp == 0) return(-1); break; case PT_PARTDUMP + SP_FALSE + SA_TRUE: /* * The partial dump packet continues. */ if (bp > ps->infoeobuffer) { startnewbuffer(tif, PT_PARTDUMP); } else { ps->count++; dp = olddisk; REPEAT8(ps->infodisklength, *bp++ = *dp++); } break; case PT_PARTDUMP + SP_FALSE + SA_FALSE: /* * The partial dump ends because alpha is no longer constant. Finish off this packet and go to the unknown * state with this new pixel. */ if (bp > ps->infoeobuffer) { startnewbuffer(tif, PT_PARTDUMP); } else { ps->count++; dp = olddisk; REPEAT8(ps->infodisklength, *bp++ = *dp++); } endpacket(ps); runstatus = PT_UNKNOWN; break; case PT_STARTUP + SP_FALSE + SA_FALSE: case PT_STARTUP + SP_FALSE + SA_TRUE: case PT_STARTUP + SP_TRUE + SA_FALSE: case PT_STARTUP + SP_TRUE + SA_TRUE: /* * The only thing to do when starting is to start a packet. However, we do not know which to start until * we have two pixels, so we go to the unknown state. */ runstatus = PT_UNKNOWN; break; case PT_UNKNOWN + SP_TRUE + SA_FALSE: case PT_UNKNOWN + SP_TRUE + SA_TRUE: runstatus = hasalphachannel ? PT_PARTRUN : PT_FULLRUN; bp = startpacket(tif, bp, runstatus); if (bp == 0) return(-1); break; case PT_UNKNOWN + SP_FALSE + SA_TRUE: bp = startpacket(tif, bp, runstatus = PT_PARTDUMP); if (bp == 0) return(-1); break; case PT_UNKNOWN + SP_FALSE + SA_FALSE: bp = startpacket(tif, bp, runstatus = PT_FULLDUMP); if (bp == 0) return(-1); break; } } /* * The following code handles the cleanup at the end of the scanline -- we must flush the current packet. */ switch (runstatus) { case PT_FULLRUN: /* everything is up to date */ break; case PT_CFULLRUN: /* add the last new pixel as a run with repeat count 0 */ if (bp > ps->fulleobuffer) { startnewbuffer(tif, 0); } else { ps->count++; *bp++ = 0; if (tif->tif_dir.td_bitspersample == 16) *bp++ = 0; dp = newdisk; REPEAT8(ps->fulldisklength, *bp++ = *dp++); } break; case PT_FULLDUMP: /* add this new pixel as the last pixel in a dump */ if (bp > ps->fulleobuffer) { startnewbuffer(tif, 0); } else { ps->count++; dp = newdisk; REPEAT8(ps->fulldisklength, *bp++ = *dp++); } break; case PT_PARTRUN: /* we are up to date */ break; case PT_CPARTRUN: /* see CFULLRUN above */ if (bp > ps->infoeobuffer) { startnewbuffer(tif, 0); } else { ps->count++; *bp++ = 0; if (tif->tif_dir.td_bitspersample == 16) *bp++ = 0; dp = newdisk; REPEAT8(ps->infodisklength, *bp++ = *dp++); } break; case PT_PARTDUMP: /* see FULLDUMP above */ if (bp > ps->infoeobuffer) { startnewbuffer(tif, 0); } else { ps->count++; dp = newdisk; REPEAT8(ps->infodisklength, *bp++ = *dp++); } break; case PT_STARTUP: break; case PT_UNKNOWN: /* we are caught with one pixel in the hand and no packet to add it to; we start a simple fulldump packet */ bp = startpacket(tif, bp, 0); if (bp == 0) return(-1); break; } endpacket(ps); tif->tif_rawcc += bp - (u_char *)tif->tif_rawcp; tif->tif_rawcp = (u_char *)bp; return(1); } /**************************************************************************** * */ static void PicioCleanup( TIFF *tif ) { if (tif->tif_data != NULL) { free(tif->tif_data); tif->tif_data = NULL; } } /**************************************************************************** * */ int TIFFInitPicio( TIFF *tif ) { tif->tif_stripdecode = PicioDecodeStrip; tif->tif_stripencode = PicioStripEncode; tif->tif_encoderow = PicioEncode; tif->tif_cleanup = PicioCleanup; return(1); }