Ejemplo n.º 1
0
/*
 * Write an array of ``type'' values for a specified tag (i.e. this is a tag
 * which is allowed to have different types, e.g. SMaxSampleType).
 * Internally the data values are represented as double since a double can
 * hold any of the TIFF tag types (yes, this should really be an abstract
 * type tany_t for portability).  The data is converted into the specified
 * type in a temporary buffer and then handed off to the appropriate array
 * writer.
 */
static int
TIFFWriteAnyArray(TIFF* tif,
    TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, double* v)
{
	char buf[10 * sizeof(double)];
	char* w = buf;
	int i, status = 0;

	if (n * TIFFDataWidth(type) > sizeof buf) {
		w = (char*) _TIFFmalloc(n * TIFFDataWidth(type));
		if (w == NULL) {
			TIFFError(tif->tif_name,
			    "No space to write array");
			return (0);
		}
	}
	switch (type) {
	case TIFF_BYTE:
		{ uint8* bp = (uint8*) w;
		  for (i = 0; i < (int) n; i++)
			bp[i] = (uint8) v[i];
		  dir->tdir_tag = (uint16) tag;
		  dir->tdir_type = (short) type;
		  dir->tdir_count = n;
		  if (!TIFFWriteByteArray(tif, dir, (char*) bp))
			goto out;
		}
		break;
	case TIFF_SBYTE:
		{ int8* bp = (int8*) w;
		  for (i = 0; i < (int) n; i++)
			bp[i] = (int8) v[i];
		  dir->tdir_tag = (uint16) tag;
		  dir->tdir_type = (short) type;
		  dir->tdir_count = n;
		  if (!TIFFWriteByteArray(tif, dir, (char*) bp))
			goto out;
		}
		break;
	case TIFF_SHORT:
		{ uint16* bp = (uint16*) w;
		  for (i = 0; i < (int) n; i++)
			bp[i] = (uint16) v[i];
		  if (!TIFFWriteShortArray(tif, type, tag, dir, n, (uint16*)bp))
				goto out;
		}
		break;
	case TIFF_SSHORT:
		{ int16* bp = (int16*) w;
		  for (i = 0; i < (int) n; i++)
			bp[i] = (int16) v[i];
		  if (!TIFFWriteShortArray(tif, type, tag, dir, n, (uint16*)bp))
			goto out;
		}
		break;
	case TIFF_LONG:
		{ uint32* bp = (uint32*) w;
		  for (i = 0; i < (int) n; i++)
			bp[i] = (uint32) v[i];
		  if (!TIFFWriteLongArray(tif, type, tag, dir, n, bp))
			goto out;
		}
		break;
	case TIFF_SLONG:
		{ int32* bp = (int32*) w;
		  for (i = 0; i < (int) n; i++)
			bp[i] = (int32) v[i];
		  if (!TIFFWriteLongArray(tif, type, tag, dir, n, (uint32*) bp))
			goto out;
		}
		break;
	case TIFF_FLOAT:
		{ float* bp = (float*) w;
		  for (i = 0; i < (int) n; i++)
			bp[i] = (float) v[i];
		  if (!TIFFWriteFloatArray(tif, type, tag, dir, n, bp))
			goto out;
		}
		break;
	case TIFF_DOUBLE:
		return (TIFFWriteDoubleArray(tif, type, tag, dir, n, v));
	default:
		/* TIFF_NOTYPE */
		/* TIFF_ASCII */
		/* TIFF_UNDEFINED */
		/* TIFF_RATIONAL */
		/* TIFF_SRATIONAL */
		goto out;
	}
	status = 1;
 out:
	if (w != buf)
		_TIFFfree(w);
	return (status);
}
Ejemplo n.º 2
0
/*
 * Verify file is writable and that the directory
 * information is setup properly.  In doing the latter
 * we also "freeze" the state of the directory so
 * that important information is not changed.
 */
int
TIFFWriteCheck(TIFF* tif, int tiles, const char* module)
{
	if (tif->tif_mode == O_RDONLY) {
		TIFFError(module, "%s: File not open for writing",
		    tif->tif_name);
		return (0);
	}
	if (tiles ^ isTiled(tif)) {
		TIFFError(tif->tif_name, tiles ?
		    "Can not write tiles to a stripped image" :
		    "Can not write scanlines to a tiled image");
		return (0);
	}
        
        /*
         * While we allow compressed TIFF files to be opened in update mode,
         * we don't allow writing any image blocks in an existing compressed
         * image.  Eventually we could do so, by moving blocks that grow
         * to the end of the file, but we don't for now. 
         */
	if (tif->tif_dir.td_stripoffset != NULL 
            && tif->tif_dir.td_compression != COMPRESSION_NONE )
        {
            TIFFError( module,
                       "%s:\n"
                       "In place update to compressed TIFF images not "
                       "supported.",
                       tif->tif_name );
            return (0);
        }

	/*
	 * On the first write verify all the required information
	 * has been setup and initialize any data structures that
	 * had to wait until directory information was set.
	 * Note that a lot of our work is assumed to remain valid
	 * because we disallow any of the important parameters
	 * from changing after we start writing (i.e. once
	 * TIFF_BEENWRITING is set, TIFFSetField will only allow
	 * the image's length to be changed).
	 */
	if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) {
		TIFFError(module,
		    "%s: Must set \"ImageWidth\" before writing data",
		    tif->tif_name);
		return (0);
	}
	if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) {
		TIFFError(module,
	    "%s: Must set \"PlanarConfiguration\" before writing data",
		    tif->tif_name);
		return (0);
	}
	if (tif->tif_dir.td_stripoffset == NULL && !TIFFSetupStrips(tif)) {
		tif->tif_dir.td_nstrips = 0;
		TIFFError(module, "%s: No space for %s arrays",
		    tif->tif_name, isTiled(tif) ? "tile" : "strip");
		return (0);
	}
	tif->tif_tilesize = TIFFTileSize(tif);
	tif->tif_scanlinesize = TIFFScanlineSize(tif);
	tif->tif_flags |= TIFF_BEENWRITING;
	return (1);
}
Ejemplo n.º 3
0
static void
cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
{
	switch (type) {
	case TIFF_SHORT:
		if (count == 1) {
			uint16 shortv;
			CopyField(tag, shortv);
		} else if (count == 2) {
			uint16 shortv1, shortv2;
			CopyField2(tag, shortv1, shortv2);
		} else if (count == 4) {
			uint16 *tr, *tg, *tb, *ta;
			CopyField4(tag, tr, tg, tb, ta);
		} else if (count == (uint16) -1) {
			uint16 shortv1;
			uint16* shortav;
			CopyField2(tag, shortv1, shortav);
		}
		break;
	case TIFF_LONG:
		{ uint32 longv;
		  CopyField(tag, longv);
		}
		break;
	case TIFF_LONG8:
		{ uint64 longv8;
		  CopyField(tag, longv8);
		}
		break;
	case TIFF_SLONG8:
		{ int64 longv8;
		  CopyField(tag, longv8);
		}
		break;
	case TIFF_RATIONAL:
		if (count == 1) {
			float floatv;
			CopyField(tag, floatv);
		} else if (count == (uint16) -1) {
			float* floatav;
			CopyField(tag, floatav);
		}
		break;
	case TIFF_ASCII:
		{ char* stringv;
		  CopyField(tag, stringv);
		}
		break;
	case TIFF_DOUBLE:
		if (count == 1) {
			double doublev;
			CopyField(tag, doublev);
		} else if (count == (uint16) -1) {
			double* doubleav;
			CopyField(tag, doubleav);
		}
		break;
	case TIFF_IFD8:
		{ toff_t ifd8;
		  CopyField(tag, ifd8);
		}
		break;          default:
                TIFFError(TIFFFileName(in),
                          "Data type %d is not supported, tag %d skipped.",
                          tag, type);
	}
}
Ejemplo n.º 4
0
/*
 * Read the specified tile and setup for decoding. 
 * The data buffer is expanded, as necessary, to
 * hold the tile's data.
 */
static int
TIFFFillTile(TIFF* tif, ttile_t tile)
{
	static const char module[] = "TIFFFillTile";
	TIFFDirectory *td = &tif->tif_dir;
	tsize_t bytecount;

	bytecount = td->td_stripbytecount[tile];
	if (bytecount <= 0) {
		TIFFError(tif->tif_name,
		    "%lu: Invalid tile byte count, tile %lu",
		    (u_long) bytecount, (u_long) tile);
		return (0);
	}
	if (isMapped(tif) &&
	    (isFillOrder(tif, td->td_fillorder) || (tif->tif_flags & TIFF_NOBITREV))) {
		/*
		 * The image is mapped into memory and we either don't
		 * need to flip bits or the compression routine is going
		 * to handle this operation itself.  In this case, avoid
		 * copying the raw data and instead just reference the
		 * data from the memory mapped file image.  This assumes
		 * that the decompression routines do not modify the
		 * contents of the raw data buffer (if they try to,
		 * the application will get a fault since the file is
		 * mapped read-only).
		 */
		if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
			_TIFFfree(tif->tif_rawdata);
		tif->tif_flags &= ~TIFF_MYBUFFER;
		if ( td->td_stripoffset[tile] + bytecount > tif->tif_size) {
			tif->tif_curtile = NOTILE;
			return (0);
		}
		tif->tif_rawdatasize = bytecount;
		tif->tif_rawdata = tif->tif_base + td->td_stripoffset[tile];
	} else {
		/*
		 * Expand raw data buffer, if needed, to
		 * hold data tile coming from file
		 * (perhaps should set upper bound on
		 *  the size of a buffer we'll use?).
		 */
		if (bytecount > tif->tif_rawdatasize) {
			tif->tif_curtile = NOTILE;
			if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
				TIFFError(module,
				"%s: Data buffer too small to hold tile %ld",
				    tif->tif_name, (long) tile);
				return (0);
			}
			if (!TIFFReadBufferSetup(tif, 0,
			    TIFFroundup(bytecount, 1024)))
				return (0);
		}
		if (TIFFReadRawTile1(tif, tile, (u_char *)tif->tif_rawdata,
		    bytecount, module) != bytecount)
			return (0);
		if (!isFillOrder(tif, td->td_fillorder) &&
		    (tif->tif_flags & TIFF_NOBITREV) == 0)
			TIFFReverseBits(tif->tif_rawdata, bytecount);
	}
	return (TIFFStartTile(tif, tile));
}
Ejemplo n.º 5
0
/*
 * Encode the supplied data and write it to the
 * specified strip.  There must be space for the
 * data; we don't check if strips overlap!
 *
 * NB: Image length must be setup before writing.
 */
tsize_t
TIFFWriteEncodedStrip(TIFF* tif, tstrip_t strip, tdata_t data, tsize_t cc)
{
	static const char module[] = "TIFFWriteEncodedStrip";
	TIFFDirectory *td = &tif->tif_dir;
	tsample_t sample;

	if (!WRITECHECKSTRIPS(tif, module))
		return ((tsize_t) -1);
	/*
	 * Check strip array to make sure there's space.
	 * We don't support dynamically growing files that
	 * have data organized in separate bitplanes because
	 * it's too painful.  In that case we require that
	 * the imagelength be set properly before the first
	 * write (so that the strips array will be fully
	 * allocated above).
	 */
	if (strip >= td->td_nstrips) {
		if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
			TIFFError(tif->tif_name,
		"Can not grow image by strips when using separate planes");
			return ((tsize_t) -1);
		}
		if (!TIFFGrowStrips(tif, 1, module))
			return ((tsize_t) -1);
		td->td_stripsperimage =
		    TIFFhowmany(td->td_imagelength, td->td_rowsperstrip);
	}
	/*
	 * Handle delayed allocation of data buffer.  This
	 * permits it to be sized according to the directory
	 * info.
	 */
	if (!BUFFERCHECK(tif))
		return ((tsize_t) -1);
	tif->tif_curstrip = strip;
	tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
	if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
		if (!(*tif->tif_setupencode)(tif))
			return ((tsize_t) -1);
		tif->tif_flags |= TIFF_CODERSETUP;
	}
        
#ifdef REWRITE_HACK        
	tif->tif_rawcc = 0;
	tif->tif_rawcp = tif->tif_rawdata;

        if( td->td_stripbytecount[strip] > 0 )
        {
            /* if we are writing over existing tiles, zero length. */
            td->td_stripbytecount[strip] = 0;

            /* this forces TIFFAppendToStrip() to do a seek */
            tif->tif_curoff = 0;
        }
#endif
        
	tif->tif_flags &= ~TIFF_POSTENCODE;
	sample = (tsample_t)(strip / td->td_stripsperimage);
	if (!(*tif->tif_preencode)(tif, sample))
		return ((tsize_t) -1);

        /* swab if needed - note that source buffer will be altered */
        tif->tif_postdecode( tif, (tidata_t) data, cc );

	if (!(*tif->tif_encodestrip)(tif, (tidata_t) data, cc, sample))
		return ((tsize_t) 0);
	if (!(*tif->tif_postencode)(tif))
		return ((tsize_t) -1);
	if (!isFillOrder(tif, td->td_fillorder) &&
	    (tif->tif_flags & TIFF_NOBITREV) == 0)
		TIFFReverseBits(tif->tif_rawdata, tif->tif_rawcc);
	if (tif->tif_rawcc > 0 &&
	    !TIFFAppendToStrip(tif, strip, tif->tif_rawdata, tif->tif_rawcc))
		return ((tsize_t) -1);
	tif->tif_rawcc = 0;
	tif->tif_rawcp = tif->tif_rawdata;
	return (cc);
}
Ejemplo n.º 6
0
/*
 * Link the current directory into the
 * directory chain for the file.
 */
