/* * Encode a chunk of pixels. * * Uses an open addressing double hashing (no chaining) on the * prefix code/next character combination. We do a variant of * Knuth's algorithm D (vol. 3, sec. 6.4) along with G. Knott's * relatively-prime secondary probe. Here, the modular division * first probe is gives way to a faster exclusive-or manipulation. * Also do block compression with an adaptive reset, whereby the * code table is cleared when the compression ratio decreases, * but after the table fills. The variable-length output codes * are re-sized at this point, and a CODE_CLEAR is generated * for the decoder. */ static int LZWEncode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) { register LZWCodecState *sp = EncoderState(tif); register long fcode; register hash_t *hp; register int h, c; hcode_t ent; long disp; long incount, outcount, checkpoint; long nextdata, nextbits; int free_ent, maxcode, nbits; tidata_t op, limit; (void) s; if (sp == NULL) return (0); /* * Load local state. */ incount = sp->enc_incount; outcount = sp->enc_outcount; checkpoint = sp->enc_checkpoint; nextdata = sp->lzw_nextdata; nextbits = sp->lzw_nextbits; free_ent = sp->lzw_free_ent; maxcode = sp->lzw_maxcode; nbits = sp->lzw_nbits; op = tif->tif_rawcp; limit = sp->enc_rawlimit; ent = sp->enc_oldcode; if (ent == (hcode_t) -1 && cc > 0) { /* * NB: This is safe because it can only happen * at the start of a strip where we know there * is space in the data buffer. */ PutNextCode(op, CODE_CLEAR); ent = *bp++; cc--; incount++; } while (cc > 0) { c = *bp++; cc--; incount++; fcode = ((long)c << BITS_MAX) + ent; h = (c << HSHIFT) ^ ent; /* xor hashing */ #ifdef _WINDOWS /* * Check hash index for an overflow. */ if (h >= HSIZE) h -= HSIZE; #endif hp = &sp->enc_hashtab[h]; if (hp->hash == fcode) { ent = hp->code; continue; } if (hp->hash >= 0) { /* * Primary hash failed, check secondary hash. */ disp = HSIZE - h; if (h == 0) disp = 1; do { /* * Avoid pointer arithmetic 'cuz of * wraparound problems with segments. */ if ((h -= disp) < 0) h += HSIZE; hp = &sp->enc_hashtab[h]; if (hp->hash == fcode) { ent = hp->code; goto hit; } } while (hp->hash >= 0); } /* * New entry, emit code and add to table. */ /* * Verify there is space in the buffer for the code * and any potential Clear code that might be emitted * below. The value of limit is setup so that there * are at least 4 bytes free--room for 2 codes. */ if (op > limit) { tif->tif_rawcc = (tsize_t)(op - tif->tif_rawdata); TIFFFlushData1(tif); op = tif->tif_rawdata; } PutNextCode(op, ent); ent = c; hp->code = free_ent++; hp->hash = fcode; if (free_ent == CODE_MAX-1) { /* table is full, emit clear code and reset */ cl_hash(sp); sp->enc_ratio = 0; incount = 0; outcount = 0; free_ent = CODE_FIRST; PutNextCode(op, CODE_CLEAR); nbits = BITS_MIN; maxcode = MAXCODE(BITS_MIN); } else { /* * If the next entry is going to be too big for * the code size, then increase it, if possible. */ if (free_ent > maxcode) { nbits++; assert(nbits <= BITS_MAX); maxcode = (int) MAXCODE(nbits); } else if (incount >= checkpoint) { long rat; /* * Check compression ratio and, if things seem * to be slipping, clear the hash table and * reset state. The compression ratio is a * 24+8-bit fractional number. */ checkpoint = incount+CHECK_GAP; CALCRATIO(sp, rat); if (rat <= sp->enc_ratio) { cl_hash(sp); sp->enc_ratio = 0; incount = 0; outcount = 0; free_ent = CODE_FIRST; PutNextCode(op, CODE_CLEAR); nbits = BITS_MIN; maxcode = MAXCODE(BITS_MIN); } else sp->enc_ratio = rat; } } hit: ; } /* * Restore global state. */ sp->enc_incount = incount; sp->enc_outcount = outcount; sp->enc_checkpoint = checkpoint; sp->enc_oldcode = ent; sp->lzw_nextdata = nextdata; sp->lzw_nextbits = nextbits; sp->lzw_free_ent = free_ent; sp->lzw_maxcode = maxcode; sp->lzw_nbits = nbits; tif->tif_rawcp = op; return (1); }
/* * Encode a run of pixels. */ static int PackBitsEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) { unsigned char* bp = (unsigned char*) buf; tidata_t op, ep, lastliteral; long n, slop; int b; enum { BASE, LITERAL, RUN, LITERAL_RUN } state; (void) s; op = tif->tif_rawcp; ep = tif->tif_rawdata + tif->tif_rawdatasize; state = BASE; lastliteral = 0; while (cc > 0) { /* * Find the longest string of identical bytes. */ b = *bp++, cc--, n = 1; for (; cc > 0 && b == *bp; cc--, bp++) n++; again: if (op + 2 >= ep) { /* insure space for new data */ /* * Be careful about writing the last * literal. Must write up to that point * and then copy the remainder to the * front of the buffer. */ if (state == LITERAL || state == LITERAL_RUN) { slop = op - lastliteral; tif->tif_rawcc += lastliteral - tif->tif_rawcp; if (!TIFFFlushData1(tif)) return (-1); op = tif->tif_rawcp; while (slop-- > 0) *op++ = *lastliteral++; lastliteral = tif->tif_rawcp; } else { tif->tif_rawcc += op - tif->tif_rawcp; if (!TIFFFlushData1(tif)) return (-1); op = tif->tif_rawcp; } } switch (state) { case BASE: /* initial state, set run/literal */ if (n > 1) { state = RUN; if (n > 128) { *op++ = (tidata) -127; *op++ = (tidataval_t) b; n -= 128; goto again; } *op++ = (tidataval_t)(-(n-1)); *op++ = (tidataval_t) b; } else { lastliteral = op; *op++ = 0; *op++ = (tidataval_t) b; state = LITERAL; } break; case LITERAL: /* last object was literal string */ if (n > 1) { state = LITERAL_RUN; if (n > 128) { *op++ = (tidata) -127; *op++ = (tidataval_t) b; n -= 128; goto again; } *op++ = (tidataval_t)(-(n-1)); /* encode run */ *op++ = (tidataval_t) b; } else { /* extend literal */ if (++(*lastliteral) == 127) state = BASE; *op++ = (tidataval_t) b; } break; case RUN: /* last object was run */ if (n > 1) { if (n > 128) { *op++ = (tidata) -127; *op++ = (tidataval_t) b; n -= 128; goto again; } *op++ = (tidataval_t)(-(n-1)); *op++ = (tidataval_t) b; } else { lastliteral = op; *op++ = 0; *op++ = (tidataval_t) b; state = LITERAL; } break; case LITERAL_RUN: /* literal followed by a run */ /* * Check to see if previous run should * be converted to a literal, in which * case we convert literal-run-literal * to a single literal. */ if (n == 1 && op[-2] == (tidata) -1 && *lastliteral < 126) { state = (((*lastliteral) += 2) == 127 ? BASE : LITERAL); op[-2] = op[-1]; /* replicate */ } else state = RUN; goto again; } } tif->tif_rawcc += op - tif->tif_rawcp; tif->tif_rawcp = op; return (1); }
/* * Encode a row of 16-bit pixels. */ static int LogL16Encode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s) { LogLuvState* sp = EncoderState(tif); int shft; tmsize_t i; tmsize_t j; tmsize_t npixels; uint8* op; int16* tp; int16 b; tmsize_t occ; int rc=0, mask; tmsize_t beg; assert(s == 0); assert(sp != NULL); npixels = cc / sp->pixel_size; if (sp->user_datafmt == SGILOGDATAFMT_16BIT) tp = (int16*) bp; else { tp = (int16*) sp->tbuf; assert(sp->tbuflen >= npixels); (*sp->tfunc)(sp, bp, npixels); } /* compress each byte string */ op = tif->tif_rawcp; occ = tif->tif_rawdatasize - tif->tif_rawcc; for (shft = 2*8; (shft -= 8) >= 0; ) for (i = 0; i < npixels; i += rc) { if (occ < 4) { tif->tif_rawcp = op; tif->tif_rawcc = tif->tif_rawdatasize - occ; if (!TIFFFlushData1(tif)) return (-1); op = tif->tif_rawcp; occ = tif->tif_rawdatasize - tif->tif_rawcc; } mask = 0xff << shft; /* find next run */ for (beg = i; beg < npixels; beg += rc) { b = (int16) (tp[beg] & mask); rc = 1; while (rc < 127+2 && beg+rc < npixels && (tp[beg+rc] & mask) == b) rc++; if (rc >= MINRUN) break; /* long enough */ } if (beg-i > 1 && beg-i < MINRUN) { b = (int16) (tp[i] & mask);/*check short run */ j = i+1; while ((tp[j++] & mask) == b) if (j == beg) { *op++ = (uint8)(128-2+j-i); *op++ = (uint8)(b >> shft); occ -= 2; i = beg; break; } }
/* * Write the contents of the current directory * to the specified file. This routine doesn't * handle overwriting a directory with auxiliary * storage that's been changed. */ static int _TIFFWriteDirectory(TIFF* tif, int done) { uint16 dircount; toff_t diroff; ttag_t tag; uint32 nfields; tsize_t dirsize; char* data; TIFFDirEntry* dir; TIFFDirectory* td; unsigned long b, fields[FIELD_SETLONGS]; int fi, nfi; if (tif->tif_mode == O_RDONLY) return (1); /* * Clear write state so that subsequent images with * different characteristics get the right buffers * setup for them. */ if (done) { if (tif->tif_flags & TIFF_POSTENCODE) { tif->tif_flags &= ~TIFF_POSTENCODE; if (!(*tif->tif_postencode)(tif)) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error post-encoding before directory write"); return (0); } } (*tif->tif_close)(tif); /* shutdown encoder */ /* * Flush any data that might have been written * by the compression close+cleanup routines. */ if (tif->tif_rawcc > 0 && !TIFFFlushData1(tif)) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error flushing data before directory write"); return (0); } if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { _TIFFfree(tif->tif_rawdata); tif->tif_rawdata = NULL; tif->tif_rawcc = 0; tif->tif_rawdatasize = 0; } tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP); } td = &tif->tif_dir; /* * Size the directory so that we can calculate * offsets for the data items that aren't kept * in-place in each field. */ nfields = 0; for (b = 0; b <= FIELD_LAST; b++) if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM) nfields += (b < FIELD_SUBFILETYPE ? 2 : 1); nfields += td->td_customValueCount; dirsize = nfields * sizeof (TIFFDirEntry); data = (char*) _TIFFmalloc(dirsize); if (data == NULL) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Cannot write directory, out of space"); return (0); } /* * Directory hasn't been placed yet, put * it at the end of the file and link it * into the existing directory structure. */ if (tif->tif_diroff == 0 && !TIFFLinkDirectory(tif)) goto bad; tif->tif_dataoff = (toff_t)( tif->tif_diroff + sizeof (uint16) + dirsize + sizeof (toff_t)); if (tif->tif_dataoff & 1) tif->tif_dataoff++; (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET); tif->tif_curdir++; dir = (TIFFDirEntry*) data; /* * Setup external form of directory * entries and write data items. */ _TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields)); /* * Write out ExtraSamples tag only if * extra samples are present in the data. */ if (FieldSet(fields, FIELD_EXTRASAMPLES) && !td->td_extrasamples) { ResetFieldBit(fields, FIELD_EXTRASAMPLES); nfields--; dirsize -= sizeof (TIFFDirEntry); } /*XXX*/ for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) { const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi]; /* ** For custom fields, we test to see if the custom field ** is set or not. For normal fields, we just use the ** FieldSet test. */ if( fip->field_bit == FIELD_CUSTOM ) { int ci, is_set = FALSE; for( ci = 0; ci < td->td_customValueCount; ci++ ) is_set |= (td->td_customValues[ci].info == fip); if( !is_set ) continue; } else if (!FieldSet(fields, fip->field_bit)) continue; /* ** Handle other fields. */ switch (fip->field_bit) { case FIELD_STRIPOFFSETS: /* * We use one field bit for both strip and tile * offsets, and so must be careful in selecting * the appropriate field descriptor (so that tags * are written in sorted order). */ tag = isTiled(tif) ? TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS; if (tag != fip->field_tag) continue; dir->tdir_tag = (uint16) tag; dir->tdir_type = (uint16) TIFF_LONG; dir->tdir_count = (uint32) td->td_nstrips; if (!TIFFWriteLongArray(tif, dir, td->td_stripoffset)) goto bad; break; case FIELD_STRIPBYTECOUNTS: /* * We use one field bit for both strip and tile * byte counts, and so must be careful in selecting * the appropriate field descriptor (so that tags * are written in sorted order). */ tag = isTiled(tif) ? TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS; if (tag != fip->field_tag) continue; dir->tdir_tag = (uint16) tag; dir->tdir_type = (uint16) TIFF_LONG; dir->tdir_count = (uint32) td->td_nstrips; if (!TIFFWriteLongArray(tif, dir, td->td_stripbytecount)) goto bad; break; case FIELD_ROWSPERSTRIP: TIFFSetupShortLong(tif, TIFFTAG_ROWSPERSTRIP, dir, td->td_rowsperstrip); break; case FIELD_COLORMAP: if (!TIFFWriteShortTable(tif, TIFFTAG_COLORMAP, dir, 3, td->td_colormap)) goto bad; break; case FIELD_IMAGEDIMENSIONS: TIFFSetupShortLong(tif, TIFFTAG_IMAGEWIDTH, dir++, td->td_imagewidth); TIFFSetupShortLong(tif, TIFFTAG_IMAGELENGTH, dir, td->td_imagelength); break; case FIELD_TILEDIMENSIONS: TIFFSetupShortLong(tif, TIFFTAG_TILEWIDTH, dir++, td->td_tilewidth); TIFFSetupShortLong(tif, TIFFTAG_TILELENGTH, dir, td->td_tilelength); break; case FIELD_COMPRESSION: TIFFSetupShort(tif, TIFFTAG_COMPRESSION, dir, td->td_compression); break; case FIELD_PHOTOMETRIC: TIFFSetupShort(tif, TIFFTAG_PHOTOMETRIC, dir, td->td_photometric); break; case FIELD_POSITION: WriteRationalPair(TIFF_RATIONAL, TIFFTAG_XPOSITION, td->td_xposition, TIFFTAG_YPOSITION, td->td_yposition); break; case FIELD_RESOLUTION: WriteRationalPair(TIFF_RATIONAL, TIFFTAG_XRESOLUTION, td->td_xresolution, TIFFTAG_YRESOLUTION, td->td_yresolution); break; case FIELD_BITSPERSAMPLE: case FIELD_MINSAMPLEVALUE: case FIELD_MAXSAMPLEVALUE: case FIELD_SAMPLEFORMAT: if (!TIFFWritePerSampleShorts(tif, fip->field_tag, dir)) goto bad; break; case FIELD_SMINSAMPLEVALUE: case FIELD_SMAXSAMPLEVALUE: if (!TIFFWritePerSampleAnys(tif, _TIFFSampleToTagType(tif), fip->field_tag, dir)) goto bad; break; case FIELD_PAGENUMBER: case FIELD_HALFTONEHINTS: case FIELD_YCBCRSUBSAMPLING: if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) goto bad; break; case FIELD_INKNAMES: if (!TIFFWriteInkNames(tif, dir)) goto bad; break; case FIELD_TRANSFERFUNCTION: if (!TIFFWriteTransferFunction(tif, dir)) goto bad; break; case FIELD_SUBIFD: /* * XXX: Always write this field using LONG type * for backward compatibility. */ dir->tdir_tag = (uint16) fip->field_tag; dir->tdir_type = (uint16) TIFF_LONG; dir->tdir_count = (uint32) td->td_nsubifd; if (!TIFFWriteLongArray(tif, dir, td->td_subifd)) goto bad; /* * Total hack: if this directory includes a SubIFD * tag then force the next <n> directories to be * written as ``sub directories'' of this one. This * is used to write things like thumbnails and * image masks that one wants to keep out of the * normal directory linkage access mechanism. */ if (dir->tdir_count > 0) { tif->tif_flags |= TIFF_INSUBIFD; tif->tif_nsubifd = (uint16) dir->tdir_count; if (dir->tdir_count > 1) tif->tif_subifdoff = dir->tdir_offset; else tif->tif_subifdoff = (uint32)( tif->tif_diroff + sizeof (uint16) + ((char*)&dir->tdir_offset-data)); } break; default: /* XXX: Should be fixed and removed. */ if (fip->field_tag == TIFFTAG_DOTRANGE) { if (!TIFFSetupShortPair(tif, fip->field_tag, dir)) goto bad; } else if (!TIFFWriteNormalTag(tif, dir, fip)) goto bad; break; } dir++; if( fip->field_bit != FIELD_CUSTOM ) ResetFieldBit(fields, fip->field_bit); } /* * Write directory. */ dircount = (uint16) nfields; diroff = (uint32) tif->tif_nextdiroff; if (tif->tif_flags & TIFF_SWAB) { /* * The file's byte order is opposite to the * native machine architecture. We overwrite * the directory information with impunity * because it'll be released below after we * write it to the file. Note that all the * other tag construction routines assume that * we do this byte-swapping; i.e. they only * byte-swap indirect data. */ for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) { TIFFSwabArrayOfShort(&dir->tdir_tag, 2); TIFFSwabArrayOfLong(&dir->tdir_count, 2); } dircount = (uint16) nfields; TIFFSwabShort(&dircount); TIFFSwabLong(&diroff); } (void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET); if (!WriteOK(tif, &dircount, sizeof (dircount))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing directory count"); goto bad; } if (!WriteOK(tif, data, dirsize)) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing directory contents"); goto bad; } if (!WriteOK(tif, &diroff, sizeof (diroff))) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing directory link"); goto bad; } if (done) { TIFFFreeDirectory(tif); tif->tif_flags &= ~TIFF_DIRTYDIRECT; (*tif->tif_cleanup)(tif); /* * Reset directory-related state for subsequent * directories. */ TIFFCreateDirectory(tif); } _TIFFfree(data); return (1); bad: _TIFFfree(data); return (0); }
/* * Finish off an encoded strip by flushing it. */ static int TWebPPostEncode(TIFF* tif) { static const char module[] = "WebPPostEncode"; int64_t stride; WebPState *sp = EncoderState(tif); assert(sp != NULL); assert(sp->state == LSTATE_INIT_ENCODE); stride = (int64_t)sp->sPicture.width * sp->nSamples; #if WEBP_ENCODER_ABI_VERSION >= 0x0100 if (sp->nSamples == 4) { if (!WebPPictureImportRGBA(&sp->sPicture, sp->pBuffer, (int)stride)) { TIFFErrorExt(tif->tif_clientdata, module, "WebPPictureImportRGBA() failed" ); return 0; } } else #endif if (!WebPPictureImportRGB(&sp->sPicture, sp->pBuffer, (int)stride)) { TIFFErrorExt(tif->tif_clientdata, module, "WebPPictureImportRGB() failed"); return 0; } if (!WebPEncode(&sp->sEncoderConfig, &sp->sPicture)) { #if WEBP_ENCODER_ABI_VERSION >= 0x0100 const char* pszErrorMsg = NULL; switch(sp->sPicture.error_code) { case VP8_ENC_ERROR_OUT_OF_MEMORY: pszErrorMsg = "Out of memory"; break; case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY: pszErrorMsg = "Out of memory while flushing bits"; break; case VP8_ENC_ERROR_NULL_PARAMETER: pszErrorMsg = "A pointer parameter is NULL"; break; case VP8_ENC_ERROR_INVALID_CONFIGURATION: pszErrorMsg = "Configuration is invalid"; break; case VP8_ENC_ERROR_BAD_DIMENSION: pszErrorMsg = "Picture has invalid width/height"; break; case VP8_ENC_ERROR_PARTITION0_OVERFLOW: pszErrorMsg = "Partition is bigger than 512k. Try using less " "SEGMENTS, or increase PARTITION_LIMIT value"; break; case VP8_ENC_ERROR_PARTITION_OVERFLOW: pszErrorMsg = "Partition is bigger than 16M"; break; case VP8_ENC_ERROR_BAD_WRITE: pszErrorMsg = "Error while fludshing bytes"; break; case VP8_ENC_ERROR_FILE_TOO_BIG: pszErrorMsg = "File is bigger than 4G"; break; case VP8_ENC_ERROR_USER_ABORT: pszErrorMsg = "User interrupted"; break; default: TIFFErrorExt(tif->tif_clientdata, module, "WebPEncode returned an unknown error code: %d", sp->sPicture.error_code); pszErrorMsg = "Unknown WebP error type."; break; } TIFFErrorExt(tif->tif_clientdata, module, "WebPEncode() failed : %s", pszErrorMsg); #else TIFFErrorExt(tif->tif_clientdata, module, "Error in WebPEncode()"); #endif return 0; } sp->sPicture.custom_ptr = NULL; if (!TIFFFlushData1(tif)) { TIFFErrorExt(tif->tif_clientdata, module, "Error flushing TIFF WebP encoder."); return 0; } return 1; }