AWARE [SYSTEMS] Imaging expertise for the Delphi developer
AWare Systems, Imaging expertise for the Delphi developer, Home TIFF and LibTiff Mailing List Archive

LibTiff Mailing List

TIFF and LibTiff Mailing List Archive
March 2010

Previous Thread
Next Thread

Previous by Thread
Next by Thread

Previous by Date
Next by Date

Contact

The TIFF Mailing List Homepage
This list is run by Frank Warmerdam
Archive maintained by AWare Systems



Valid HTML 4.01!



Thread

2010.03.22 01:34 "Problems with Modified tiffset", by Kevin Myers
2010.03.22 02:56 "Re: Problems with Modified tiffset", by Kevin Myers

2010.03.22 02:56 "Re: Problems with Modified tiffset", by Kevin Myers

Oops, never mind, finally found the problem myself.  Had inappropriate value
for field_passcount member of TIFFFieldInfo structure to use with ASCII tag
content.  After changing value for field_passcount from TRUE to FALSE, all
works as it should.  Sorry for the false alarm.  Hope nobody out there
wasted any time trying to track this down...

My corrected code is attached, in case anyone is interested.

s/KAM

  ----- Original Message ----- 
  From: Kevin Myers 
  To: tiff@lists.maptools.org 
  Sent: Sunday, March 21, 2010 20:34
  Subject: Problems with Modified tiffset


  I've already sent this to a couple of my acquaintances on this list, but
  thought I might as well run it past everyone in case someone else can spot
  the problem right away...

  I have attempted to modify the tiffset program to allow it to set the
  value of user defined (custom) tags.  I could have sworn that I had this
  working some time ago, but now it definitely isn't working, and I'm not
  sure if it is due to a bug in libtiff, or (more likely) some kind of
  problem in my own code.  The modifications that I made are relatively
  simple, and make use of the so-called "tag extender" feature of libtiff,
  which is documented under the "Defining Application Tags" section on this
  web page:
  http://www.remotesensing.org/libtiff/addingtags.html

  I have attached my modified version of tiffset.c for tiff 3.9.2.  Since
  I'm sure that many of you are much stronger C programmers than I am, I
  doubt that you will have any problems compiling this.  My own approach was
  to temporarily replace the standard version of tiffset.c in the tools
  directory, delete or rename any previously generated tiffset.exe in the
  tools output folder if you have one, and go from there.  From the tools
  folder, I simply used nmake /f makefile.vc under Windows XP using VC from
  Visual Studio 2008 Express.

  After successfully compiling the program, here is what happens:
  If I use my modified tiffset to set the value of a standard tiff tag, say
  ImageDescription (tag number 270, ASCII text), everything works fine. 
  Here is how I would do that (assume test.tif is an existing tiff file):

  tiffset -s 270 MyValue test.tif
  or
  tiffset -s ImageDescription NewValue test.tif

  You can use tiffinfo to verify that the ImageDescription tag value is set
  correctly.

  On the other hand, when I use the following command:

  tiffset -s 65000 MyValue test.tif

  Everything *appears* to proceed normally.  But when I run tiffinfo, I find
  that tag 65000 did get set to *something*, but not what it was supposed to
  be.  It seems to be getting set to some bytes from elsewhere in memory. 
  Looks like some kind of pointer related problem...

  Internally, tiffset is using the TIFFSetField function from libtiff to set
  the tag value.  My modified tiffset currently includes a printf statement
  to print the values of the arguments to TIFFSetField immediately prior to
  the call, and everything *seems* to be ok at that point.  The correct,
  anticipated values are printed at this point for both standard and
  user-defined tag cases.  But somewhere within the execution of
  TIFFSetField, things are getting screwed up for the user-defined tag case,
  and I can't figure out why/where.  The code used in TIFFSetField is
  somewhat beyond my level of C expertise, and it would take me forever to
  track down where the correct value is getting lost.  Hopefully someone
  else out there may be able to track down this problem a lot more quickly. 
  Any takers?

  I'm trying to finish up a critical project with immediately pending
  deadlines.  A small but critical portion of that project requires
  programmatically adding metadata to tiff images via custom tag values, and
  this problem currently has my progress ground to a complete standstill.

  Thanks,
  Kevin M.