static int
TIFFLinkDirectory(TIFF* tif)
{
	static const char module[] = "TIFFLinkDirectory";
	uint32 nextdir;
	uint32 diroff;

	tif->tif_diroff = (TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1;
	diroff = (uint32) tif->tif_diroff;
	if (tif->tif_flags & TIFF_SWAB)
		TIFFSwabLong(&diroff);
#if SUBIFD_SUPPORT
	if (tif->tif_flags & TIFF_INSUBIFD) {
		(void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
		if (!WriteOK(tif, &diroff, sizeof (diroff))) {
			TIFFError(module,
			    "%s: Error writing SubIFD directory link",
			    tif->tif_name);
			return (0);
		}
		/*
		 * Advance to the next SubIFD or, if this is
		 * the last one configured, revert back to the
		 * normal directory linkage.
		 */
		if (--tif->tif_nsubifd)
			tif->tif_subifdoff += sizeof (diroff);
		else
			tif->tif_flags &= ~TIFF_INSUBIFD;
		return (1);
	}
#endif
	if (tif->tif_header.tiff_diroff == 0) {
		/*
		 * First directory, overwrite offset in header.
		 */
		tif->tif_header.tiff_diroff = (uint32) tif->tif_diroff;
#define	HDROFF(f)	((toff_t) &(((TIFFHeader*) 0)->f))
		(void) TIFFSeekFile(tif, HDROFF(tiff_diroff), SEEK_SET);
		if (!WriteOK(tif, &diroff, sizeof (diroff))) {
			TIFFError(tif->tif_name, "Error writing TIFF header");
			return (0);
		}
		return (1);
	}
	/*
	 * Not the first directory, search to the last and append.
	 */
	nextdir = tif->tif_header.tiff_diroff;
	do {
		uint16 dircount;

		if (!SeekOK(tif, nextdir) ||
		    !ReadOK(tif, &dircount, sizeof (dircount))) {
			TIFFError(module, "Error fetching directory count");
			return (0);
		}
		if (tif->tif_flags & TIFF_SWAB)
			TIFFSwabShort(&dircount);
		(void) TIFFSeekFile(tif,
		    dircount * sizeof (TIFFDirEntry), SEEK_CUR);
		if (!ReadOK(tif, &nextdir, sizeof (nextdir))) {
			TIFFError(module, "Error fetching directory link");
			return (0);
		}
		if (tif->tif_flags & TIFF_SWAB)
			TIFFSwabLong(&nextdir);
	} while (nextdir != 0);
	(void) TIFFSeekFile(tif, -(toff_t) sizeof (nextdir), SEEK_CUR);
	if (!WriteOK(tif, &diroff, sizeof (diroff))) {
		TIFFError(module, "Error writing directory link");
		return (0);
	}
	return (1);
}
Ejemplo n.º 7
0
int
main(int argc, char* argv[])
{
        int c;
        int dirnum = -1;
        uint32 diroff = 0;

        oerror = TIFFSetErrorHandler(NULL);
        owarning = TIFFSetWarningHandler(NULL);
        while ((c = getopt(argc, argv, "d:o:p:eflmsvw?")) != -1)
            switch (c) {
            case 'd':
                dirnum = atoi(optarg);
                break;
            case 'e':
                oerror = TIFFSetErrorHandler(oerror);
                break;
            case 'l':
                order0 = FILLORDER_LSB2MSB;
                break;
            case 'm':
                order0 = FILLORDER_MSB2LSB;
                break;
            case 'o':
                diroff = strtoul(optarg, NULL, 0);
                break;
            case 'p':
                photo0 = photoArg(optarg);
                break;
            case 's':
                stoponerr = 1;
                break;
            case 'w':
                owarning = TIFFSetWarningHandler(owarning);
                break;
            case 'v':
                verbose = 1;
                break;
            case '?':
                usage();
                /*NOTREACHED*/
            }
        filenum = argc - optind;
        if ( filenum < 1)
                usage();

        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);

        /*
         * Get the screen size
         */
        xmax = glutGet(GLUT_SCREEN_WIDTH);
        ymax = glutGet(GLUT_SCREEN_HEIGHT);

        /*
         * Use 90% of the screen size
         */
        xmax = (uint32) (xmax - xmax / 10.0);
        ymax = (uint32) (ymax - ymax / 10.0);

        filelist = (char **) _TIFFmalloc(filenum * sizeof(char*));
        if (!filelist) {
                TIFFError(argv[0], "Can not allocate space for the file list.");
                return 1;
        }
        _TIFFmemcpy(filelist, argv + optind, filenum * sizeof(char*));
        fileindex = -1;
        if (nextImage() < 0) {
                _TIFFfree(filelist);
                return 2;
        }
        /*
         * Set initial directory if user-specified
         * file was opened successfully.
         */
        if (dirnum != -1 && !TIFFSetDirectory(tif, dirnum))
            TIFFError(argv[0], "Error, seeking to directory %d", dirnum);
        if (diroff != 0 && !TIFFSetSubDirectory(tif, diroff))
            TIFFError(argv[0], "Error, setting subdirectory at %#x", diroff);
        order = order0;
        photo = photo0;
	if (initImage() < 0){
                _TIFFfree(filelist);
                return 3;
        }
        /*
         * Create a new window or reconfigure an existing
         * one to suit the image to be displayed.
         */
        glutInitWindowSize(width, height);
        snprintf(title, TITLE_LENGTH - 1, "%s [%u]", filelist[fileindex],
                (unsigned int) TIFFCurrentDirectory(tif));
        glutCreateWindow(title);
        glutDisplayFunc(raster_draw);
        glutReshapeFunc(raster_reshape);
        glutKeyboardFunc(raster_keys);
        glutSpecialFunc(raster_special);
        glutMainLoop();

        cleanup_and_exit();
        return 0;
}
Ejemplo n.º 8
0
TIFF*
TIFFClientOpen(
	const char* name, const char* mode,
	thandle_t clientdata,
	TIFFReadWriteProc readproc,
	TIFFReadWriteProc writeproc,
	TIFFSeekProc seekproc,
	TIFFCloseProc closeproc,
	TIFFSizeProc sizeproc,
	TIFFMapFileProc mapproc,
	TIFFUnmapFileProc unmapproc
)
{
	static const char module[] = "TIFFClientOpen";
	TIFF *tif;
	int m, bigendian;
	const char* cp;

	m = _TIFFgetMode(mode, module);
	if (m == -1)
		goto bad2;
	tif = (TIFF *)_TIFFmalloc(sizeof (TIFF) + strlen(name) + 1);
	if (tif == NULL) {
		TIFFError(module, "%s: Out of memory (TIFF structure)", name);
		goto bad2;
	}
	_TIFFmemset(tif, 0, sizeof (*tif));
	tif->tif_name = (char *)tif + sizeof (TIFF);
	strcpy(tif->tif_name, name);
	tif->tif_mode = m &~ (O_CREAT|O_TRUNC);
	tif->tif_curdir = (tdir_t) -1;		/* non-existent directory */
	tif->tif_curoff = 0;
	tif->tif_curstrip = (tstrip_t) -1;	/* invalid strip */
	tif->tif_row = (uint32) -1;		/* read/write pre-increment */
	tif->tif_clientdata = clientdata;
	tif->tif_readproc = readproc;
	tif->tif_writeproc = writeproc;
	tif->tif_seekproc = seekproc;
	tif->tif_closeproc = closeproc;
	tif->tif_sizeproc = sizeproc;
	tif->tif_mapproc = mapproc;
	tif->tif_unmapproc = unmapproc;
	_TIFFSetDefaultCompressionState(tif);	/* setup default state */
	/*
	 * Default is to return data MSB2LSB and enable the
	 * use of memory-mapped files and strip chopping when
	 * a file is opened read-only.
	 */
	tif->tif_flags = FILLORDER_MSB2LSB;
	if (m == O_RDONLY )
            tif->tif_flags |= TIFF_MAPPED;

#ifdef STRIPCHOP_DEFAULT
	if (m == O_RDONLY || m == O_RDWR)
		tif->tif_flags |= STRIPCHOP_DEFAULT;
#endif

	{ union { int32 i; char c[4]; } u; u.i = 1; bigendian = u.c[0] == 0; }
	/*
	 * Process library-specific flags in the open mode string.
	 * The following flags may be used to control intrinsic library
	 * behaviour that may or may not be desirable (usually for
	 * compatibility with some application that claims to support
	 * TIFF but only supports some braindead idea of what the
	 * vendor thinks TIFF is):
	 *
	 * 'l'		use little-endian byte order for creating a file
	 * 'b'		use big-endian byte order for creating a file
	 * 'L'		read/write information using LSB2MSB bit order
	 * 'B'		read/write information using MSB2LSB bit order
	 * 'H'		read/write information using host bit order
	 * 'M'		enable use of memory-mapped files when supported
	 * 'm'		disable use of memory-mapped files
	 * 'C'		enable strip chopping support when reading
	 * 'c'		disable strip chopping support
	 *
	 * The use of the 'l' and 'b' flags is strongly discouraged.
	 * These flags are provided solely because numerous vendors,
	 * typically on the PC, do not correctly support TIFF; they
	 * only support the Intel little-endian byte order.  This
	 * support is not configured by default because it supports
	 * the violation of the TIFF spec that says that readers *MUST*
	 * support both byte orders.  It is strongly recommended that
	 * you not use this feature except to deal with busted apps
	 * that write invalid TIFF.  And even in those cases you should
	 * bang on the vendors to fix their software.
	 *
	 * The 'L', 'B', and 'H' flags are intended for applications
	 * that can optimize operations on data by using a particular
	 * bit order.  By default the library returns data in MSB2LSB
	 * bit order for compatibiltiy with older versions of this
	 * library.  Returning data in the bit order of the native cpu
	 * makes the most sense but also requires applications to check
	 * the value of the FillOrder tag; something they probabyl do
	 * not do right now.
	 *
	 * The 'M' and 'm' flags are provided because some virtual memory
	 * systems exhibit poor behaviour when large images are mapped.
	 * These options permit clients to control the use of memory-mapped
	 * files on a per-file basis.
	 *
	 * The 'C' and 'c' flags are provided because the library support
	 * for chopping up large strips into multiple smaller strips is not
	 * application-transparent and as such can cause problems.  The 'c'
	 * option permits applications that only want to look at the tags,
	 * for example, to get the unadulterated TIFF tag information.
	 */
	for (cp = mode; *cp; cp++)
		switch (*cp) {
		case 'b':
			if ((m&O_CREAT) && !bigendian)
				tif->tif_flags |= TIFF_SWAB;
			break;
		case 'l':
			if ((m&O_CREAT) && bigendian)
				tif->tif_flags |= TIFF_SWAB;
			break;
		case 'B':
			tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
			    FILLORDER_MSB2LSB;
			break;
		case 'L':
			tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
			    FILLORDER_LSB2MSB;
			break;
		case 'H':
			tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
			    HOST_FILLORDER;
			break;
		case 'M':
			if (m == O_RDONLY)
				tif->tif_flags |= TIFF_MAPPED;
			break;
		case 'm':
			if (m == O_RDONLY)
				tif->tif_flags &= ~TIFF_MAPPED;
			break;
		case 'C':
			if (m == O_RDONLY)
				tif->tif_flags |= TIFF_STRIPCHOP;
			break;
		case 'c':
			if (m == O_RDONLY)
				tif->tif_flags &= ~TIFF_STRIPCHOP;
			break;
		}
	/*
	 * Read in TIFF header.
	 */
	if (!ReadOK(tif, &tif->tif_header, sizeof (TIFFHeader))) {
		if (tif->tif_mode == O_RDONLY) {
			TIFFError(name, "Cannot read TIFF header");
			goto bad;
		}
		/*
		 * Setup header and write.
		 */
		tif->tif_header.tiff_magic = tif->tif_flags & TIFF_SWAB
		    ? (bigendian ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN)
		    : (bigendian ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN);
		tif->tif_header.tiff_version = TIFF_VERSION;
		if (tif->tif_flags & TIFF_SWAB)
			TIFFSwabShort(&tif->tif_header.tiff_version);
		tif->tif_header.tiff_diroff = 0;	/* filled in later */

                /*
                 * This seek shouldn't be necessary, but I have had some
                 * crazy problems with a failed fseek() on Solaris leaving
                 * the current file pointer out of whack when an fwrite()
                 * is done. 
                 */
                TIFFSeekFile( tif, 0, SEEK_SET );

		if (!WriteOK(tif, &tif->tif_header, sizeof (TIFFHeader))) {
			TIFFError(name, "Error writing TIFF header");
			goto bad;
		}
		/*
		 * Setup the byte order handling.
		 */
		TIFFInitOrder(tif, tif->tif_header.tiff_magic, bigendian);
		/*
		 * Setup default directory.
		 */
		if (!TIFFDefaultDirectory(tif))
			goto bad;
		tif->tif_diroff = 0;
		return (tif);
	}
	/*
	 * Setup the byte order handling.
	 */
	if (tif->tif_header.tiff_magic != TIFF_BIGENDIAN &&
	    tif->tif_header.tiff_magic != TIFF_LITTLEENDIAN) {
		TIFFError(name,  "Not a TIFF file, bad magic number %d (0x%x)",
		    tif->tif_header.tiff_magic,
		    tif->tif_header.tiff_magic);
		goto bad;
	}
	TIFFInitOrder(tif, tif->tif_header.tiff_magic, bigendian);
	/*
	 * Swap header if required.
	 */
	if (tif->tif_flags & TIFF_SWAB) {
		TIFFSwabShort(&tif->tif_header.tiff_version);
		TIFFSwabLong(&tif->tif_header.tiff_diroff);
	}
	/*
	 * Now check version (if needed, it's been byte-swapped).
	 * Note that this isn't actually a version number, it's a
	 * magic number that doesn't change (stupid).
	 */
	if (tif->tif_header.tiff_version != TIFF_VERSION) {
		TIFFError(name,
		    "Not a TIFF file, bad version number %d (0x%x)",
		    tif->tif_header.tiff_version,
		    tif->tif_header.tiff_version); 
		goto bad;
	}
	tif->tif_flags |= TIFF_MYBUFFER;
	tif->tif_rawcp = tif->tif_rawdata = 0;
	tif->tif_rawdatasize = 0;
	/*
	 * Setup initial directory.
	 */
	switch (mode[0]) {
	case 'r':
		tif->tif_nextdiroff = tif->tif_header.tiff_diroff;
		/*
		 * Try to use a memory-mapped file if the client
		 * has not explicitly suppressed usage with the
		 * 'm' flag in the open mode (see above).
		 */
		if ((tif->tif_flags & TIFF_MAPPED) &&
	!TIFFMapFileContents(tif, (tdata_t*) &tif->tif_base, &tif->tif_size))
			tif->tif_flags &= ~TIFF_MAPPED;
		if (TIFFReadDirectory(tif)) {
                        if( m != O_RDONLY 
                          && tif->tif_dir.td_compression != COMPRESSION_NONE )
                        {
                            TIFFError( name, 
                                       "Can't open a compressed TIFF file"
                                       " with compression for update." );
                            goto bad;
                        }
			tif->tif_rawcc = -1;
			tif->tif_flags |= TIFF_BUFFERSETUP;
			return (tif);
		}
		break;
	case 'a':
		/*
		 * New directories are automatically append
		 * to the end of the directory chain when they
		 * are written out (see TIFFWriteDirectory).
		 */
		if (!TIFFDefaultDirectory(tif))
			goto bad;
		return (tif);
	}
bad:
	tif->tif_mode = O_RDONLY;	/* XXX avoid flush */
	TIFFClose(tif);
	return ((TIFF*)0);
bad2:
	(void) (*closeproc)(clientdata);
	return ((TIFF*)0);
}
Ejemplo n.º 9
0
int
main(int argc, char* argv[])
{
	uint32	width, length;
	uint16	nbands = 1;		/* number of bands in input image */
        uint16	depth = 8;		/* bits per pixel in input image */
	uint32	rowsperstrip = (uint32) -1;
        uint16	photometric = PHOTOMETRIC_MINISBLACK;
	int	fd = 0;
	struct stat instat;
	char	*outfilename = NULL, *infilename = NULL;
	TIFF	*out = NULL;

	BMPFileHeader file_hdr;
        BMPInfoHeader info_hdr;
        int     bmp_type;
        uint32  clr_tbl_size, n_clr_elems = 3;
        unsigned char *clr_tbl;
	unsigned short *red_tbl = NULL, *green_tbl = NULL, *blue_tbl = NULL;
	uint32	row, clr;

	int	c;
	extern int optind;
	extern char* optarg;

	while ((c = getopt(argc, argv, "c:r:o:h")) != -1) {
		switch (c) {
		case 'c':		/* compression scheme */
			if (!processCompressOptions(optarg))
				usage();
			break;
		case 'r':		/* rows/strip */
			rowsperstrip = atoi(optarg);
			break;
		case 'o':
			outfilename = optarg;
			break;
		case 'h':
			usage();
		default:
			break;
		}
	}

	if (argc - optind < 2)
		usage();

	if (outfilename == NULL)
		outfilename = argv[argc-1];
	out = TIFFOpen(outfilename, "w");
	if (out == NULL) {
		TIFFError(infilename, "Cannot open file %s for output",
			  outfilename);
		goto bad3;
	}
	

	while (optind < argc-1) {
		infilename = argv[optind];
		optind++;
	    
		fd = open(infilename, O_RDONLY|O_BINARY, 0);
		if (fd < 0) {
			TIFFError(infilename, "Cannot open input file");
			return -1;
		}

		read(fd, file_hdr.bType, 2);
		if(file_hdr.bType[0] != 'B' || file_hdr.bType[1] != 'M') {
			TIFFError(infilename, "File is not BMP");
			goto bad;
		}

/* -------------------------------------------------------------------- */
/*      Read the BMPFileHeader. We need iOffBits value only             */
/* -------------------------------------------------------------------- */
		lseek(fd, 10, SEEK_SET);
		read(fd, &file_hdr.iOffBits, 4);
#ifdef WORDS_BIGENDIAN
		TIFFSwabLong(&file_hdr.iOffBits);
#endif
		fstat(fd, &instat);
		file_hdr.iSize = instat.st_size;

/* -------------------------------------------------------------------- */
/*      Read the BMPInfoHeader.                                         */
/* -------------------------------------------------------------------- */

		lseek(fd, BFH_SIZE, SEEK_SET);
		read(fd, &info_hdr.iSize, 4);
#ifdef WORDS_BIGENDIAN
		TIFFSwabLong(&info_hdr.iSize);
#endif

		if (info_hdr.iSize == BIH_WIN4SIZE)
			bmp_type = BMPT_WIN4;
		else if (info_hdr.iSize == BIH_OS21SIZE)
			bmp_type = BMPT_OS21;
		else if (info_hdr.iSize == BIH_OS22SIZE
			 || info_hdr.iSize == 16)
			bmp_type = BMPT_OS22;
		else
			bmp_type = BMPT_WIN5;

		if (bmp_type == BMPT_WIN4
		    || bmp_type == BMPT_WIN5
		    || bmp_type == BMPT_OS22) {
			read(fd, &info_hdr.iWidth, 4);
			read(fd, &info_hdr.iHeight, 4);
			read(fd, &info_hdr.iPlanes, 2);
			read(fd, &info_hdr.iBitCount, 2);
			read(fd, &info_hdr.iCompression, 4);
			read(fd, &info_hdr.iSizeImage, 4);
			read(fd, &info_hdr.iXPelsPerMeter, 4);
			read(fd, &info_hdr.iYPelsPerMeter, 4);
			read(fd, &info_hdr.iClrUsed, 4);
			read(fd, &info_hdr.iClrImportant, 4);
#ifdef WORDS_BIGENDIAN
			TIFFSwabLong((uint32*) &info_hdr.iWidth);
			TIFFSwabLong((uint32*) &info_hdr.iHeight);
			TIFFSwabShort((uint16*) &info_hdr.iPlanes);
			TIFFSwabShort((uint16*) &info_hdr.iBitCount);
			TIFFSwabLong((uint32*) &info_hdr.iCompression);
			TIFFSwabLong((uint32*) &info_hdr.iSizeImage);
			TIFFSwabLong((uint32*) &info_hdr.iXPelsPerMeter);
			TIFFSwabLong((uint32*) &info_hdr.iYPelsPerMeter);
			TIFFSwabLong((uint32*) &info_hdr.iClrUsed);
			TIFFSwabLong((uint32*) &info_hdr.iClrImportant);
#endif
			n_clr_elems = 4;
		}

		if (bmp_type == BMPT_OS22) {
			/* 
			 * FIXME: different info in different documents
			 * regarding this!
			 */
			 n_clr_elems = 3;
		}

		if (bmp_type == BMPT_OS21) {
			int16  iShort;

			read(fd, &iShort, 2);
#ifdef WORDS_BIGENDIAN
			TIFFSwabShort((uint16*) &iShort);
#endif
			info_hdr.iWidth = iShort;
			read(fd, &iShort, 2);
#ifdef WORDS_BIGENDIAN
			TIFFSwabShort((uint16*) &iShort);
#endif
			info_hdr.iHeight = iShort;
			read(fd, &iShort, 2);
#ifdef WORDS_BIGENDIAN
			TIFFSwabShort((uint16*) &iShort);
#endif
			info_hdr.iPlanes = iShort;
			read(fd, &iShort, 2);
#ifdef WORDS_BIGENDIAN
			TIFFSwabShort((uint16*) &iShort);
#endif
			info_hdr.iBitCount = iShort;
			info_hdr.iCompression = BMPC_RGB;
			n_clr_elems = 3;
		}

		if (info_hdr.iBitCount != 1  && info_hdr.iBitCount != 4  &&
		    info_hdr.iBitCount != 8  && info_hdr.iBitCount != 16 &&
		    info_hdr.iBitCount != 24 && info_hdr.iBitCount != 32) {
		    TIFFError(infilename,
			      "Cannot process BMP file with bit count %d",
			      info_hdr.iBitCount);
		    close(fd);
		    return 0;
		}

		width = info_hdr.iWidth;
		length = (info_hdr.iHeight > 0) ? info_hdr.iHeight : -info_hdr.iHeight;

		switch (info_hdr.iBitCount)
		{
			case 1:
			case 4:
			case 8:
				nbands = 1;
				depth = info_hdr.iBitCount;
				photometric = PHOTOMETRIC_PALETTE;
				/* Allocate memory for colour table and read it. */
				if (info_hdr.iClrUsed)
				    clr_tbl_size =
					    ((uint32)(1<<depth)<info_hdr.iClrUsed)
					    ? (uint32) (1 << depth)
					    : info_hdr.iClrUsed;
				else
				    clr_tbl_size = 1 << depth;
				clr_tbl = (unsigned char *)
					_TIFFmalloc(n_clr_elems * clr_tbl_size);
				if (!clr_tbl) {
					TIFFError(infilename,
					"Can't allocate space for color table");
					goto bad;
				}

				lseek(fd, BFH_SIZE + info_hdr.iSize, SEEK_SET);
				read(fd, clr_tbl, n_clr_elems * clr_tbl_size);

				red_tbl = (unsigned short*)
					_TIFFmalloc(((tmsize_t)1)<<depth * sizeof(unsigned short));
				if (!red_tbl) {
					TIFFError(infilename,
				"Can't allocate space for red component table");
					_TIFFfree(clr_tbl);
					goto bad1;
				}
				green_tbl = (unsigned short*)
					_TIFFmalloc(((tmsize_t)1)<<depth * sizeof(unsigned short));
				if (!green_tbl) {
					TIFFError(infilename,
				"Can't allocate space for green component table");
					_TIFFfree(clr_tbl);
					goto bad2;
				}
				blue_tbl = (unsigned short*)
					_TIFFmalloc(((tmsize_t)1)<<depth * sizeof(unsigned short));
				if (!blue_tbl) {
					TIFFError(infilename,
				"Can't allocate space for blue component table");
					_TIFFfree(clr_tbl);
					goto bad3;
				}

				for(clr = 0; clr < clr_tbl_size; clr++) {
				    red_tbl[clr] = 257*clr_tbl[clr*n_clr_elems+2];
				    green_tbl[clr] = 257*clr_tbl[clr*n_clr_elems+1];
				    blue_tbl[clr] = 257*clr_tbl[clr*n_clr_elems];
				}

				_TIFFfree(clr_tbl);
				break;
			case 16:
			case 24:
				nbands = 3;
				depth = info_hdr.iBitCount / nbands;
				photometric = PHOTOMETRIC_RGB;
				break;
			case 32:
				nbands = 3;
				depth = 8;
				photometric = PHOTOMETRIC_RGB;
				break;
			default:
				break;
		}

/* -------------------------------------------------------------------- */
/*  Create output file.                                                 */
/* -------------------------------------------------------------------- */

		TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
		TIFFSetField(out, TIFFTAG_IMAGELENGTH, length);
		TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
		TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, nbands);
		TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, depth);
		TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
		TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
		TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
			     TIFFDefaultStripSize(out, rowsperstrip));
		
		if (red_tbl && green_tbl && blue_tbl) {
			TIFFSetField(out, TIFFTAG_COLORMAP,
				     red_tbl, green_tbl, blue_tbl);
		}
		
		if (compression == (uint16) -1)
			compression = COMPRESSION_PACKBITS;
		TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
		switch (compression) {
		case COMPRESSION_JPEG:
			if (photometric == PHOTOMETRIC_RGB
			    && jpegcolormode == JPEGCOLORMODE_RGB)
				photometric = PHOTOMETRIC_YCBCR;
			TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
			TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
			break;
		case COMPRESSION_LZW:
		case COMPRESSION_DEFLATE:
			if (predictor != 0)
				TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
			break;
		}

