| AWARE [SYSTEMS] | Imaging expertise for the Delphi developer | |||||||
![]() |
TIFF and LibTiff Mailing List Archive | |||||||
LibTiff Mailing List
TIFF and LibTiff Mailing List Archive Contact
The TIFF Mailing List Homepage |
Thread2010.03.22 02:56 "Re: Problems with Modified tiffset", by Kevin MyersOops, 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: */ |
|||||||