/******************************************************************************
 * $Id: tiffset.c,v 1.13 2009/03/21 21:52:00 kam1 Exp $
 *
 * Project:  libtiff tools
 * Purpose:  Mainline for setting metadata in existing TIFF files.
 * Author:   Frank Warmerdam, warmerdam@pobox.com
 *
 ******************************************************************************
 * Copyright (c) 2000, Frank Warmerdam
 *
 * Permission to use, copy, modify, distribute, and sell this software and 
 * its documentation for any purpose is hereby granted without fee, provided
 * that (i) the above copyright notices and this permission notice appear in
 * all copies of the software and related documentation, and (ii) the names
 of
 * Sam Leffler and Silicon Graphics may not be used in any advertising or
 * publicity relating to the software without the specific, prior written
 * permission of Sam Leffler and Silicon Graphics.
 * 
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
 * 
 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
 
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
 * OF THIS SOFTWARE.
 ******************************************************************************
 *
 * $Log: tiffset.c,v $
 * Revision 1.13  2009/03/21 21:52:00  kam1
 * Add support for setting undocumented ASCII tag values.
 *
 * Revision 1.12  2007/02/24 17:14:14  dron
 * Properly handle tags with TIFF_VARIABLE writecount. As per bug
 * http://bugzilla.remotesensing.org/show_bug.cgi?id=1350
 *
 * Revision 1.11  2005/09/13 14:13:42  dron
 * Avoid warnings.
 *
 * Revision 1.10  2005/02/24 14:47:11  fwarmerdam
 * Updated header.
 *
 */


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "tiffio.h"

#define	TRUE	1
#define	FALSE	0

#define TIFFTAG_CUSTOM 65535

static char* usageMsg[] = {
"usage: tiffset [options] tiff-filename",
"where options are:",
" -s <tagname> [count] <value>...   set the tag value",
" -sf <tagname> <tag data filename>  set the tag value from file (ASCII tags
only)",
NULL
};

static TIFFDataType	user_field_type = 0;		/* user specified TIFF tag data
type */
static ttag_t		user_tag = 0;			/* user specified TIFF tag Id */
static TIFFExtendProc	_ParentExtender = NULL;		/* parent tag extender proc
*/

static TIFFFieldInfo	xtiffFieldInfo[] = {
    { TIFFTAG_CUSTOM,	TIFF_VARIABLE,	TIFF_VARIABLE,	TIFF_ASCII,
    FIELD_CUSTOM,	TRUE,	FALSE,	"Tag 65535" }
};



static void
usage(void)
{
	int i;
	for (i = 0; usageMsg[i]; i++)
		fprintf(stderr, "%s\n", usageMsg[i]);
	exit(-1);
}


/* KAM - tag type extender callback */
static void
_XTIFFDefaultDirectory(TIFF *tif)
{
	/* update our extended tag field info */
	xtiffFieldInfo[0].field_tag = user_tag;
//	xtiffFieldInfo[0].field_type = user_field_type;
	sprintf(xtiffFieldInfo[0].field_name, "Tag %d", (int) user_tag);

	/* Install the extended Tag field info */
	TIFFMergeFieldInfo(tif, xtiffFieldInfo, 1);

	/* Since an XTIFF client module may have overridden
	 * the default directory method, we call it now to
	 * allow it to set up the rest of its own methods.
	 */

    if (_ParentExtender) (*_ParentExtender)(tif);
}


/* KAM - initialize tag type extender */
static
void _XTIFFInitialize(void)
{
	static int first_time=1;
	
	if (! first_time) return; /* Been there. Done that. */
	first_time = 0;
	
	/* Grab the inherited method and install */
	_ParentExtender = TIFFSetTagExtender(_XTIFFDefaultDirectory);
}


static const TIFFFieldInfo *
GetField(TIFF *tiff, const char *tagname)
{
    const TIFFFieldInfo *fip;

	if( user_tag > 0 )
		fip = TIFFFieldWithTag(tiff, user_tag);
	else
		fip = TIFFFieldWithName(tiff, tagname);

	if (!fip) {
		fprintf( stderr, "Field name %s not recognized.\n", tagname );
        return (TIFFFieldInfo *)NULL;
    }

    return fip;
}