/* -------------------------------------------------------------------- */
/*  Read uncompressed image data.                                       */
/* -------------------------------------------------------------------- */

		if (info_hdr.iCompression == BMPC_RGB) {
			uint32 offset, size;
			char *scanbuf;

			/* XXX: Avoid integer overflow. We can calculate size
			 * in one step using
			 *
			 *  size = ((width * info_hdr.iBitCount + 31) & ~31) / 8
			 *
			 * formulae, but we should check for overflow
			 * conditions during calculation.
			 */
			size = width * info_hdr.iBitCount + 31;
			if (!width || !info_hdr.iBitCount
			    || (size - 31) / info_hdr.iBitCount != width ) {
				TIFFError(infilename,
					  "Wrong image parameters; can't "
					  "allocate space for scanline buffer");
				goto bad3;
			}
			size = (size & ~31) / 8;

			scanbuf = (char *) _TIFFmalloc(size);
			if (!scanbuf) {
				TIFFError(infilename,
				"Can't allocate space for scanline buffer");
				goto bad3;
			}

			for (row = 0; row < length; row++) {
				if (info_hdr.iHeight > 0)
					offset = file_hdr.iOffBits+(length-row-1)*size;
				else
					offset = file_hdr.iOffBits + row * size;
				if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
					TIFFError(infilename,
						  "scanline %lu: Seek error",
						  (unsigned long) row);
					break;
				}

				if (read(fd, scanbuf, size) < 0) {
					TIFFError(infilename,
						  "scanline %lu: Read error",
						  (unsigned long) row);
					break;
				}

				rearrangePixels(scanbuf, width, info_hdr.iBitCount);

				if (TIFFWriteScanline(out, scanbuf, row, 0)<0) {
					TIFFError(infilename,
						  "scanline %lu: Write error",
						  (unsigned long) row);
					break;
				}
			}

			_TIFFfree(scanbuf);

/* -------------------------------------------------------------------- */
/*  Read compressed image data.                                         */
/* -------------------------------------------------------------------- */

		} else if ( info_hdr.iCompression == BMPC_RLE8
			    || info_hdr.iCompression == BMPC_RLE4 ) {
			uint32		i, j, k, runlength;
			uint32		compr_size, uncompr_size;
			unsigned char   *comprbuf;
			unsigned char   *uncomprbuf;

			compr_size = file_hdr.iSize - file_hdr.iOffBits;
			uncompr_size = width * length;
			comprbuf = (unsigned char *) _TIFFmalloc( compr_size );
			if (!comprbuf) {
				TIFFError(infilename,
			"Can't allocate space for compressed scanline buffer");
				goto bad3;
			}
			uncomprbuf = (unsigned char *)_TIFFmalloc(uncompr_size);
			if (!uncomprbuf) {
				TIFFError(infilename,
			"Can't allocate space for uncompressed scanline buffer");
				goto bad3;
			}

			lseek(fd, file_hdr.iOffBits, SEEK_SET);
			read(fd, comprbuf, compr_size);
			i = 0;
			j = 0;
			if (info_hdr.iBitCount == 8) {		/* RLE8 */
			    while(j < uncompr_size && i < compr_size) {
				if ( comprbuf[i] ) {
				    runlength = comprbuf[i++];
				    while( runlength > 0
					   && j < uncompr_size
					   && i < compr_size ) {
					uncomprbuf[j++] = comprbuf[i];
					runlength--;
				    }
				    i++;
				} else {
				    i++;
				    if (comprbuf[i] == 0) /* Next scanline */
					i++;
				    else if (comprbuf[i] == 1) /* End of image */
					break;
				    else if (comprbuf[i] == 2) { /* Move to... */
					i++;
					if (i < compr_size - 1) {
					    j+=comprbuf[i]+comprbuf[i+1]*width;
					    i += 2;
					}
					else
					    break;
				    } else {            /* Absolute mode */
					runlength = comprbuf[i++];
					for (k = 0; k < runlength && j < uncompr_size && i < compr_size; k++)
					    uncomprbuf[j++] = comprbuf[i++];
					if ( k & 0x01 )
					    i++;
				    }
				}
			    }
			}
			else {				    /* RLE4 */
			    while( j < uncompr_size && i < compr_size ) {
				if ( comprbuf[i] ) {
				    runlength = comprbuf[i++];
				    while( runlength > 0 && j < uncompr_size && i < compr_size ) {
					if ( runlength & 0x01 )
					    uncomprbuf[j++] = (comprbuf[i] & 0xF0) >> 4;
					else
					    uncomprbuf[j++] = comprbuf[i] & 0x0F;
					runlength--;
				    }
				    i++;
				} else {
				    i++;
				    if (comprbuf[i] == 0) /* Next scanline */
					i++;
				    else if (comprbuf[i] == 1) /* End of image */
					break;
				    else if (comprbuf[i] == 2) { /* Move to... */
					i++;
					if (i < compr_size - 1) {
					    j+=comprbuf[i]+comprbuf[i+1]*width;
					    i += 2;
					}
					else
					    break;
				    } else {            /* Absolute mode */
					runlength = comprbuf[i++];
					for (k = 0; k < runlength && j < uncompr_size && i < compr_size; k++) {
					    if (k & 0x01)
						uncomprbuf[j++] = comprbuf[i++] & 0x0F;
					    else
						uncomprbuf[j++] = (comprbuf[i] & 0xF0) >> 4;
					}
					if (k & 0x01)
					    i++;
				    }
				}
			    }
			}
Ejemplo n.º 10
0
/*
 * Read the specified strip and setup for decoding. 
 * The data buffer is expanded, as necessary, to
 * hold the strip's data.
 */
int
TIFFFillStrip(TIFF* tif, tstrip_t strip)
{
	static const char module[] = "TIFFFillStrip";
	TIFFDirectory *td = &tif->tif_dir;
	tsize_t bytecount;

	bytecount = td->td_stripbytecount[strip];
	if (bytecount <= 0) {
		TIFFError(tif->tif_name,
		    "%lu: Invalid strip byte count, strip %lu",
		    (unsigned long) bytecount, (unsigned long) strip);
		return (0);
	}
	if (isMapped(tif) &&
	    (isFillOrder(tif, td->td_fillorder)
             || (tif->tif_flags & TIFF_NOBITREV))) {
		/*
		 * The image is mapped into memory and we either don't
		 * need to flip bits or the compression routine is going
		 * to handle this operation itself.  In this case, avoid
		 * copying the raw data and instead just reference the
		 * data from the memory mapped file image.  This assumes
		 * that the decompression routines do not modify the
		 * contents of the raw data buffer (if they try to,
		 * the application will get a fault since the file is
		 * mapped read-only).
		 */
		if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
			_TIFFfree(tif->tif_rawdata);
		tif->tif_flags &= ~TIFF_MYBUFFER;
		if ( td->td_stripoffset[strip] + bytecount > tif->tif_size) {
			/*
			 * This error message might seem strange, but it's
			 * what would happen if a read were done instead.
			 */
			TIFFError(module,
		    "%s: Read error on strip %lu; got %lu bytes, expected %lu",
			    tif->tif_name,
			    (unsigned long) strip,
			    (unsigned long) tif->tif_size - td->td_stripoffset[strip],
			    (unsigned long) bytecount);
			tif->tif_curstrip = NOSTRIP;
			return (0);
		}
		tif->tif_rawdatasize = bytecount;
		tif->tif_rawdata = tif->tif_base + td->td_stripoffset[strip];
	} else {
		/*
		 * Expand raw data buffer, if needed, to
		 * hold data strip coming from file
		 * (perhaps should set upper bound on
		 *  the size of a buffer we'll use?).
		 */
		if (bytecount > tif->tif_rawdatasize) {
			tif->tif_curstrip = NOSTRIP;
			if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
				TIFFError(module,
				"%s: Data buffer too small to hold strip %lu",
				    tif->tif_name, (unsigned long) strip);
				return (0);
			}
			if (!TIFFReadBufferSetup(tif, 0,
			    TIFFroundup(bytecount, 1024)))
				return (0);
		}
		if (TIFFReadRawStrip1(tif, strip, (unsigned char *)tif->tif_rawdata,
		    bytecount, module) != bytecount)
			return (0);
		if (!isFillOrder(tif, td->td_fillorder) &&
		    (tif->tif_flags & TIFF_NOBITREV) == 0)
			TIFFReverseBits(tif->tif_rawdata, bytecount);
	}
	return (TIFFStartStrip(tif, strip));
}
Ejemplo n.º 11
0
void
rasterize(int interleaved, char* mode)
{
    register unsigned long row;
    unsigned char *newras;
    unsigned char *ras;
    TIFF *tif;
    tstrip_t strip;
    tsize_t stripsize;

    if ((newras = (unsigned char*) _TIFFmalloc(width*height+EXTRAFUDGE)) == NULL) {
        fprintf(stderr, "not enough memory for image\n");
        return;
    }
#define DRAWSEGMENT(offset, step) {			\
        for (row = offset; row < height; row += step) {	\
            _TIFFmemcpy(newras + row*width, ras, width);\
            ras += width;                            	\
        }						\
    }
    ras = raster;
    if (interleaved) {
        DRAWSEGMENT(0, 8);
        DRAWSEGMENT(4, 8);
        DRAWSEGMENT(2, 4);
        DRAWSEGMENT(1, 2);
    } else 
        DRAWSEGMENT(0, 1);
