1 /******************************************************************************
2 * $Id: tiffset.c,v 1.19 2017-10-01 17:38:12 erouault Exp $
3 *
4 * Project: libtiff tools
5 * Purpose: Mainline for setting metadata in existing TIFF files.
6 * Author: Frank Warmerdam, warmerdam@pobox.com
7 *
8 ******************************************************************************
9 * Copyright (c) 2000, Frank Warmerdam
10 *
11 * Permission to use, copy, modify, distribute, and sell this software and
12 * its documentation for any purpose is hereby granted without fee, provided
13 * that (i) the above copyright notices and this permission notice appear in
14 * all copies of the software and related documentation, and (ii) the names of
15 * Sam Leffler and Silicon Graphics may not be used in any advertising or
16 * publicity relating to the software without the specific, prior written
17 * permission of Sam Leffler and Silicon Graphics.
18 *
19 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
21 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
22 *
23 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
24 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
25 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
26 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
27 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
28 * OF THIS SOFTWARE.
29 ******************************************************************************
30 */
31
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdlib.h>
36
37 #include "tiffio.h"
38
39 static char* usageMsg[] = {
40 "usage: tiffset [options] filename",
41 "where options are:",
42 " -s <tagname> [count] <value>... set the tag value",
43 " -u <tagname> to unset the tag",
44 " -d <dirno> set the directory",
45 " -sd <diroff> set the subdirectory",
46 " -sf <tagname> <filename> read the tag value from file (for ASCII tags only)",
47 NULL
48 };
49
50 static void
usage(void)51 usage(void)
52 {
53 int i;
54 for (i = 0; usageMsg[i]; i++)
55 fprintf(stderr, "%s\n", usageMsg[i]);
56 exit(-1);
57 }
58
59 static const TIFFField *
GetField(TIFF * tiff,const char * tagname)60 GetField(TIFF *tiff, const char *tagname)
61 {
62 const TIFFField *fip;
63
64 if( atoi(tagname) > 0 )
65 fip = TIFFFieldWithTag(tiff, (ttag_t)atoi(tagname));
66 else
67 fip = TIFFFieldWithName(tiff, tagname);
68
69 if (!fip) {
70 fprintf( stderr, "Field name \"%s\" is not recognised.\n", tagname );
71 return (TIFFField *)NULL;
72 }
73
74 return fip;
75 }
76
77 int
main(int argc,char * argv[])78 main(int argc, char* argv[])
79 {
80 TIFF *tiff;
81 int arg_index;
82
83 if (argc < 2)
84 usage();
85
86 tiff = TIFFOpen(argv[argc-1], "r+");
87 if (tiff == NULL)
88 return 2;
89
90 for( arg_index = 1; arg_index < argc-1; arg_index++ ) {
91 if (strcmp(argv[arg_index],"-d") == 0 && arg_index < argc-2) {
92 arg_index++;
93 if( TIFFSetDirectory(tiff, atoi(argv[arg_index]) ) != 1 )
94 {
95 fprintf( stderr, "Failed to set directory=%s\n", argv[arg_index] );
96 return 6;
97 }
98 arg_index++;
99 }
100 if (strcmp(argv[arg_index],"-sd") == 0 && arg_index < argc-2) {
101 arg_index++;
102 if( TIFFSetSubDirectory(tiff, atoi(argv[arg_index]) ) != 1 )
103 {
104 fprintf( stderr, "Failed to set sub directory=%s\n", argv[arg_index] );
105 return 7;
106 }
107 arg_index++;
108 }
109 /* Add unset option to tiffset -- Zach Baker (niquil@niquil.net) 11/14/2012 */
110 if (strcmp(argv[arg_index],"-u") == 0 && arg_index < argc-2) {
111 const TIFFField *fip;
112 const char *tagname;
113 arg_index++;
114 tagname = argv[arg_index];
115 fip = GetField(tiff, tagname);
116 if (!fip)
117 return 3;
118
119 if (TIFFUnsetField(tiff, TIFFFieldTag(fip)) != 1)
120 {
121 fprintf(stderr, "Failed to unset %s\n", TIFFFieldName(fip));
122 }
123 arg_index++;
124 } else if (strcmp(argv[arg_index],"-s") == 0 && arg_index < argc-3) {
125 const TIFFField *fip;
126 const char *tagname;
127
128 arg_index++;
129 tagname = argv[arg_index];
130 fip = GetField(tiff, tagname);
131
132 if (!fip)
133 return 3;
134
135 arg_index++;
136 if (TIFFFieldDataType(fip) == TIFF_ASCII) {
137 if (TIFFSetField(tiff, TIFFFieldTag(fip), argv[arg_index]) != 1)
138 fprintf( stderr, "Failed to set %s=%s\n",
139 TIFFFieldName(fip), argv[arg_index] );
140 } else if (TIFFFieldWriteCount(fip) > 0
141 || TIFFFieldWriteCount(fip) == TIFF_VARIABLE) {
142 int ret = 1;
143 short wc;
144
145 if (TIFFFieldWriteCount(fip) == TIFF_VARIABLE)
146 wc = atoi(argv[arg_index++]);
147 else
148 wc = TIFFFieldWriteCount(fip);
149
150 if (argc - arg_index < wc) {
151 fprintf( stderr,
152 "Number of tag values is not enough. "
153 "Expected %d values for %s tag, got %d\n",
154 wc, TIFFFieldName(fip), argc - arg_index);
155 return 4;
156 }
157
158 if (wc > 1 || TIFFFieldWriteCount(fip) == TIFF_VARIABLE) {
159 int i, size;
160 void *array;
161
162 switch (TIFFFieldDataType(fip)) {
163 /*
164 * XXX: We can't use TIFFDataWidth()
165 * to determine the space needed to store
166 * the value. For TIFF_RATIONAL values
167 * TIFFDataWidth() returns 8, but we use 4-byte
168 * float to represent rationals.
169 */
170 case TIFF_BYTE:
171 case TIFF_ASCII:
172 case TIFF_SBYTE:
173 case TIFF_UNDEFINED:
174 default:
175 size = 1;
176 break;
177
178 case TIFF_SHORT:
179 case TIFF_SSHORT:
180 size = 2;
181 break;
182
183 case TIFF_LONG:
184 case TIFF_SLONG:
185 case TIFF_FLOAT:
186 case TIFF_IFD:
187 case TIFF_RATIONAL:
188 case TIFF_SRATIONAL:
189 size = 4;
190 break;
191
192 case TIFF_DOUBLE:
193 size = 8;
194 break;
195 }
196
197 array = _TIFFmalloc(wc * size);
198 if (!array) {
199 fprintf(stderr, "No space for %s tag\n",
200 tagname);
201 return 4;
202 }
203
204 switch (TIFFFieldDataType(fip)) {
205 case TIFF_BYTE:
206 for (i = 0; i < wc; i++)
207 ((uint8 *)array)[i] = atoi(argv[arg_index+i]);
208 break;
209 case TIFF_SHORT:
210 for (i = 0; i < wc; i++)
211 ((uint16 *)array)[i] = atoi(argv[arg_index+i]);
212 break;
213 case TIFF_SBYTE:
214 for (i = 0; i < wc; i++)
215 ((int8 *)array)[i] = atoi(argv[arg_index+i]);
216 break;
217 case TIFF_SSHORT:
218 for (i = 0; i < wc; i++)
219 ((int16 *)array)[i] = atoi(argv[arg_index+i]);
220 break;
221 case TIFF_LONG:
222 for (i = 0; i < wc; i++)
223 ((uint32 *)array)[i] = atol(argv[arg_index+i]);
224 break;
225 case TIFF_SLONG:
226 case TIFF_IFD:
227 for (i = 0; i < wc; i++)
228 ((uint32 *)array)[i] = atol(argv[arg_index+i]);
229 break;
230 case TIFF_DOUBLE:
231 for (i = 0; i < wc; i++)
232 ((double *)array)[i] = atof(argv[arg_index+i]);
233 break;
234 case TIFF_RATIONAL:
235 case TIFF_SRATIONAL:
236 case TIFF_FLOAT:
237 for (i = 0; i < wc; i++)
238 ((float *)array)[i] = (float)atof(argv[arg_index+i]);
239 break;
240 default:
241 break;
242 }
243
244 if (TIFFFieldPassCount(fip)) {
245 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
246 wc, array);
247 } else if (TIFFFieldTag(fip) == TIFFTAG_PAGENUMBER
248 || TIFFFieldTag(fip) == TIFFTAG_HALFTONEHINTS
249 || TIFFFieldTag(fip) == TIFFTAG_YCBCRSUBSAMPLING
250 || TIFFFieldTag(fip) == TIFFTAG_DOTRANGE) {
251 if (TIFFFieldDataType(fip) == TIFF_BYTE) {
252 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
253 ((uint8 *)array)[0], ((uint8 *)array)[1]);
254 } else if (TIFFFieldDataType(fip) == TIFF_SHORT) {
255 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
256 ((uint16 *)array)[0], ((uint16 *)array)[1]);
257 }
258 } else {
259 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
260 array);
261 }
262
263 _TIFFfree(array);
264 } else {
265 switch (TIFFFieldDataType(fip)) {
266 case TIFF_BYTE:
267 case TIFF_SHORT:
268 case TIFF_SBYTE:
269 case TIFF_SSHORT:
270 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
271 atoi(argv[arg_index++]));
272 break;
273 case TIFF_LONG:
274 case TIFF_SLONG:
275 case TIFF_IFD:
276 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
277 atol(argv[arg_index++]));
278 break;
279 case TIFF_DOUBLE:
280 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
281 atof(argv[arg_index++]));
282 break;
283 case TIFF_RATIONAL:
284 case TIFF_SRATIONAL:
285 case TIFF_FLOAT:
286 ret = TIFFSetField(tiff, TIFFFieldTag(fip),
287 (float)atof(argv[arg_index++]));
288 break;
289 default:
290 break;
291 }
292 }
293
294 if (ret != 1)
295 fprintf(stderr, "Failed to set %s\n", TIFFFieldName(fip));
296 arg_index += wc;
297 }
298 } else if (strcmp(argv[arg_index],"-sf") == 0 && arg_index < argc-3) {
299 FILE *fp;
300 const TIFFField *fip;
301 char *text;
302 size_t len;
303
304 arg_index++;
305 fip = GetField(tiff, argv[arg_index]);
306
307 if (!fip)
308 return 3;
309
310 if (TIFFFieldDataType(fip) != TIFF_ASCII) {
311 fprintf( stderr,
312 "Only ASCII tags can be set from file. "
313 "%s is not ASCII tag.\n", TIFFFieldName(fip) );
314 return 5;
315 }
316
317 arg_index++;
318 fp = fopen( argv[arg_index], "rt" );
319 if(fp == NULL) {
320 perror( argv[arg_index] );
321 continue;
322 }
323
324 text = (char *) malloc(1000000);
325 len = fread( text, 1, 999999, fp );
326 text[len] = '\0';
327
328 fclose( fp );
329
330 if(TIFFSetField( tiff, TIFFFieldTag(fip), text ) != 1) {
331 fprintf(stderr, "Failed to set %s from file %s\n",
332 TIFFFieldName(fip), argv[arg_index]);
333 }
334
335 _TIFFfree( text );
336 arg_index++;
337 } else {
338 fprintf(stderr, "Unrecognised option: %s\n",
339 argv[arg_index]);
340 usage();
341 }
342 }
343
344 TIFFRewriteDirectory(tiff);
345 TIFFClose(tiff);
346 return 0;
347 }
348
349 /* vim: set ts=8 sts=8 sw=8 noet: */
350 /*
351 * Local Variables:
352 * mode: c
353 * c-basic-offset: 8
354 * fill-column: 78
355 * End:
356 */
357