int
main(int argc, char* argv[])
{
    TIFF *tiff;
    int  arg_index;
	char* tifffile;
	const char *tagname;
	char* tag_value;

	/* KAM - initialize tag extender */
	_XTIFFInitialize();

	/* at least 2 arguments are always required (really more) */
	if (argc < 2)
        usage();

	/* target file is always last argument */
	tifffile = argv[argc-1];

    for( arg_index = 1; arg_index < argc-1; arg_index++ ) {
        if (strcmp(argv[arg_index],"-s") == 0 && arg_index < argc-3) {
            const TIFFFieldInfo *fip;

            arg_index++;
            tagname = argv[arg_index];

            user_tag = (ttag_t)atoi(tagname);

            tiff = TIFFOpen(tifffile, "r+");
            if (tiff == NULL)
                return 2;

            fip = GetField(tiff, tagname);

            if (!fip)
                return 3;

            arg_index++;
            tag_value=argv[arg_index];
            if (fip->field_type == TIFF_ASCII) {

                if (TIFFSetField(tiff, fip->field_tag, argv[arg_index]) !=
                1)
                    fprintf( stderr, "Failed to set %s=%s\n",
                             fip->field_name, argv[arg_index] );

            } else if (fip->field_writecount > 0
		           || fip->field_writecount == TIFF_VARIABLE) {
                int     ret = 1;
                short   wc;

                if (fip->field_writecount == TIFF_VARIABLE)
                        wc = atoi(argv[arg_index++]);
                else
                        wc = fip->field_writecount;

                if (argc - arg_index < wc) {
                    fprintf( stderr,
                             "Number of tag values is not enough. "
                             "Expected %d values for %s tag, got %d\n",
                             wc, fip->field_name, argc - arg_index);
                    return 4;
                }
                    
                if (wc > 1) {
                        int     i, size;
                        void    *array;

                        switch (fip->field_type) {
                                /*
                                 * XXX: We can't use TIFFDataWidth()
                                 * to determine the space needed to store
                                 * the value. For TIFF_RATIONAL values
                                 * TIFFDataWidth() returns 8, but we use
                    4-byte
                                 * float to represent rationals.
                                 */
                                case TIFF_BYTE:
                                case TIFF_ASCII:
                                case TIFF_SBYTE:
                                case TIFF_UNDEFINED:
				default:
                                    size = 1;
                                    break;

                                case TIFF_SHORT:
                                case TIFF_SSHORT:
                                    size = 2;
                                    break;

                                case TIFF_LONG:
                                case TIFF_SLONG:
                                case TIFF_FLOAT:
                                case TIFF_IFD:
                                case TIFF_RATIONAL:
                                case TIFF_SRATIONAL:
                                    size = 4;
                                    break;

                                case TIFF_DOUBLE:
                                    size = 8;
                                    break;
                        }

                        array = _TIFFmalloc(wc * size);
                        if (!array) {
                                fprintf(stderr, "No space for %s tag\n",
                                        tagname);
                                return 4;
                        }

                        switch (fip->field_type) {
                            case TIFF_BYTE:
                                for (i = 0; i < wc; i++)
                                    ((uint8 *)array)[i] =
                    atoi(argv[arg_index+i]);
                                break;
                            case TIFF_SHORT:
                                for (i = 0; i < wc; i++)
                                    ((uint16 *)array)[i] =
                    atoi(argv[arg_index+i]);
                                break;
                            case TIFF_SBYTE:
                                for (i = 0; i < wc; i++)
                                    ((int8 *)array)[i] =
                    atoi(argv[arg_index+i]);
                                break;
                            case TIFF_SSHORT:
                                for (i = 0; i < wc; i++)
                                    ((int16 *)array)[i] =
                    atoi(argv[arg_index+i]);
                                break;
                            case TIFF_LONG:
                                for (i = 0; i < wc; i++)
                                    ((uint32 *)array)[i] =
                    atol(argv[arg_index+i]);
                                break;
                            case TIFF_SLONG:
                            case TIFF_IFD:
                                for (i = 0; i < wc; i++)
                                    ((uint32 *)array)[i] =
                    atol(argv[arg_index+i]);
                                break;
                            case TIFF_DOUBLE:
                                for (i = 0; i < wc; i++)
                                    ((double *)array)[i] =
                    atof(argv[arg_index+i]);
                                break;
                            case TIFF_RATIONAL:
                            case TIFF_SRATIONAL:
                            case TIFF_FLOAT:
                                for (i = 0; i < wc; i++)
                                    ((float *)array)[i] =
                    (float)atof(argv[arg_index+i]);
                                break;
                            default:
                                break;
                        }
                
                        if (fip->field_passcount) {
                                ret = TIFFSetField(tiff, fip->field_tag,
                                                   wc, array);
                        } else {
                                ret = TIFFSetField(tiff, fip->field_tag,
                                                   array);
                        }

                        _TIFFfree(array);
                } else {
                        switch (fip->field_type) {
                            case TIFF_BYTE:
                            case TIFF_SHORT:
                            case TIFF_SBYTE:
                            case TIFF_SSHORT:
                                ret = TIFFSetField(tiff, fip->field_tag,
                                                   atoi(argv[arg_index++]));
                                break;
                            case TIFF_LONG:
                            case TIFF_SLONG:
                            case TIFF_IFD:
                                ret = TIFFSetField(tiff, fip->field_tag,
                                                   atol(argv[arg_index++]));
                                break;
                            case TIFF_DOUBLE:
                                ret = TIFFSetField(tiff, fip->field_tag,
                                                   atof(argv[arg_index++]));
                                break;
                            case TIFF_RATIONAL:
                            case TIFF_SRATIONAL:
                            case TIFF_FLOAT:
                                ret = TIFFSetField(tiff, fip->field_tag,
                                                  
                    (float)atof(argv[arg_index++]));
                                break;
                            default:
                                break;
                        }
                }

                if (ret != 1)
                    fprintf(stderr, "Failed to set %s\n", fip->field_name);
                arg_index += wc;
            }
        } else if (strcmp(argv[arg_index],"-sf") == 0 && arg_index < argc-3)
        {
            FILE    *fp;
            const TIFFFieldInfo *fip;
            char    *text;
            int     len;

            arg_index++;
            tagname = argv[arg_index];
			user_tag = (ttag_t)atoi(tagname);
			tiff = TIFFOpen(tifffile, "r+");
            fip = GetField(tiff, tagname);

            if (!fip)
                return 3;

			/* TODO: add support for all user-specific field types */
			if (fip->field_type != TIFF_ASCII) {
                fprintf( stderr,
                         "Only ASCII tags can be set from file. "
                         "%s is not ASCII tag.\n", fip->field_name );
                return 5;
            }

            arg_index++;
            fp = fopen( argv[arg_index], "rt" );
            if(fp == NULL) {
                perror( argv[arg_index] );
                continue;
            }

			/* KAM - Should consider fixing this old kludge                  */
			/* Following code limits max data size to approximately 1 MB.    */
			/* Should allow up to 4 GB for classic TIFF (in extreme case).   */
			/* Since file name is specified on the command line (not a pipe) */
			/* should know file size in advance and be able to attempt       */
			/* allocation accordingly.  However, there really ought to be    */
			/* a version of TIFFSetField that would let us set the tag value */
			/* incrementally rather than needing to allocate all of this     */
			/* memory at one time.                                           */

			/* TODO: get file size here, how? */

			/* check that file size is integer multiple of data type size    */
			/* for non-ASCII data types.                                     */
			/* Use TIFFDataWidth() to get the individual field width.        */

			/* For testing purposes, an apparently unused tag Id is 65000.   */
			/* Until add support for other types, can use TIFF_ASCII=2.      */

			/* TODO: change memory allocation to match file size */
			text = (char *) malloc(1000000);
            len = fread( text, 1, 999999, fp );
            text[len] = '\0';

            fclose( fp );

            if(TIFFSetField( tiff, fip->field_tag, text ) != 1) {
                fprintf(stderr, "Failed to set %s from file %s\n", 
                        fip->field_name, argv[arg_index]);
            }

            _TIFFfree( text );
            arg_index++;

        } else if (strcmp(argv[arg_index],"-f") == 0 && arg_index < argc-5)
        {
			/* KAM - add option to force data type and handling of unrecognized tags
			*/
			arg_index++;
			user_field_type = atoi(argv[arg_index]);
        } else {
            fprintf(stderr, "Unrecognized option: %s\n",
                    argv[arg_index]);
            usage();
        }
    }

    TIFFRewriteDirectory(tiff);
    TIFFClose(tiff);
    return 0;
}

/* vim: set ts=8 sts=8 sw=8 noet: */