#undef DRAWSEGMENT

    tif = TIFFOpen(imagename, mode);
    if (!tif) {
	TIFFError(imagename,"Can not open output image");
	exit(-1);
    }
    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32) width);
    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32) height);
    TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
    TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
    TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 
	rowsperstrip = TIFFDefaultStripSize(tif, rowsperstrip));
    TIFFSetField(tif, TIFFTAG_COMPRESSION, compression);
    switch (compression) {
    case COMPRESSION_LZW:
    case COMPRESSION_DEFLATE:
	    if (predictor != 0)
		    TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor);
	    break;
    }
    TIFFSetField(tif, TIFFTAG_COLORMAP, red, green, blue);
    TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
    strip = 0;
    stripsize = TIFFStripSize(tif);
    for (row=0; row<height; row += rowsperstrip) {
	if (rowsperstrip > height-row) {
	    rowsperstrip = height-row;
	    stripsize = TIFFVStripSize(tif, rowsperstrip);
	}
	if (TIFFWriteEncodedStrip(tif, strip, newras+row*width, stripsize) < 0)
	    break;
	strip++;
    }
    TIFFClose(tif);

    _TIFFfree(newras);
}
Ejemplo n.º 12
0
/* This function will write an entire directory to the disk, and return the
   offset value indicating where in the file it wrote the beginning of the
   directory structure. This is NOT the same as the offset value before
   calling this function, because some of the fields may have caused various
   data items to be written out BEFORE writing the directory structure.

   This code was basically written by ripping of the TIFFWriteDirectory() 
   code and generalizing it, using RPS's TIFFWritePliIfd() code for
   inspiration.  My original goal was to make this code general enough that
   the original TIFFWriteDirectory() could be rewritten to just call this
   function with the appropriate field and field-accessing arguments.

   However, now I realize that there's a lot of code that gets executed for
   the main, standard TIFF directories that does not apply to special
   private subdirectories, so such a reimplementation for the sake of
   eliminating redundant or duplicate code is probably not possible,
   unless we also pass in a Main flag to indiciate which type of handling
   to do, which would be kind of a hack. I've marked those places where I
   changed or ripped out code which would have to be re-inserted to
   generalize this function. If it can be done in a clean and graceful way,
   it would be a great way to generalize the TIFF library. Otherwise, I'll
   just leave this code here where it duplicates but remains on top of and
   hopefully mostly independent of the main TIFF library.

   The caller will probably want to free the sub directory structure after
   returning from this call, since otherwise once written out, the user
   is likely to forget about it and leave data lying around.
*/
toff_t
TIFFWritePrivateDataSubDirectory(TIFF* tif,
				 uint32 pdir_fieldsset[], int pdir_fields_last,
				 TIFFFieldInfo *field_info,
				 int (*getFieldFn)(TIFF *tif, ttag_t tag, ...))
{
	uint16 dircount;
	uint32 diroff, nextdiroff;
	ttag_t tag;
	uint32 nfields;
	tsize_t dirsize;
	char* data;
	TIFFDirEntry* dir;
	u_long b, *fields, fields_size;
	toff_t directory_offset;
	TIFFFieldInfo* fip;

	/*
	 * Deleted out all of the encoder flushing and such code from here -
	 * not necessary for subdirectories.
	 */

	/* Finish writing out any image data. */
	TIFFFlushData(tif);

	/*
	 * 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 <= pdir_fields_last; b++)
		if (FieldSet(pdir_fieldsset, b))
			/* Deleted code to make size of first 4 tags 2
			   instead of 1. */
			nfields += 1;
	dirsize = nfields * sizeof (TIFFDirEntry);
	data = (char*) _TIFFmalloc(dirsize);
	if (data == NULL) {
		TIFFError(tif->tif_name,
		    "Cannot write private subdirectory, out of space");
		return (0);
	}
	/*
	 * Place directory in data section of the file. If there isn't one
	 * yet, place it at the end of the file. The directory is treated as
	 * data, so we don't link it into the directory structure at all.
	 */
	if (tif->tif_dataoff == 0)
	    tif->tif_dataoff =(TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1;
	diroff = tif->tif_dataoff;
	tif->tif_dataoff = (toff_t)(
	    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.
	 */
	/*
	 * We make a local copy of the fieldsset here so that we don't mess
	 * up the original one when we call ResetFieldBit(). But I'm not sure
	 * why the original code calls ResetFieldBit(), since we're already
	 * going through the fields in order...
	 *
	 * fields_size is the number of uint32's we will need to hold the
	 * bit-mask for all of the fields. If our highest field number is
	 * 100, then we'll need 100 / (8*4)+1 == 4 uint32's to hold the
	 * fieldset.
	 *
	 * Unlike the original code, we allocate fields dynamically based
	 * on the requested pdir_fields_last value, allowing private
	 * data subdirectories to contain more than the built-in code's limit
	 * of 95 tags in a directory.
	 */
	fields_size = pdir_fields_last / (8*sizeof(uint32)) + 1;
	fields = _TIFFmalloc(fields_size*sizeof(uint32));
	_TIFFmemcpy(fields, pdir_fieldsset, fields_size * sizeof(uint32));

	/* Deleted "write out extra samples tag" code here. */

	/* Deleted code for checking a billion little special cases for the
	 * standard TIFF tags. Should add a general mechanism for overloading
	 * write function for each field, just like Brian kept telling me!!!
	 */
	for (fip = field_info; fip->field_tag; fip++) {
		/* Deleted code to check for FIELD_IGNORE!! */
		if (/* fip->field_bit == FIELD_IGNORE || */
		    !FieldSet(fields, fip->field_bit))
			continue;
		if (!TIFFWriteNormalSubTag(tif, dir, fip, getFieldFn))
			goto bad;
		dir++;
		ResetFieldBit(fields, fip->field_bit);
	}

	/* Now we've written all of the referenced data, and are about to
	   write the main directory structure, so grab the tif_dataoff value
	   now so we can remember where we wrote the directory. */
	directory_offset = tif->tif_dataoff;

	/*
	 * Write directory.
	 */
	dircount = (uint16) nfields;
	/* Deleted code to link to the next directory - we set it to zero! */
	nextdiroff = 0;
	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(&nextdiroff);
	}

	(void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET);
	if (!WriteOK(tif, &dircount, sizeof (dircount))) {
		TIFFError(tif->tif_name, "Error writing private subdirectory count");
		goto bad;
	}
	if (!WriteOK(tif, data, dirsize)) {
		TIFFError(tif->tif_name, "Error writing private subdirectory contents");
		goto bad;
	}
	if (!WriteOK(tif, &nextdiroff, sizeof (nextdiroff))) {
		TIFFError(tif->tif_name, "Error writing private subdirectory link");
		goto bad;
	}
	tif->tif_dataoff += sizeof(dircount) + dirsize + sizeof(nextdiroff);

	_TIFFfree(data);
	_TIFFfree(fields);
	tif->tif_flags &= ~TIFF_DIRTYDIRECT;

#if (0)
	/* This stuff commented out because I don't think we want it for
	   subdirectories, but I could be wrong. */
	(*tif->tif_cleanup)(tif);

	/*
	 * Reset directory-related state for subsequent
	 * directories.
	 */
	TIFFDefaultDirectory(tif);
	tif->tif_curoff = 0;
	tif->tif_row = (uint32) -1;
	tif->tif_curstrip = (tstrip_t) -1;
#endif

	return (directory_offset);
bad:
	_TIFFfree(data);
	_TIFFfree(fields);
	return (0);
}
Ejemplo n.º 13
0
static int
tiffcvt(TIFF* in, TIFF* out)
{
	uint32 width, height;		/* image width & height */
	uint32* raster;			/* retrieve RGBA image */
	uint16 shortv;
	float floatv;
	char *stringv;
	uint32 longv;
	int result;
	size_t pixel_count;

	TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
	TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
	pixel_count = width * height;

 	/* XXX: Check the integer overflow. */
 	if (!width || !height || pixel_count / width != height) {
 		TIFFError(TIFFFileName(in),
 			  "Malformed input file; "
 			  "can't allocate buffer for raster of %lux%lu size",
 			  (unsigned long)width, (unsigned long)height);
 		return 0;
 	}
 
 	raster = (uint32*)_TIFFCheckMalloc(in, pixel_count, sizeof(uint32),
 					   "raster buffer");
  	if (raster == 0) {
 		TIFFError(TIFFFileName(in),
 			  "Failed to allocate buffer (%lu elements of %lu each)",
 			  (unsigned long)pixel_count,
 			  (unsigned long)sizeof(uint32));
  		return (0);
  	}

	if (!TIFFReadRGBAImage(in, width, height, raster, 0)) {
		_TIFFfree(raster);
		return (0);
	}

	CopyField(TIFFTAG_SUBFILETYPE, longv);
	TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
	TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
	TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
	TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
	TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
	if (compression == COMPRESSION_JPEG)
		TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RAW);
	CopyField(TIFFTAG_FILLORDER, shortv);
	TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
	TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
	CopyField(TIFFTAG_XRESOLUTION, floatv);
	CopyField(TIFFTAG_YRESOLUTION, floatv);
	CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
	TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
	{ char buf[2048];
	  char *cp = strrchr(TIFFFileName(in), '/');
	  sprintf(buf, "YCbCr conversion of %s", cp ? cp+1 : TIFFFileName(in));
	  TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, buf);
	}
	TIFFSetField(out, TIFFTAG_SOFTWARE, TIFFGetVersion());
	CopyField(TIFFTAG_DOCUMENTNAME, stringv);

	TIFFSetField(out, TIFFTAG_REFERENCEBLACKWHITE, refBlackWhite);
	TIFFSetField(out, TIFFTAG_YCBCRSUBSAMPLING,
	    horizSubSampling, vertSubSampling);
	TIFFSetField(out, TIFFTAG_YCBCRPOSITIONING, YCBCRPOSITION_CENTERED);
	TIFFSetField(out, TIFFTAG_YCBCRCOEFFICIENTS, ycbcrCoeffs);
	rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
	TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);

	result = cvtRaster(out, raster, width, height);
        _TIFFfree(raster);
        return result;
}
Ejemplo n.º 14
0
static int
cvt_whole_image( TIFF *in, TIFF *out )

{
    uint32* raster;			/* retrieve RGBA image */
    uint32  width, height;		/* image width & height */
    uint32  row;
        
    TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
    TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);

    rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
    TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);

    raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32));
    if (raster == 0) {
        TIFFError(TIFFFileName(in), "No space for raster buffer");
        return (0);
    }

    /* Read the image in one chunk into an RGBA array */
    if (!TIFFReadRGBAImageOriented(in, width, height, raster,
                                   ORIENTATION_TOPLEFT, 0)) {
        _TIFFfree(raster);
        return (0);
    }

    /*
    ** Do we want to strip away alpha components?
    */
    if( no_alpha )
    {
        int	pixel_count = width * height;
        unsigned char *src, *dst;

        src = (unsigned char *) raster;
        dst = (unsigned char *) raster;
        while( pixel_count > 0 )
        {
            *(dst++) = *(src++);
            *(dst++) = *(src++);
            *(dst++) = *(src++);
            src++;
            pixel_count--;
        }
    }

    /* Write out the result in strips */

    for( row = 0; row < height; row += rowsperstrip )
    {
        unsigned char * raster_strip;
        int	rows_to_write;
        int	bytes_per_pixel;

        if( no_alpha )
        {
            raster_strip = ((unsigned char *) raster) + 3 * row * width;
            bytes_per_pixel = 3;
        }
        else
        {
            raster_strip = (unsigned char *) (raster + row * width);
            bytes_per_pixel = 4;
        }

        if( row + rowsperstrip > height )
            rows_to_write = height - row;
        else
            rows_to_write = rowsperstrip;

        if( TIFFWriteEncodedStrip( out, row / rowsperstrip, raster_strip,
                             bytes_per_pixel * rows_to_write * width ) == -1 )
        {
            _TIFFfree( raster );
            return 0;
        }
    }

    _TIFFfree( raster );

    return 1;
}
Ejemplo n.º 15
0
/*
 * Read the next TIFF directory from a file
 * and convert it to the internal format.
 * We read directories sequentially.
 */
int
TIFFReadDirectory(TIFF* tif)
{
	register TIFFDirEntry* dp;
	register int n;
	register TIFFDirectory* td;
	TIFFDirEntry* dir;
	int iv;
	long v;
	double dv;
	const TIFFFieldInfo* fip;
	int fix;
	uint16 dircount;
	uint32 nextdiroff;
	char* cp;
	int diroutoforderwarning = 0;

	tif->tif_diroff = tif->tif_nextdiroff;
	if (tif->tif_diroff == 0)		/* no more directories */
		return (0);
	/*
	 * Cleanup any previous compression state.
	 */
	(*tif->tif_cleanup)(tif);
	tif->tif_curdir++;
	nextdiroff = 0;
	if (!isMapped(tif)) {
		if (!SeekOK(tif, tif->tif_diroff)) {
			TIFFError(tif->tif_name,
			    "Seek error accessing TIFF directory");
			return (0);
		}
		if (!ReadOK(tif, &dircount, sizeof (uint16))) {
			TIFFError(tif->tif_name,
			    "Can not read TIFF directory count");
			return (0);
		}
		if (tif->tif_flags & TIFF_SWAB)
			TIFFSwabShort(&dircount);
		dir = (TIFFDirEntry *)CheckMalloc(tif,
		    dircount * sizeof (TIFFDirEntry), "to read TIFF directory");
		if (dir == NULL)
			return (0);
		if (!ReadOK(tif, dir, dircount*sizeof (TIFFDirEntry))) {
			TIFFError(tif->tif_name, "Can not read TIFF directory");
			goto bad;
		}
		/*
		 * Read offset to next directory for sequential scans.
		 */
		(void) ReadOK(tif, &nextdiroff, sizeof (uint32));
	} else {
		toff_t off = tif->tif_diroff;

		if ((tsize_t) (off + sizeof (uint16)) > tif->tif_size) {
			TIFFError(tif->tif_name,
			    "Can not read TIFF directory count");
			return (0);
		} else
			_TIFFmemcpy(&dircount, tif->tif_base + off, sizeof (uint16));
		off += sizeof (uint16);
		if (tif->tif_flags & TIFF_SWAB)
			TIFFSwabShort(&dircount);
		dir = (TIFFDirEntry *)CheckMalloc(tif,
		    dircount * sizeof (TIFFDirEntry), "to read TIFF directory");
		if (dir == NULL)
			return (0);
		if (((tsize_t) (off + dircount*sizeof (TIFFDirEntry)))
                                                   > tif->tif_size) {
			TIFFError(tif->tif_name, "Can not read TIFF directory");
			goto bad;
		} else
			_TIFFmemcpy(dir, tif->tif_base + off,
			    dircount*sizeof (TIFFDirEntry));
		off += dircount* sizeof (TIFFDirEntry);
		if (((tsize_t)(off + sizeof (uint32))) <= tif->tif_size)
			_TIFFmemcpy(&nextdiroff, tif->tif_base+off, sizeof (uint32));
	}
	if (tif->tif_flags & TIFF_SWAB)
		TIFFSwabLong(&nextdiroff);
	tif->tif_nextdiroff = nextdiroff;

	tif->tif_flags &= ~TIFF_BEENWRITING;	/* reset before new dir */
	/*
	 * Setup default value and then make a pass over
	 * the fields to check type and tag information,
	 * and to extract info required to size data
	 * structures.  A second pass is made afterwards
	 * to read in everthing not taken in the first pass.
	 */
	td = &tif->tif_dir;
	/* free any old stuff and reinit */
	TIFFFreeDirectory(tif);
	TIFFDefaultDirectory(tif);
	/*
	 * Electronic Arts writes gray-scale TIFF files
	 * without a PlanarConfiguration directory entry.
	 * Thus we setup a default value here, even though
	 * the TIFF spec says there is no default value.
	 */
	TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);

	/*
	 * Sigh, we must make a separate pass through the
	 * directory for the following reason:
	 *
	 * We must process the Compression tag in the first pass
	 * in order to merge in codec-private tag definitions (otherwise
	 * we may get complaints about unknown tags).  However, the
	 * Compression tag may be dependent on the SamplesPerPixel
	 * tag value because older TIFF specs permited Compression
	 * to be written as a SamplesPerPixel-count tag entry.
	 * Thus if we don't first figure out the correct SamplesPerPixel
	 * tag value then we may end up ignoring the Compression tag
	 * value because it has an incorrect count value (if the
	 * true value of SamplesPerPixel is not 1).
	 *
	 * It sure would have been nice if Aldus had really thought
	 * this stuff through carefully.
	 */ 
	for (dp = dir, n = dircount; n > 0; n--, dp++) {
		if (tif->tif_flags & TIFF_SWAB) {
			TIFFSwabArrayOfShort(&dp->tdir_tag, 2);
			TIFFSwabArrayOfLong(&dp->tdir_count, 2);
		}
		if (dp->tdir_tag == TIFFTAG_SAMPLESPERPIXEL) {
			if (!TIFFFetchNormalTag(tif, dp))
				goto bad;
			dp->tdir_tag = IGNORE;
		}
	}
	/*
	 * First real pass over the directory.
	 */
	fix = 0;
	for (dp = dir, n = dircount; n > 0; n--, dp++) {

                /*
                 * Find the field information entry for this tag.
		 * Added check for tags to ignore ... [BFC]
                 */
		if( TIFFReassignTagToIgnore(TIS_EXTRACT, dp->tdir_tag) )
                    dp->tdir_tag = IGNORE;

		if (dp->tdir_tag == IGNORE)
                    continue;
                
		/*
		 * Silicon Beach (at least) writes unordered
		 * directory tags (violating the spec).  Handle
		 * it here, but be obnoxious (maybe they'll fix it?).
		 */
		if (dp->tdir_tag < tif->tif_fieldinfo[fix]->field_tag) {
			if (!diroutoforderwarning) {
				TIFFWarning(tif->tif_name,
	"invalid TIFF directory; tags are not sorted in ascending order");
				diroutoforderwarning = 1;
			}
			fix = 0;			/* O(n^2) */
		}
		while (fix < tif->tif_nfields &&
		    tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag)
			fix++;
		if (fix == tif->tif_nfields ||
		    tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) {
			TIFFWarning(tif->tif_name,
			    "unknown field with tag %d (0x%x) ignored",
			    dp->tdir_tag,  dp->tdir_tag);
			dp->tdir_tag = IGNORE;
			fix = 0;			/* restart search */
			continue;
		}
		/*
		 * Null out old tags that we ignore.
		 */
		if (tif->tif_fieldinfo[fix]->field_bit == FIELD_IGNORE) {
	ignore:
			dp->tdir_tag = IGNORE;
			continue;
		}
		/*
		 * Check data type.
		 */
		fip = tif->tif_fieldinfo[fix];
		while (dp->tdir_type != (u_short) fip->field_type) {
			if (fip->field_type == TIFF_ANY)	/* wildcard */
				break;
			fip++, fix++;
			if (fix == tif->tif_nfields ||
			    fip->field_tag != dp->tdir_tag) {
				TIFFWarning(tif->tif_name,
				   "wrong data type %d for \"%s\"; tag ignored",
				    dp->tdir_type, fip[-1].field_name);
				goto ignore;
			}
		}
		/*
		 * Check count if known in advance.
		 */
		if (fip->field_readcount != TIFF_VARIABLE) {
			uint32 expected = (fip->field_readcount == TIFF_SPP) ?
			    (uint32) td->td_samplesperpixel :
			    (uint32) fip->field_readcount;
			if (!CheckDirCount(tif, dp, expected))
				goto ignore;
		}

		switch (dp->tdir_tag) {
		case TIFFTAG_COMPRESSION:
			/*
			 * The 5.0 spec says the Compression tag has
			 * one value, while earlier specs say it has
			 * one value per sample.  Because of this, we
			 * accept the tag if one value is supplied.
			 */
			if (dp->tdir_count == 1) {
				v = TIFFExtractData(tif,
				    dp->tdir_type, dp->tdir_offset);
				if (!TIFFSetField(tif, dp->tdir_tag, (int)v))
					goto bad;
				break;
			}
			if (!TIFFFetchPerSampleShorts(tif, dp, &iv) ||
			    !TIFFSetField(tif, dp->tdir_tag, iv))
				goto bad;
			dp->tdir_tag = IGNORE;
			break;
		case TIFFTAG_STRIPOFFSETS:
		case TIFFTAG_STRIPBYTECOUNTS:
		case TIFFTAG_TILEOFFSETS:
		case TIFFTAG_TILEBYTECOUNTS:
			TIFFSetFieldBit(tif, fip->field_bit);
			break;
		case TIFFTAG_IMAGEWIDTH:
		case TIFFTAG_IMAGELENGTH:
		case TIFFTAG_IMAGEDEPTH:
		case TIFFTAG_TILELENGTH:
		case TIFFTAG_TILEWIDTH:
		case TIFFTAG_TILEDEPTH:
		case TIFFTAG_PLANARCONFIG:
		case TIFFTAG_ROWSPERSTRIP:
			if (!TIFFFetchNormalTag(tif, dp))
				goto bad;
			dp->tdir_tag = IGNORE;
			break;
		case TIFFTAG_EXTRASAMPLES:
			(void) TIFFFetchExtraSamples(tif, dp);
			dp->tdir_tag = IGNORE;
			break;
		}
	}

	/*
	 * Allocate directory structure and setup defaults.
	 */
	if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) {
		MissingRequired(tif, "ImageLength");
		goto bad;
	}
	if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) {
		MissingRequired(tif, "PlanarConfiguration");
		goto bad;
	}
	/* 
 	 * Setup appropriate structures (by strip or by tile)
	 */
	if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
		td->td_nstrips = TIFFNumberOfStrips(tif);
		td->td_tilewidth = td->td_imagewidth;
		td->td_tilelength = td->td_rowsperstrip;
		td->td_tiledepth = td->td_imagedepth;
		tif->tif_flags &= ~TIFF_ISTILED;
	} else {
		td->td_nstrips = TIFFNumberOfTiles(tif);
		tif->tif_flags |= TIFF_ISTILED;
	}
	td->td_stripsperimage = td->td_nstrips;
	if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
		td->td_stripsperimage /= td->td_samplesperpixel;
	if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) {
		MissingRequired(tif,
		    isTiled(tif) ? "TileOffsets" : "StripOffsets");
		goto bad;
	}

	/*
	 * Second pass: extract other information.
	 */
	for (dp = dir, n = dircount; n > 0; n--, dp++) {
		if (dp->tdir_tag == IGNORE)
			continue;
		switch (dp->tdir_tag) {
		case TIFFTAG_MINSAMPLEVALUE:
		case TIFFTAG_MAXSAMPLEVALUE:
		case TIFFTAG_BITSPERSAMPLE:
			/*
			 * The 5.0 spec says the Compression tag has
			 * one value, while earlier specs say it has
			 * one value per sample.  Because of this, we
			 * accept the tag if one value is supplied.
			 *
			 * The MinSampleValue, MaxSampleValue and
			 * BitsPerSample tags are supposed to be written
			 * as one value/sample, but some vendors incorrectly
			 * write one value only -- so we accept that
			 * as well (yech).
			 */
			if (dp->tdir_count == 1) {
				v = TIFFExtractData(tif,
				    dp->tdir_type, dp->tdir_offset);
				if (!TIFFSetField(tif, dp->tdir_tag, (int)v))
					goto bad;
				break;
			}
			/* fall thru... */
		case TIFFTAG_DATATYPE:
		case TIFFTAG_SAMPLEFORMAT:
			if (!TIFFFetchPerSampleShorts(tif, dp, &iv) ||
			    !TIFFSetField(tif, dp->tdir_tag, iv))
				goto bad;
			break;
		case TIFFTAG_SMINSAMPLEVALUE:
		case TIFFTAG_SMAXSAMPLEVALUE:
			if (!TIFFFetchPerSampleAnys(tif, dp, &dv) ||
			    !TIFFSetField(tif, dp->tdir_tag, dv))
				goto bad;
			break;
		case TIFFTAG_STRIPOFFSETS:
		case TIFFTAG_TILEOFFSETS:
			if (!TIFFFetchStripThing(tif, dp,
			    td->td_nstrips, &td->td_stripoffset))
				goto bad;
			break;
		case TIFFTAG_STRIPBYTECOUNTS:
		case TIFFTAG_TILEBYTECOUNTS:
			if (!TIFFFetchStripThing(tif, dp,
			    td->td_nstrips, &td->td_stripbytecount))
				goto bad;
			break;
		case TIFFTAG_COLORMAP:
		case TIFFTAG_TRANSFERFUNCTION:
			/*
			 * TransferFunction can have either 1x or 3x data
			 * values; Colormap can have only 3x items.
			 */
			v = 1L<<td->td_bitspersample;
			if (dp->tdir_tag == TIFFTAG_COLORMAP ||
			    dp->tdir_count != (uint32) v) {
				if (!CheckDirCount(tif, dp, (uint32)(3*v)))
					break;
			}
			v *= sizeof (uint16);
			cp = CheckMalloc(tif, dp->tdir_count * sizeof (uint16),
			    "to read \"TransferFunction\" tag");
			if (cp != NULL) {
				if (TIFFFetchData(tif, dp, cp)) {
					/*
					 * This deals with there being only
					 * one array to apply to all samples.
					 */
					uint32 c =
					    (uint32)1 << td->td_bitspersample;
					if (dp->tdir_count == c)
						v = 0;
					TIFFSetField(tif, dp->tdir_tag,
					    cp, cp+v, cp+2*v);
				}
				_TIFFfree(cp);
			}
			break;
		case TIFFTAG_PAGENUMBER:
		case TIFFTAG_HALFTONEHINTS:
		case TIFFTAG_YCBCRSUBSAMPLING:
		case TIFFTAG_DOTRANGE:
			(void) TIFFFetchShortPair(tif, dp);
			break;
#ifdef COLORIMETRY_SUPPORT
		case TIFFTAG_REFERENCEBLACKWHITE:
			(void) TIFFFetchRefBlackWhite(tif, dp);
			break;
#endif
/* BEGIN REV 4.0 COMPATIBILITY */
		case TIFFTAG_OSUBFILETYPE:
			v = 0;
			switch (TIFFExtractData(tif, dp->tdir_type,
			    dp->tdir_offset)) {
			case OFILETYPE_REDUCEDIMAGE:
				v = FILETYPE_REDUCEDIMAGE;
				break;
			case OFILETYPE_PAGE:
				v = FILETYPE_PAGE;
				break;
			}
			if (v)
				(void) TIFFSetField(tif,
				    TIFFTAG_SUBFILETYPE, (int)v);
			break;
/* END REV 4.0 COMPATIBILITY */
		default:
			(void) TIFFFetchNormalTag(tif, dp);
			break;
		}
	}
	/*
	 * Verify Palette image has a Colormap.
	 */
	if (td->td_photometric == PHOTOMETRIC_PALETTE &&
	    !TIFFFieldSet(tif, FIELD_COLORMAP)) {
		MissingRequired(tif, "Colormap");
		goto bad;
	}
	/*
	 * Attempt to deal with a missing StripByteCounts tag.
	 */
	if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) {
		/*
		 * Some manufacturers violate the spec by not giving
		 * the size of the strips.  In this case, assume there
		 * is one uncompressed strip of data.
		 */
		if ((td->td_planarconfig == PLANARCONFIG_CONTIG &&
		    td->td_nstrips > 1) ||
		    (td->td_planarconfig == PLANARCONFIG_SEPARATE &&
		     td->td_nstrips != td->td_samplesperpixel)) {
		    MissingRequired(tif, "StripByteCounts");
		    goto bad;
		}
		TIFFWarning(tif->tif_name,
"TIFF directory is missing required \"%s\" field, calculating from imagelength",
		    _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name);
		EstimateStripByteCounts(tif, dir, dircount);
#define	BYTECOUNTLOOKSBAD \
    (td->td_stripbytecount[0] == 0 || \
    (td->td_compression == COMPRESSION_NONE && \
     td->td_stripbytecount[0] > TIFFGetFileSize(tif) - td->td_stripoffset[0]))
	} else if (td->td_nstrips == 1 && BYTECOUNTLOOKSBAD) {
		/*
		 * Plexus (and others) sometimes give a value
		 * of zero for a tag when they don't know what
		 * the correct value is!  Try and handle the
		 * simple case of estimating the size of a one
		 * strip image.
		 */
		TIFFWarning(tif->tif_name,
	    "Bogus \"%s\" field, ignoring and calculating from imagelength",
		    _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name);
		EstimateStripByteCounts(tif, dir, dircount);
	}
	if (dir)
		_TIFFfree((char *)dir);
	if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE))
		td->td_maxsamplevalue = (uint16)((1L<<td->td_bitspersample)-1);
	/*
	 * Setup default compression scheme.
	 */
	if (!TIFFFieldSet(tif, FIELD_COMPRESSION))
		TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
        /*
         * Some manufacturers make life difficult by writing
	 * large amounts of uncompressed data as a single strip.
	 * This is contrary to the recommendations of the spec.
         * The following makes an attempt at breaking such images
	 * into strips closer to the recommended 8k bytes.  A
	 * side effect, however, is that the RowsPerStrip tag
	 * value may be changed.
         */
	if (td->td_nstrips == 1 && td->td_compression == COMPRESSION_NONE &&
	    (tif->tif_flags & (TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP)
		ChopUpSingleUncompressedStrip(tif);
	/*
	 * Reinitialize i/o since we are starting on a new directory.
	 */
	tif->tif_row = (uint32) -1;
	tif->tif_curstrip = (tstrip_t) -1;
	tif->tif_col = (uint32) -1;
	tif->tif_curtile = (ttile_t) -1;
	tif->tif_tilesize = TIFFTileSize(tif);
	tif->tif_scanlinesize = TIFFScanlineSize(tif);
	return (1);
bad:
	if (dir)
		_TIFFfree(dir);
	return (0);
}
Ejemplo n.º 16
0
int
TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024])
{
    uint16* sampleinfo;
    uint16 extrasamples;
    uint16 planarconfig;
    int colorchannels;

    img->tif = tif;
    img->stoponerr = stop;
    TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample);
    switch (img->bitspersample) {
    case 1: case 2: case 4:
    case 8: case 16:
    break;
    default:
    sprintf(emsg, "Sorry, can not image with %d-bit samples",
    img->bitspersample);
    return (0);
    }
    img->alpha = 0;
    TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel);
    TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES,
    &extrasamples, &sampleinfo);
    if (extrasamples == 1)
    switch (sampleinfo[0]) {
    case EXTRASAMPLE_ASSOCALPHA:    /* data is pre-multiplied */
    case EXTRASAMPLE_UNASSALPHA:    /* data is not pre-multiplied */
    img->alpha = sampleinfo[0];
    break;
    }
    colorchannels = img->samplesperpixel - extrasamples;
    TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
    if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) {
    switch (colorchannels) {
    case 1:
    if (isCCITTCompression(tif))
    img->photometric = PHOTOMETRIC_MINISWHITE;
    else
    img->photometric = PHOTOMETRIC_MINISBLACK;
    break;
    case 3:
    img->photometric = PHOTOMETRIC_RGB;
    break;
    default:
    sprintf(emsg, "Missing needed %s tag", photoTag);
    return (0);
    }
    }
    switch (img->photometric) {
    case PHOTOMETRIC_PALETTE:
    if (!TIFFGetField(tif, TIFFTAG_COLORMAP,
    &img->redcmap, &img->greencmap, &img->bluecmap)) {
    TIFFError(TIFFFileName(tif), "Missing required \"Colormap\" tag");
    return (0);
    }
    /* fall thru... */
    case PHOTOMETRIC_MINISWHITE:
    case PHOTOMETRIC_MINISBLACK:
    if (planarconfig == PLANARCONFIG_CONTIG && img->samplesperpixel != 1) {
    sprintf(emsg,
    "Sorry, can not handle contiguous data with %s=%d, and %s=%d",
    photoTag, img->photometric,
    "Samples/pixel", img->samplesperpixel);
    return (0);
    }
    break;
    case PHOTOMETRIC_YCBCR:
    if (planarconfig != PLANARCONFIG_CONTIG) {
    sprintf(emsg, "Sorry, can not handle YCbCr images with %s=%d",
    "Planarconfiguration", planarconfig);
    return (0);
    }
    /* It would probably be nice to have a reality check here. */
    { uint16 compress;
      TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress);
      if (compress == COMPRESSION_JPEG && planarconfig == PLANARCONFIG_CONTIG) {
    /* can rely on libjpeg to convert to RGB */
    /* XXX should restore current state on exit */
    TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
    img->photometric = PHOTOMETRIC_RGB;
      }
    }
    break;
    case PHOTOMETRIC_RGB:
    if (colorchannels < 3) {
    sprintf(emsg, "Sorry, can not handle RGB image with %s=%d",
    "Color channels", colorchannels);
    return (0);
    }
    break;
    case PHOTOMETRIC_SEPARATED: {
    uint16 inkset;
    TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset);
    if (inkset != INKSET_CMYK) {
    sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
    "InkSet", inkset);
    return (0);
    }
    if (img->samplesperpixel != 4) {
    sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
    "Samples/pixel", img->samplesperpixel);
    return (0);
    }
    break;
    }
    default:
    sprintf(emsg, "Sorry, can not handle image with %s=%d",
    photoTag, img->photometric);
    return (0);
    }
    img->Map = NULL;
    img->BWmap = NULL;
    img->PALmap = NULL;
    img->ycbcr = NULL;
    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width);
    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height);
    TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation);
    img->isContig =
    !(planarconfig == PLANARCONFIG_SEPARATE && colorchannels > 1);
    if (img->isContig) {
    img->get = TIFFIsTiled(tif) ? gtTileContig : gtStripContig;
    (void) pickTileContigCase(img);
    } else {
    img->get = TIFFIsTiled(tif) ? gtTileSeparate : gtStripSeparate;
    (void) pickTileSeparateCase(img);
    }
    return (1);
}
Ejemplo n.º 17
0
/*
 * 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.
 */
int
TIFFWriteDirectory(TIFF* tif)
{
	uint16 dircount;
	uint32 diroff;
	ttag_t tag;
	uint32 nfields;
	tsize_t dirsize;
	char* data;
	TIFFDirEntry* dir;
	TIFFDirectory* td;
	u_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 (tif->tif_flags & TIFF_POSTENCODE) {
		tif->tif_flags &= ~TIFF_POSTENCODE;
		if (!(*tif->tif_postencode)(tif)) {
			TIFFError(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)) {
		TIFFError(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_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))
			nfields += (b < FIELD_SUBFILETYPE ? 2 : 1);
	dirsize = nfields * sizeof (TIFFDirEntry);
	data = (char*) _TIFFmalloc(dirsize);
	if (data == NULL) {
		TIFFError(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];
		if (!FieldSet(fields, fip->field_bit))
			continue;
		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;
			if (!TIFFWriteLongArray(tif, TIFF_LONG, tag, dir,
			    (uint32) td->td_nstrips, 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;
			if (!TIFFWriteLongArray(tif, TIFF_LONG, tag, dir,
			    (uint32) td->td_nstrips, 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_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:
#ifdef YCBCR_SUPPORT
		case FIELD_YCBCRSUBSAMPLING:
#endif
#ifdef CMYK_SUPPORT
		case FIELD_DOTRANGE:
#endif
			if (!TIFFSetupShortPair(tif, fip->field_tag, dir))
				goto bad;
			break;
#ifdef CMYK_SUPPORT
		case FIELD_INKNAMES:
			if (!TIFFWriteInkNames(tif, dir))
				goto bad;
			break;
#endif
#ifdef COLORIMETRY_SUPPORT
		case FIELD_TRANSFERFUNCTION:
			if (!TIFFWriteTransferFunction(tif, dir))
				goto bad;
			break;
#endif
#if SUBIFD_SUPPORT
		case FIELD_SUBIFD:
			if (!TIFFWriteNormalTag(tif, dir, fip))
				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;
#endif
		default:
			if (!TIFFWriteNormalTag(tif, dir, fip))
				goto bad;
			break;
		}
		dir++;
		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))) {
		TIFFError(tif->tif_name, "Error writing directory count");
		goto bad;
	}
	if (!WriteOK(tif, data, dirsize)) {
		TIFFError(tif->tif_name, "Error writing directory contents");
		goto bad;
	}
	if (!WriteOK(tif, &diroff, sizeof (diroff))) {
		TIFFError(tif->tif_name, "Error writing directory link");
		goto bad;
	}
	TIFFFreeDirectory(tif);
	_TIFFfree(data);
	tif->tif_flags &= ~TIFF_DIRTYDIRECT;
	(*tif->tif_cleanup)(tif);

	/*
	 * Reset directory-related state for subsequent
	 * directories.
	 */
	TIFFDefaultDirectory(tif);
	tif->tif_diroff = 0;
	tif->tif_curoff = 0;
	tif->tif_row = (uint32) -1;
	tif->tif_curstrip = (tstrip_t) -1;
	return (1);
bad:
	_TIFFfree(data);
	return (0);
}
Ejemplo n.º 18
0
/*
 * Get an tile-organized image that has
 *   SamplesPerPixel > 1
 *   PlanarConfiguration separated
 * We assume that all such images are RGB.
 */ 
static int
gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
{
    TIFF* tif = img->tif;
    tileSeparateRoutine put = img->put.separate;
    uint16 orientation;
    uint32 col, row, y;
    uint32 tw, th;
    u_char* buf;
    u_char* r;
    u_char* g;
    u_char* b;
    u_char* a;
    tsize_t tilesize;
    int32 fromskew, toskew;
    int alpha = img->alpha;
    uint32 nrow;

    tilesize = TIFFTileSize(tif);
    buf = (u_char*) _TIFFmalloc(4*tilesize);
    if (buf == 0) {
    TIFFError(TIFFFileName(tif), "No space for tile buffer");
    return (0);
    }
    r = buf;
    g = r + tilesize;
    b = g + tilesize;
    a = b + tilesize;
    if (!alpha)
    memset(a, 0xff, tilesize);
    TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
    TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
    y = setorientation(img, h);
    orientation = img->orientation;
    toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? tw+w : tw-w);
    for (row = 0; row < h; row += th) {
    nrow = (row + th > h ? h - row : th);
    for (col = 0; col < w; col += tw) {
    if (TIFFReadTile(tif, r, col, row,0,0) < 0 && img->stoponerr)
    break;
    if (TIFFReadTile(tif, g, col, row,0,1) < 0 && img->stoponerr)
    break;
    if (TIFFReadTile(tif, b, col, row,0,2) < 0 && img->stoponerr)
    break;
    if (alpha && TIFFReadTile(tif,a,col,row,0,3) < 0 && img->stoponerr)
    break;
    if (col + tw > w) {
    /*
     * Tile is clipped horizontally.  Calculate
     * visible portion and skewing factors.
     */
    uint32 npix = w - col;
    fromskew = tw - npix;
    (*put)(img, raster+y*w+col, col, y,
        npix, nrow, fromskew, toskew + fromskew, r, g, b, a);
    } else {
    (*put)(img, raster+y*w+col, col, y,
        tw, nrow, 0, toskew, r, g, b, a);
    }
    }
    y += (orientation == ORIENTATION_TOPLEFT ?
    -(int32) nrow : (int32) nrow);
    }
    _TIFFfree(buf);
    return (1);
}
Ejemplo n.º 19
0
/*
 * Append the data to the specified strip.
 */
static int
TIFFAppendToStrip(TIFF* tif, tstrip_t strip, tidata_t data, tsize_t cc) {
    TIFFDirectory* td = &tif->tif_dir;
    static const char module[] = "TIFFAppendToStrip";

    if (td->td_stripoffset[strip] == 0 || tif->tif_curoff == 0) {
        /*
         * No current offset, set the current strip.
         */
        assert(td->td_nstrips > 0);
        if (td->td_stripoffset[strip] != 0) {
            /*
             * Prevent overlapping of the data chunks. We need
                         * this to enable in place updating of the compressed
                         * images. Larger blocks will be moved at the end of
                         * the file without any optimization of the spare
                         * space, so such scheme is not too much effective.
             */
            if (td->td_stripbytecountsorted) {
                if (strip == td->td_nstrips - 1
                        || td->td_stripoffset[strip + 1] <
                        td->td_stripoffset[strip] + cc) {
                    td->td_stripoffset[strip] =
                        TIFFSeekFile(tif, (toff_t)0,
                                     SEEK_END);
                }
            } else {
                tstrip_t i;
                for (i = 0; i < td->td_nstrips; i++) {
                    if (td->td_stripoffset[i] >
                            td->td_stripoffset[strip]
                            && td->td_stripoffset[i] <
                            td->td_stripoffset[strip] + cc) {
                        td->td_stripoffset[strip] =
                            TIFFSeekFile(tif,
                                         (toff_t)0,
                                         SEEK_END);
                    }
                }
            }

            if (!SeekOK(tif, td->td_stripoffset[strip])) {
                TIFFError(module,
                          "%s: Seek error at scanline %lu",
                          tif->tif_name,
                          (unsigned long)tif->tif_row);
                return (0);
            }
        } else
            td->td_stripoffset[strip] =
                TIFFSeekFile(tif, (toff_t) 0, SEEK_END);
        tif->tif_curoff = td->td_stripoffset[strip];
    }

    if (!WriteOK(tif, data, cc)) {
        TIFFError(module, "%s: Write error at scanline %lu",
                  tif->tif_name, (unsigned long) tif->tif_row);
        return (0);
    }
    tif->tif_curoff += cc;
    td->td_stripbytecount[strip] += cc;
    return (1);
}
static int
cvt_by_tile( TIFF *in, TIFF *out )

{
    uint32* raster;			/* retrieve RGBA image */
    uint32  width, height;		/* image width & height */
    uint32  tile_width, tile_height;
    uint32  row, col;
    uint32  *wrk_line;
    int	    ok = 1;

    TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
    TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);

    if( !TIFFGetField(in, TIFFTAG_TILEWIDTH, &tile_width)
        || !TIFFGetField(in, TIFFTAG_TILELENGTH, &tile_height) ) {
        TIFFError(TIFFFileName(in), "Source image not tiled");
        return (0);
    }
    
    TIFFSetField(out, TIFFTAG_TILEWIDTH, tile_width );
    TIFFSetField(out, TIFFTAG_TILELENGTH, tile_height );

    /*
     * Allocate tile buffer
     */
    raster = (uint32*)_TIFFmalloc(tile_width * tile_height * sizeof (uint32));
    if (raster == 0) {
        TIFFError(TIFFFileName(in), "No space for raster buffer");
        return (0);
    }

    /*
     * Allocate a scanline buffer for swapping during the vertical
     * mirroring pass.
     */
    wrk_line = (uint32*)_TIFFmalloc(tile_width * sizeof (uint32));
    if (!wrk_line) {
        TIFFError(TIFFFileName(in), "No space for raster scanline buffer");
        ok = 0;
    }
    
    /*
     * Loop over the tiles.
     */
    for( row = 0; ok && row < height; row += tile_height )
    {
        for( col = 0; ok && col < width; col += tile_width )
        {
            uint32 i_row;

            /* Read the tile into an RGBA array */
            if (!TIFFReadRGBATile(in, col, row, raster)) {
                ok = 0;
                break;
            }


	    /*
	     * XXX: raster array has 4-byte unsigned integer type, that is why
	     * we should rearrange it here.
	     */
#if HOST_BIGENDIAN
	    TIFFSwabArrayOfLong(raster, tile_width * tile_height);
#endif

            /*
             * For some reason the TIFFReadRGBATile() function chooses the
             * lower left corner as the origin.  Vertically mirror scanlines.
             */
            for( i_row = 0; i_row < tile_height / 2; i_row++ )
            {
                uint32	*top_line, *bottom_line;

                top_line = raster + tile_width * i_row;
                bottom_line = raster + tile_width * (tile_height-i_row-1);

                _TIFFmemcpy(wrk_line, top_line, 4*tile_width);
                _TIFFmemcpy(top_line, bottom_line, 4*tile_width);
                _TIFFmemcpy(bottom_line, wrk_line, 4*tile_width);
            }

            /*
             * Write out the result in a tile.
             */

            if( TIFFWriteEncodedTile( out,
                                      TIFFComputeTile( out, col, row, 0, 0),
                                      raster,
                                      4 * tile_width * tile_height ) == -1 )
            {
                ok = 0;
                break;
            }
        }
    }

    _TIFFfree( raster );
    _TIFFfree( wrk_line );

    return ok;
}
Ejemplo n.º 21
0
static int
LZWDecodeCompat(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s)
{
	LZWCodecState *sp = DecoderState(tif);
	char *op = (char*) op0;
	long occ = (long) occ0;
	char *tp;
	u_char *bp;
	int code, nbits;
	long nextbits, nextdata, nbitsmask;
	code_t *codep, *free_entp, *maxcodep, *oldcodep;

	(void) s;
	assert(sp != NULL);
	/*
	 * Restart interrupted output operation.
	 */
	if (sp->dec_restart) {
		long residue;

		codep = sp->dec_codep;
		residue = codep->length - sp->dec_restart;
		if (residue > occ) {
			/*
			 * Residue from previous decode is sufficient
			 * to satisfy decode request.  Skip to the
			 * start of the decoded string, place decoded
			 * values in the output buffer, and return.
			 */
			sp->dec_restart += occ;
			do {
				codep = codep->next;
			} while (--residue > occ);
			tp = op + occ;
			do {
				*--tp = codep->value;
				codep = codep->next;
			} while (--occ);
			return (1);
		}
		/*
		 * Residue satisfies only part of the decode request.
		 */
		op += residue, occ -= residue;
		tp = op;
		do {
			*--tp = codep->value;
			codep = codep->next;
		} while (--residue);
		sp->dec_restart = 0;
	}

	bp = (u_char *)tif->tif_rawcp;
	nbits = sp->lzw_nbits;
	nextdata = sp->lzw_nextdata;
	nextbits = sp->lzw_nextbits;
	nbitsmask = sp->dec_nbitsmask;
	oldcodep = sp->dec_oldcodep;
	free_entp = sp->dec_free_entp;
	maxcodep = sp->dec_maxcodep;

	while (occ > 0) {
		NextCode(tif, sp, bp, code, GetNextCodeCompat);
		if (code == CODE_EOI)
			break;
		if (code == CODE_CLEAR) {
			free_entp = sp->dec_codetab + CODE_FIRST;
			nbits = BITS_MIN;
			nbitsmask = MAXCODE(BITS_MIN);
			maxcodep = sp->dec_codetab + nbitsmask;
			NextCode(tif, sp, bp, code, GetNextCodeCompat);
			if (code == CODE_EOI)
				break;
			*op++ = (char) code, occ--;
			oldcodep = sp->dec_codetab + code;
			continue;
		}
		codep = sp->dec_codetab + code;

		/*
	 	 * Add the new entry to the code table.
	 	 */
		if (free_entp < &sp->dec_codetab[0] ||
			free_entp >= &sp->dec_codetab[CSIZE]) {
			TIFFError(tif->tif_name,
			"LZWDecodeCompat: Corrupted LZW table at scanline %d",
			tif->tif_row);
			return (0);
		}

		free_entp->next = oldcodep;
		if (free_entp->next < &sp->dec_codetab[0] ||
			free_entp->next >= &sp->dec_codetab[CSIZE]) {
			TIFFError(tif->tif_name,
			"LZWDecodeCompat: Corrupted LZW table at scanline %d",
			tif->tif_row);
			return (0);
		}
		free_entp->firstchar = free_entp->next->firstchar;
		free_entp->length = free_entp->next->length+1;
		free_entp->value = (codep < free_entp) ?
		    codep->firstchar : free_entp->firstchar;
		if (++free_entp > maxcodep) {
			if (++nbits > BITS_MAX)		/* should not happen */
				nbits = BITS_MAX;
			nbitsmask = MAXCODE(nbits);
			maxcodep = sp->dec_codetab + nbitsmask;
		}
		oldcodep = codep;
		if (code >= 256) {
			/*
		 	 * Code maps to a string, copy string
			 * value to output (written in reverse).
		 	 */
			if(codep->length == 0) {
			    TIFFError(tif->tif_name,
	    		    "LZWDecodeCompat: Wrong length of decoded "
			    "string: data probably corrupted at scanline %d",
			    tif->tif_row);	
			    return (0);
			}
			if (codep->length > occ) {
				/*
				 * String is too long for decode buffer,
				 * locate portion that will fit, copy to
				 * the decode buffer, and setup restart
				 * logic for the next decoding call.
				 */
				sp->dec_codep = codep;
				do {
					codep = codep->next;
				} while (codep->length > occ);
				sp->dec_restart = occ;
				tp = op + occ;
				do  {
					*--tp = codep->value;
					codep = codep->next;
				}  while (--occ);
				break;
			}
			op += codep->length, occ -= codep->length;
			tp = op;
			do {
				*--tp = codep->value;
			} while( (codep = codep->next) != NULL);
		} else
			*op++ = (char) code, occ--;
	}

	tif->tif_rawcp = (tidata_t) bp;
	sp->lzw_nbits = (u_short) nbits;
	sp->lzw_nextdata = nextdata;
	sp->lzw_nextbits = nextbits;
	sp->dec_nbitsmask = nbitsmask;
	sp->dec_oldcodep = oldcodep;
	sp->dec_free_entp = free_entp;
	sp->dec_maxcodep = maxcodep;

	if (occ > 0) {
		TIFFError(tif->tif_name,
	    "LZWDecodeCompat: Not enough data at scanline %d (short %d bytes)",
		    tif->tif_row, occ);
		return (0);
	}
	return (1);
}
static int
cvt_by_strip( TIFF *in, TIFF *out )

{
    uint32* raster;			/* retrieve RGBA image */
    uint32  width, height;		/* image width & height */
    uint32  row;
    uint32  *wrk_line;
    int	    ok = 1;

    TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
    TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);

    if( !TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip) ) {
        TIFFError(TIFFFileName(in), "Source image not in strips");
        return (0);
    }
    
    TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);

    /*
     * Allocate strip buffer
     */
    raster = (uint32*)_TIFFmalloc(width * rowsperstrip * sizeof (uint32));
    if (raster == 0) {
        TIFFError(TIFFFileName(in), "No space for raster buffer");
        return (0);
    }

    /*
     * Allocate a scanline buffer for swapping during the vertical
     * mirroring pass.
     */
    wrk_line = (uint32*)_TIFFmalloc(width * sizeof (uint32));
    if (!wrk_line) {
        TIFFError(TIFFFileName(in), "No space for raster scanline buffer");
        ok = 0;
    }
    
    /*
     * Loop over the strips.
     */
    for( row = 0; ok && row < height; row += rowsperstrip )
    {
        int	rows_to_write, i_row;

        /* Read the strip into an RGBA array */
        if (!TIFFReadRGBAStrip(in, row, raster)) {
            ok = 0;
            break;
        }

	/*
	 * XXX: raster array has 4-byte unsigned integer type, that is why
	 * we should rearrange it here.
	 */
#if HOST_BIGENDIAN
	TIFFSwabArrayOfLong(raster, width * rowsperstrip);
#endif

        /*
         * Figure out the number of scanlines actually in this strip.
         */
        if( row + rowsperstrip > height )
            rows_to_write = height - row;
        else
            rows_to_write = rowsperstrip;

        /*
         * For some reason the TIFFReadRGBAStrip() function chooses the
         * lower left corner as the origin.  Vertically mirror scanlines.
         */

        for( i_row = 0; i_row < rows_to_write / 2; i_row++ )
        {
            uint32	*top_line, *bottom_line;

            top_line = raster + width * i_row;
            bottom_line = raster + width * (rows_to_write-i_row-1);

            _TIFFmemcpy(wrk_line, top_line, 4*width);
            _TIFFmemcpy(top_line, bottom_line, 4*width);
            _TIFFmemcpy(bottom_line, wrk_line, 4*width);
        }

        /*
         * Write out the result in a strip
         */

        if( TIFFWriteEncodedStrip( out, row / rowsperstrip, raster,
                                   4 * rows_to_write * width ) == -1 )
        {
            ok = 0;
            break;
        }
    }

    _TIFFfree( raster );
    _TIFFfree( wrk_line );

    return ok;
}
Ejemplo n.º 23
0
int
main(int argc, char* argv[])
{
	uint16 defconfig = (uint16) -1;
	uint16 deffillorder = 0;
	uint32 deftilewidth = (uint32) -1;
	uint32 deftilelength = (uint32) -1;
	uint32 defrowsperstrip = (uint32) -1;
	uint32 diroff = 0, p_diroff = 0;
	TIFF* in;
	TIFF* out;
	char mode[10];
	char* mp = mode;
	int c;
	extern int optind;
	extern char* optarg;

	*mp++ = 'w';
	*mp = '\0';
	while ((c = getopt(argc, argv, "c:f:l:o:z:p:r:w:aistBLMC")) != -1)
		switch (c) {
		case 'a':		/* append to output */
			mode[0] = 'a';
			break;
		case 'c':		/* compression scheme */
			if (!processCompressOptions(optarg))
				usage();
			break;
		case 'f':		/* fill order */
			if (streq(optarg, "lsb2msb"))
				deffillorder = FILLORDER_LSB2MSB;
			else if (streq(optarg, "msb2lsb"))
				deffillorder = FILLORDER_MSB2LSB;
			else
				usage();
			break;
		case 'i':		/* ignore errors */
			ignore = TRUE;
			break;
		case 'l':		/* tile length */
			outtiled = TRUE;
			deftilelength = atoi(optarg);
			break;
		case 'o':		/* initial directory offset */
			diroff = strtoul(optarg, NULL, 0);
			break;
		case 'z':		/* initial directory offset */
			p_diroff = strtoul(optarg, NULL, 0);
			break;
		case 'p':		/* planar configuration */
			if (streq(optarg, "separate"))
				defconfig = PLANARCONFIG_SEPARATE;
			else if (streq(optarg, "contig"))
				defconfig = PLANARCONFIG_CONTIG;
			else
				usage();
			break;
		case 'r':		/* rows/strip */
			defrowsperstrip = atoi(optarg);
			break;
		case 's':		/* generate stripped output */
			outtiled = FALSE;
			break;
		case 't':		/* generate tiled output */
			outtiled = TRUE;
			break;
		case 'w':		/* tile width */
			outtiled = TRUE;
			deftilewidth = atoi(optarg);
			break;
		case 'B':
			*mp++ = 'b'; *mp = '\0';
			break;
		case 'L':
			*mp++ = 'l'; *mp = '\0';
			break;
		case 'M':
			*mp++ = 'm'; *mp = '\0';
			break;
		case 'C':
			*mp++ = 'c'; *mp = '\0';
			break;
		case '?':
			usage();
			/*NOTREACHED*/
		}
	if (argc - optind < 2)
		usage();
	out = TIFFOpen(argv[argc-1], mode);
	if (out == NULL)
		return (-2);
	mode[0] = 'r';
	for (; optind < argc-1 ; optind++) {
		in = TIFFOpen(argv[optind], mode);
		if (in == NULL)
			return (-3);
		if (diroff != 0 && !TIFFSetSubDirectory(in, diroff)) {
			TIFFError(TIFFFileName(in),
			    "Error, setting subdirectory at %#x", diroff);
			(void) TIFFClose(out);
			return (1);
		}
		if (p_diroff != 0 && !TIFFSetDirectory(in, p_diroff)) {
			TIFFError(TIFFFileName(in),
			    "Error, setting subdirectory at %#x", diroff);
			(void) TIFFClose(out);
			return (1);
		}
		do {
			config = defconfig;
			compression = defcompression;
			predictor = defpredictor;
			fillorder = deffillorder;
			rowsperstrip = defrowsperstrip;
			tilewidth = deftilewidth;
			tilelength = deftilelength;
			g3opts = defg3opts;
			if (!tiffcp(in, out) || !TIFFWriteDirectory(out)) {
				(void) TIFFClose(out);
				return (1);
			}
		} while (TIFFReadDirectory(in) && p_diroff == 0 );
		(void) TIFFClose(in);
	}
	(void) TIFFClose(out);
	return (0);
}
static int
cvt_whole_image( TIFF *in, TIFF *out )

{
    uint32* raster;			/* retrieve RGBA image */
    uint32  width, height;		/* image width & height */
    uint32  row;
    size_t pixel_count;
        
    TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
    TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
    pixel_count = width * height;

    /* XXX: Check the integer overflow. */
    if (!width || !height || pixel_count / width != height) {
        TIFFError(TIFFFileName(in),
		  "Malformed input file; can't allocate buffer for raster of %lux%lu size",
		  (unsigned long)width, (unsigned long)height);
        return 0;
    }

    rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
    TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);

    raster = (uint32*)_TIFFCheckMalloc(in, pixel_count, sizeof(uint32), "raster buffer");
    if (raster == 0) {
        TIFFError(TIFFFileName(in), "Requested buffer size is %lu elements %lu each",
		  (unsigned long)pixel_count, (unsigned long)sizeof(uint32));
        return (0);
    }

    /* Read the image in one chunk into an RGBA array */
    if (!TIFFReadRGBAImageOriented(in, width, height, raster,
                                   ORIENTATION_TOPLEFT, 0)) {
        _TIFFfree(raster);
        return (0);
    }

    /*
     * XXX: raster array has 4-byte unsigned integer type, that is why
     * we should rearrange it here.
     */
#if HOST_BIGENDIAN
    TIFFSwabArrayOfLong(raster, width * height);
#endif

    /*
     * Do we want to strip away alpha components?
     */
    if (no_alpha)
    {
        size_t count = pixel_count;
        unsigned char *src, *dst;

	src = dst = (unsigned char *) raster;
        while (count > 0)
        {
	    *(dst++) = *(src++);
	    *(dst++) = *(src++);
	    *(dst++) = *(src++);
	    src++;
	    count--;
        }
    }

    /*
     * Write out the result in strips
     */
    for (row = 0; row < height; row += rowsperstrip)
    {
        unsigned char * raster_strip;
        int	rows_to_write;
        int	bytes_per_pixel;

        if (no_alpha)
        {
            raster_strip = ((unsigned char *) raster) + 3 * row * width;
            bytes_per_pixel = 3;
        }
        else
        {
            raster_strip = (unsigned char *) (raster + row * width);
            bytes_per_pixel = 4;
        }

        if( row + rowsperstrip > height )
            rows_to_write = height - row;
        else
            rows_to_write = rowsperstrip;

        if( TIFFWriteEncodedStrip( out, row / rowsperstrip, raster_strip,
                             bytes_per_pixel * rows_to_write * width ) == -1 )
        {
            _TIFFfree( raster );
            return 0;
        }
    }

    _TIFFfree( raster );

    return 1;
}
Ejemplo n.º 25
0
/*
 * Encode the supplied data and write it to the
 * specified tile.  There must be space for the
 * data.  The function clamps individual writes
 * to a tile to the tile size, but does not (and
 * can not) check that multiple writes to the same
 * tile do not write more than tile size data.
 *
 * NB: Image length must be setup before writing; this
 *     interface does not support automatically growing
 *     the image on each write (as TIFFWriteScanline does).
 */
tsize_t
TIFFWriteEncodedTile(TIFF* tif, ttile_t tile, tdata_t data, tsize_t cc)
{
	static const char module[] = "TIFFWriteEncodedTile";
	TIFFDirectory *td;
	tsample_t sample;

	if (!WRITECHECKTILES(tif, module))
		return ((tsize_t) -1);
	td = &tif->tif_dir;
	if (tile >= td->td_nstrips) {
		TIFFError(module, "%s: Tile %lu out of range, max %lu",
		    tif->tif_name, (u_long) tile, (u_long) td->td_nstrips);
		return ((tsize_t) -1);
	}
	/*
	 * Handle delayed allocation of data buffer.  This
	 * permits it to be sized more intelligently (using
	 * directory information).
	 */
	if (!BUFFERCHECK(tif))
		return ((tsize_t) -1);
	tif->tif_curtile = tile;

#ifdef REWRITE_HACK        
	tif->tif_rawcc = 0;
	tif->tif_rawcp = tif->tif_rawdata;

        if( td->td_stripbytecount[tile] > 0 )
        {
            /* if we are writing over existing tiles, zero length. */
            td->td_stripbytecount[tile] = 0;

            /* this forces TIFFAppendToStrip() to do a seek */
            tif->tif_curoff = 0;
        }
#endif
        
	/* 
	 * Compute tiles per row & per column to compute
	 * current row and column
	 */
	tif->tif_row = (tile % TIFFhowmany(td->td_imagelength, td->td_tilelength))
		* td->td_tilelength;
	tif->tif_col = (tile % TIFFhowmany(td->td_imagewidth, td->td_tilewidth))
		* td->td_tilewidth;

	if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
		if (!(*tif->tif_setupencode)(tif))
			return ((tsize_t) -1);
		tif->tif_flags |= TIFF_CODERSETUP;
	}
	tif->tif_flags &= ~TIFF_POSTENCODE;
	sample = (tsample_t)(tile/td->td_stripsperimage);
	if (!(*tif->tif_preencode)(tif, sample))
		return ((tsize_t) -1);
	/*
	 * Clamp write amount to the tile size.  This is mostly
	 * done so that callers can pass in some large number
	 * (e.g. -1) and have the tile size used instead.
	 */
	if ( cc < 1 || cc > tif->tif_tilesize)
		cc = tif->tif_tilesize;

        /* swab if needed - note that source buffer will be altered */
        tif->tif_postdecode( tif, (tidata_t) data, cc );

	if (!(*tif->tif_encodetile)(tif, (tidata_t) data, cc, sample))
		return ((tsize_t) 0);
	if (!(*tif->tif_postencode)(tif))
		return ((tsize_t) -1);
	if (!isFillOrder(tif, td->td_fillorder) &&
	    (tif->tif_flags & TIFF_NOBITREV) == 0)
		TIFFReverseBits((u_char *)tif->tif_rawdata, tif->tif_rawcc);
	if (tif->tif_rawcc > 0 && !TIFFAppendToStrip(tif, tile,
	    tif->tif_rawdata, tif->tif_rawcc))
		return ((tsize_t) -1);
	tif->tif_rawcc = 0;
	tif->tif_rawcp = tif->tif_rawdata;
	return (cc);
}
Ejemplo n.º 26
0
static int
_TIFFVSetField(TIFF* tif, ttag_t tag, va_list ap)
{
	TIFFDirectory* td = &tif->tif_dir;
	int status = 1;
	uint32 v32;
	int i, v;
	double d;
	char* s;

	switch (tag) {
	case TIFFTAG_SUBFILETYPE:
		td->td_subfiletype = va_arg(ap, uint32);
		break;
	case TIFFTAG_IMAGEWIDTH:
		td->td_imagewidth = va_arg(ap, uint32);
		break;
	case TIFFTAG_IMAGELENGTH:
		td->td_imagelength = va_arg(ap, uint32);
		break;
	case TIFFTAG_BITSPERSAMPLE:
		td->td_bitspersample = (uint16) va_arg(ap, int);
		/*
		 * If the data require post-decoding processing
		 * to byte-swap samples, set it up here.  Note
		 * that since tags are required to be ordered,
		 * compression code can override this behaviour
		 * in the setup method if it wants to roll the
		 * post decoding work in with its normal work.
		 */
		if (tif->tif_flags & TIFF_SWAB) {
			if (td->td_bitspersample == 16)
				tif->tif_postdecode = _TIFFSwab16BitData;
			else if (td->td_bitspersample == 32)
				tif->tif_postdecode = _TIFFSwab32BitData;
			else if (td->td_bitspersample == 64)
				tif->tif_postdecode = _TIFFSwab64BitData;
		}
		break;
	case TIFFTAG_COMPRESSION:
		v = va_arg(ap, int) & 0xffff;
		/*
		 * If we're changing the compression scheme,
		 * the notify the previous module so that it
		 * can cleanup any state it's setup.
		 */
		if (TIFFFieldSet(tif, FIELD_COMPRESSION)) {
			if (td->td_compression == v)
				break;
			(*tif->tif_cleanup)(tif);
			tif->tif_flags &= ~TIFF_CODERSETUP;
		}
		/*
		 * Setup new compression routine state.
		 */
		if ( ! tif->tif_mode == O_RDONLY ) { 
		  /* Handle removal of LZW compression */ 
		  if ( v == COMPRESSION_LZW ) { 
		    TIFFError(tif->tif_name, 
			      "LZW compression no longer supported due to Unisys patent enforcement"); 
		    v=COMPRESSION_NONE;
		  }
		}
		if( (status = TIFFSetCompressionScheme(tif, v)) != 0 )
		  td->td_compression = v;
		break;
	case TIFFTAG_PHOTOMETRIC:
		td->td_photometric = (uint16) va_arg(ap, int);
		break;
	case TIFFTAG_THRESHHOLDING:
		td->td_threshholding = (uint16) va_arg(ap, int);
		break;
	case TIFFTAG_FILLORDER:
		v = va_arg(ap, int);
		if (v != FILLORDER_LSB2MSB && v != FILLORDER_MSB2LSB)
			goto badvalue;
		td->td_fillorder = (uint16) v;
		break;
	case TIFFTAG_DOCUMENTNAME:
		_TIFFsetString(&td->td_documentname, va_arg(ap, char*));
		break;
	case TIFFTAG_ARTIST:
		_TIFFsetString(&td->td_artist, va_arg(ap, char*));
		break;
	case TIFFTAG_DATETIME:
		_TIFFsetString(&td->td_datetime, va_arg(ap, char*));
		break;
	case TIFFTAG_HOSTCOMPUTER:
		_TIFFsetString(&td->td_hostcomputer, va_arg(ap, char*));
		break;
	case TIFFTAG_IMAGEDESCRIPTION:
		_TIFFsetString(&td->td_imagedescription, va_arg(ap, char*));
		break;
	case TIFFTAG_MAKE:
		_TIFFsetString(&td->td_make, va_arg(ap, char*));
		break;
	case TIFFTAG_MODEL:
		_TIFFsetString(&td->td_model, va_arg(ap, char*));
		break;
	case TIFFTAG_SOFTWARE:
		_TIFFsetString(&td->td_software, va_arg(ap, char*));
		break;
	case TIFFTAG_ORIENTATION:
		v = va_arg(ap, int);
		if (v < ORIENTATION_TOPLEFT || ORIENTATION_LEFTBOT < v) {
			TIFFWarning(tif->tif_name,
			    "Bad value %ld for \"%s\" tag ignored",
			    v, _TIFFFieldWithTag(tif, tag)->field_name);
		} else
			td->td_orientation = (uint16) v;
		break;
	case TIFFTAG_SAMPLESPERPIXEL:
		/* XXX should cross check -- e.g. if pallette, then 1 */
		v = va_arg(ap, int);
		if (v == 0)
			goto badvalue;
		td->td_samplesperpixel = (uint16) v;
		break;
	case TIFFTAG_ROWSPERSTRIP:
		v32 = va_arg(ap, uint32);
		if (v32 == 0)
			goto badvalue32;
		td->td_rowsperstrip = v32;
		if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
			td->td_tilelength = v32;
			td->td_tilewidth = td->td_imagewidth;
		}
		break;
	case TIFFTAG_MINSAMPLEVALUE:
		td->td_minsamplevalue = (uint16) va_arg(ap, int);
		break;
	case TIFFTAG_MAXSAMPLEVALUE:
		td->td_maxsamplevalue = (uint16) va_arg(ap, int);
		break;
	case TIFFTAG_SMINSAMPLEVALUE:
		td->td_sminsamplevalue = (double) va_arg(ap, dblparam_t);
		break;
	case TIFFTAG_SMAXSAMPLEVALUE:
		td->td_smaxsamplevalue = (double) va_arg(ap, dblparam_t);
		break;
	case TIFFTAG_XRESOLUTION:
		td->td_xresolution = (float) va_arg(ap, dblparam_t);
		break;
	case TIFFTAG_YRESOLUTION:
		td->td_yresolution = (float) va_arg(ap, dblparam_t);
		break;
	case TIFFTAG_PLANARCONFIG:
		v = va_arg(ap, int);
		if (v != PLANARCONFIG_CONTIG && v != PLANARCONFIG_SEPARATE)
			goto badvalue;
		td->td_planarconfig = (uint16) v;
		break;
	case TIFFTAG_PAGENAME:
		_TIFFsetString(&td->td_pagename, va_arg(ap, char*));
		break;
	case TIFFTAG_XPOSITION:
		td->td_xposition = (float) va_arg(ap, dblparam_t);
		break;
	case TIFFTAG_YPOSITION:
		td->td_yposition = (float) va_arg(ap, dblparam_t);
		break;
	case TIFFTAG_RESOLUTIONUNIT:
		v = va_arg(ap, int);
		if (v < RESUNIT_NONE || RESUNIT_CENTIMETER < v)
			goto badvalue;
		td->td_resolutionunit = (uint16) v;
		break;
	case TIFFTAG_PAGENUMBER:
		td->td_pagenumber[0] = (uint16) va_arg(ap, int);
		td->td_pagenumber[1] = (uint16) va_arg(ap, int);
		break;
	case TIFFTAG_HALFTONEHINTS:
		td->td_halftonehints[0] = (uint16) va_arg(ap, int);
		td->td_halftonehints[1] = (uint16) va_arg(ap, int);
		break;
	case TIFFTAG_COLORMAP:
		v32 = (uint32)(1L<<td->td_bitspersample);
		_TIFFsetShortArray(&td->td_colormap[0], va_arg(ap, uint16*), v32);
		_TIFFsetShortArray(&td->td_colormap[1], va_arg(ap, uint16*), v32);
		_TIFFsetShortArray(&td->td_colormap[2], va_arg(ap, uint16*), v32);
		break;
	case TIFFTAG_EXTRASAMPLES:
		if (!setExtraSamples(td, ap, &v))
			goto badvalue;
		break;
	case TIFFTAG_MATTEING:
		td->td_extrasamples = (uint16) (va_arg(ap, int) != 0);
		if (td->td_extrasamples) {
			uint16 sv = EXTRASAMPLE_ASSOCALPHA;
			_TIFFsetShortArray(&td->td_sampleinfo, &sv, 1);
		}
		break;
	case TIFFTAG_TILEWIDTH:
		v32 = va_arg(ap, uint32);
		if (v32 % 16) {
			if (tif->tif_mode != O_RDONLY)
				goto badvalue32;
			TIFFWarning(tif->tif_name,
			    "Nonstandard tile width %d, convert file", v32);
		}
		td->td_tilewidth = v32;
		tif->tif_flags |= TIFF_ISTILED;
		break;
	case TIFFTAG_TILELENGTH:
		v32 = va_arg(ap, uint32);
		if (v32 % 16) {
			if (tif->tif_mode != O_RDONLY)
				goto badvalue32;
			TIFFWarning(tif->tif_name,
			    "Nonstandard tile length %d, convert file", v32);
		}
		td->td_tilelength = v32;
		tif->tif_flags |= TIFF_ISTILED;
		break;
	case TIFFTAG_TILEDEPTH:
		v32 = va_arg(ap, uint32);
		if (v32 == 0)
			goto badvalue32;
		td->td_tiledepth = v32;
		break;
	case TIFFTAG_DATATYPE:
		v = va_arg(ap, int);
		switch (v) {
		case DATATYPE_VOID:	v = SAMPLEFORMAT_VOID;	break;
		case DATATYPE_INT:	v = SAMPLEFORMAT_INT;	break;
		case DATATYPE_UINT:	v = SAMPLEFORMAT_UINT;	break;
		case DATATYPE_IEEEFP:	v = SAMPLEFORMAT_IEEEFP;break;
		default:		goto badvalue;
		}
		td->td_sampleformat = (uint16) v;
		break;
	case TIFFTAG_SAMPLEFORMAT:
		v = va_arg(ap, int);
		if (v < SAMPLEFORMAT_UINT || SAMPLEFORMAT_VOID < v)
			goto badvalue;
		td->td_sampleformat = (uint16) v;
		break;
	case TIFFTAG_IMAGEDEPTH:
		td->td_imagedepth = va_arg(ap, uint32);
		break;
	case TIFFTAG_STONITS:
		d = va_arg(ap, dblparam_t);
		if (d <= 0.)
			goto badvaluedbl;
		td->td_stonits = d;
		break;

	/* Begin Pixar Tags */
 	case TIFFTAG_PIXAR_IMAGEFULLWIDTH:
 		td->td_imagefullwidth = va_arg(ap, uint32);
 		break;
 	case TIFFTAG_PIXAR_IMAGEFULLLENGTH:
 		td->td_imagefulllength = va_arg(ap, uint32);
 		break;
 	case TIFFTAG_PIXAR_TEXTUREFORMAT:
 		_TIFFsetString(&td->td_textureformat, va_arg(ap, char*));
 		break;
 	case TIFFTAG_PIXAR_WRAPMODES:
 		_TIFFsetString(&td->td_wrapmodes, va_arg(ap, char*));
 		break;
 	case TIFFTAG_PIXAR_FOVCOT:
 		td->td_fovcot = (float) va_arg(ap, dblparam_t);
 		break;
 	case TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN:
 		_TIFFsetFloatArray(&td->td_matrixWorldToScreen,
 			va_arg(ap, float*), 16);
 		break;
 	case TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA:
 		_TIFFsetFloatArray(&td->td_matrixWorldToCamera,
 			va_arg(ap, float*), 16);
 		break;
 	/* End Pixar Tags */	       

#if SUBIFD_SUPPORT
	case TIFFTAG_SUBIFD:
		if ((tif->tif_flags & TIFF_INSUBIFD) == 0) {
			td->td_nsubifd = (uint16) va_arg(ap, int);
			_TIFFsetLongArray(&td->td_subifd, va_arg(ap, uint32*),
			    (long) td->td_nsubifd);
		} else {
Ejemplo n.º 27
0
int
TIFFWriteScanline(TIFF* tif, tdata_t buf, uint32 row, tsample_t sample)
{
	static const char module[] = "TIFFWriteScanline";
	register TIFFDirectory *td;
	int status, imagegrew = 0;
	tstrip_t strip;

	if (!WRITECHECKSTRIPS(tif, module))
		return (-1);
	/*
	 * Handle delayed allocation of data buffer.  This
	 * permits it to be sized more intelligently (using
	 * directory information).
	 */
	if (!BUFFERCHECK(tif))
		return (-1);
	td = &tif->tif_dir;
	/*
	 * Extend image length if needed
	 * (but only for PlanarConfig=1).
	 */
	if (row >= td->td_imagelength) {	/* extend image */
		if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
			TIFFError(tif->tif_name,
		"Can not change \"ImageLength\" when using separate planes");
			return (-1);
		}
		td->td_imagelength = row+1;
		imagegrew = 1;
	}
	/*
	 * Calculate strip and check for crossings.
	 */
	if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
		if (sample >= td->td_samplesperpixel) {
			TIFFError(tif->tif_name,
			    "%d: Sample out of range, max %d",
			    sample, td->td_samplesperpixel);
			return (-1);
		}
		strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip;
	} else
		strip = row / td->td_rowsperstrip;
	if (strip != tif->tif_curstrip) {
		/*
		 * Changing strips -- flush any data present.
		 */
		if (!TIFFFlushData(tif))
			return (-1);
		tif->tif_curstrip = strip;
		/*
		 * Watch out for a growing image.  The value of
		 * strips/image will initially be 1 (since it
		 * can't be deduced until the imagelength is known).
		 */
		if (strip >= td->td_stripsperimage && imagegrew)
			td->td_stripsperimage =
			    TIFFhowmany(td->td_imagelength,td->td_rowsperstrip);
		tif->tif_row =
		    (strip % td->td_stripsperimage) * td->td_rowsperstrip;
		if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
			if (!(*tif->tif_setupencode)(tif))
				return (-1);
			tif->tif_flags |= TIFF_CODERSETUP;
		}
		if (!(*tif->tif_preencode)(tif, sample))
			return (-1);
		tif->tif_flags |= TIFF_POSTENCODE;
	}
	/*
	 * Check strip array to make sure there's space.
	 * We don't support dynamically growing files that
	 * have data organized in separate bitplanes because
	 * it's too painful.  In that case we require that
	 * the imagelength be set properly before the first
	 * write (so that the strips array will be fully
	 * allocated above).
	 */
	if (strip >= td->td_nstrips && !TIFFGrowStrips(tif, 1, module))
		return (-1);
	/*
	 * Ensure the write is either sequential or at the
	 * beginning of a strip (or that we can randomly
	 * access the data -- i.e. no encoding).
	 */
	if (row != tif->tif_row) {
		if (row < tif->tif_row) {
			/*
			 * Moving backwards within the same strip:
			 * backup to the start and then decode
			 * forward (below).
			 */
			tif->tif_row = (strip % td->td_stripsperimage) *
			    td->td_rowsperstrip;
			tif->tif_rawcp = tif->tif_rawdata;
		}
		/*
		 * Seek forward to the desired row.
		 */
		if (!(*tif->tif_seek)(tif, row - tif->tif_row))
			return (-1);
		tif->tif_row = row;
	}

        /* swab if needed - note that source buffer will be altered */
        tif->tif_postdecode( tif, (tidata_t) buf, tif->tif_scanlinesize );

	status = (*tif->tif_encoderow)(tif, (tidata_t) buf,
	    tif->tif_scanlinesize, sample);

        /* we are now poised at the beginning of the next row */
	tif->tif_row = row + 1;
	return (status);
}
Ejemplo n.º 28
0
static void
MissingRequired(TIFF* tif, const char* tagname)
{
	TIFFError(tif->tif_name,
	    "TIFF directory is missing required \"%s\" field", tagname);
}
Ejemplo n.º 29
0
/*
 * Setup state for decoding a strip.
 */
static int
LZWPreDecode(TIFF* tif, tsample_t s)
{
	LZWDecodeState *sp = DecoderState(tif);

	(void) s;
	assert(sp != NULL);
	/*
	 * Check for old bit-reversed codes.
	 */
	if (tif->tif_rawdata[0] == 0 && (tif->tif_rawdata[1] & 0x1)) {
#ifdef LZW_COMPAT
		if (!sp->dec_decode) {
			TIFFWarning(tif->tif_name,
			    "Old-style LZW codes, convert file");
			/*
			 * Override default decoding methods with
			 * ones that deal with the old coding.
			 * Otherwise the predictor versions set
			 * above will call the compatibility routines
			 * through the dec_decode method.
			 */
			tif->tif_decoderow = LZWDecodeCompat;
			tif->tif_decodestrip = LZWDecodeCompat;
			tif->tif_decodetile = LZWDecodeCompat;
			/*
			 * If doing horizontal differencing, must
			 * re-setup the predictor logic since we
			 * switched the basic decoder methods...
			 */
			(*tif->tif_setupdecode)(tif);
			sp->dec_decode = LZWDecodeCompat;
		}
		sp->lzw_maxcode = MAXCODE(BITS_MIN);
#else /* !LZW_COMPAT */
		if (!sp->dec_decode) {
			TIFFError(tif->tif_name,
			    "Old-style LZW codes not supported");
			sp->dec_decode = LZWDecode;
		}
		return (0);
#endif/* !LZW_COMPAT */
	} else {
		sp->lzw_maxcode = MAXCODE(BITS_MIN)-1;
		sp->dec_decode = LZWDecode;
	}
	sp->lzw_nbits = BITS_MIN;
	sp->lzw_nextbits = 0;
	sp->lzw_nextdata = 0;

	sp->dec_restart = 0;
	sp->dec_nbitsmask = MAXCODE(BITS_MIN);
#ifdef LZW_CHECKEOS
	sp->dec_bitsleft = tif->tif_rawcc << 3;
#endif
	sp->dec_free_entp = sp->dec_codetab + CODE_FIRST;
	/*
	 * Zero entries that are not yet filled in.  We do
	 * this to guard against bogus input data that causes
	 * us to index into undefined entries.  If you can
	 * come up with a way to safely bounds-check input codes
	 * while decoding then you can remove this operation.
	 */
	_TIFFmemset(sp->dec_free_entp, 0, (CSIZE-CODE_FIRST)*sizeof (code_t));
	sp->dec_oldcodep = &sp->dec_codetab[-1];
	sp->dec_maxcodep = &sp->dec_codetab[sp->dec_nbitsmask-1];
	return (1);
}
Ejemplo n.º 30
0
int 
TIFFRewriteDirectory( TIFF *tif )
{
    static const char module[] = "TIFFRewriteDirectory";

    /* We don't need to do anything special if it hasn't been written. */
    if( tif->tif_diroff == 0 )
        return TIFFWriteDirectory( tif );

    /*
    ** Find and zero the pointer to this directory, so that TIFFLinkDirectory
    ** will cause it to be added after this directories current pre-link.
    */
    
    /* Is it the first directory in the file? */
    if (tif->tif_header.tiff_diroff == tif->tif_diroff) 
    {
        tif->tif_header.tiff_diroff = 0;
        tif->tif_diroff = 0;

#if defined(__hpux) && defined(__LP64__)
#define HDROFF(f) ((toff_t)(unsigned long) &(((TIFFHeader*) 0)->f))
#else
#define	HDROFF(f)	((toff_t) &(((TIFFHeader*) 0)->f))
#endif
        TIFFSeekFile(tif, HDROFF(tiff_diroff), SEEK_SET);
        if (!WriteOK(tif, &(tif->tif_header.tiff_diroff), 
                     sizeof (tif->tif_diroff))) 
        {
            TIFFError(tif->tif_name, "Error updating TIFF header");
            return (0);
        }
    }
    else
    {
        toff_t  nextdir, off;

	nextdir = tif->tif_header.tiff_diroff;
	do {
		uint16 dircount;

		if (!SeekOK(tif, nextdir) ||
		    !ReadOK(tif, &dircount, sizeof (dircount))) {
			TIFFError(module, "Error fetching directory count");
			return (0);
		}
		if (tif->tif_flags & TIFF_SWAB)
			TIFFSwabShort(&dircount);
		(void) TIFFSeekFile(tif,
		    dircount * sizeof (TIFFDirEntry), SEEK_CUR);
		if (!ReadOK(tif, &nextdir, sizeof (nextdir))) {
			TIFFError(module, "Error fetching directory link");
			return (0);
		}
		if (tif->tif_flags & TIFF_SWAB)
			TIFFSwabLong(&nextdir);
	} while (nextdir != tif->tif_diroff && nextdir != 0);
        off = TIFFSeekFile(tif, 0, SEEK_CUR); /* get current offset */
        (void) TIFFSeekFile(tif, off - (toff_t)sizeof(nextdir), SEEK_SET);
        tif->tif_diroff = 0;
	if (!WriteOK(tif, &(tif->tif_diroff), sizeof (nextdir))) {
		TIFFError(module, "Error writing directory link");
		return (0);
	}
    }

    /*
    ** Now use TIFFWriteDirectory() normally.
    */

    return TIFFWriteDirectory( tif );
}