Fix FreeBSD build.
[haiku.git] / src / tools / translation / tiffinfo / tiffinfo.cpp
blobb6e41b7eeac52cf2674978e476b77eef4482fd0b
1 /*****************************************************************************/
2 // tiffinfo
3 // Written by Michael Wilber, OBOS Translation Kit Team
4 //
5 // Version:
6 //
7 // tiffinfo is a command line program for displaying text information about
8 // TIFF images. This information includes a listing of every field (tag) in
9 // the TIFF file, for every image in the file. Also, for some fields,
10 // the numerical value for the field is converted to descriptive text.
12 // This application and all source files used in its construction, except
13 // where noted, are licensed under the MIT License, and have been written
14 // and are:
16 // Copyright (c) 2003 OpenBeOS Project
18 // Permission is hereby granted, free of charge, to any person obtaining a
19 // copy of this software and associated documentation files (the "Software"),
20 // to deal in the Software without restriction, including without limitation
21 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
22 // and/or sell copies of the Software, and to permit persons to whom the
23 // Software is furnished to do so, subject to the following conditions:
25 // The above copyright notice and this permission notice shall be included
26 // in all copies or substantial portions of the Software.
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
29 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
31 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
34 // DEALINGS IN THE SOFTWARE.
35 /*****************************************************************************/
36 #include <ByteOrder.h>
37 #include <File.h>
38 #include <StorageDefs.h>
39 #include <iostream.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
44 struct IFDEntry {
45 uint16 tag;
46 // uniquely identifies the field
47 uint16 fieldType;
48 // number, string, float, etc.
49 uint32 count;
50 // length / number of values
52 // The actual value or the file offset
53 // where the actual value is located
54 union {
55 float floatval;
56 uint32 longval;
57 uint16 shortvals[2];
58 uint8 bytevals[4];
62 enum ENTRY_TYPE {
63 TIFF_BYTE = 1,
64 TIFF_ASCII,
65 TIFF_SHORT,
66 TIFF_LONG,
67 TIFF_RATIONAL,
68 TIFF_SBYTE,
69 TIFF_UNDEFINED,
70 TIFF_SSHORT,
71 TIFF_SLONG,
72 TIFF_SRATIONAL,
73 TIFF_FLOAT,
74 TIFF_DOUBLE
77 const char *
78 get_type_string(uint16 type)
80 const char *kstrTypes[] = {
81 "Byte",
82 "ASCII",
83 "Short",
84 "Long",
85 "Rational",
86 "Signed Byte",
87 "Undefined",
88 "Signed Short",
89 "Signed Long",
90 "Signed Rational",
91 "Float",
92 "Double"
95 if (type >= 1 && type <= 12)
96 return kstrTypes[type - 1];
97 else
98 return "?";
101 const char *
102 get_tag_string(uint16 tag)
104 switch (tag) {
105 case 254: return "New Subfile Type";
106 case 255: return "Subfile Type";
107 case 256: return "Image Width";
108 case 257: return "Image Height";
109 case 258: return "Bits Per Sample";
110 case 259: return "Compression";
111 case 262: return "Photometric Interpretation";
112 case 263: return "Thresholding";
113 case 264: return "CellWidth";
114 case 265: return "CellLength";
115 case 266: return "Fill Order";
116 case 269: return "Document Name";
117 case 270: return "Image Description";
118 case 271: return "Make";
119 case 272: return "Model";
120 case 273: return "Strip Offsets";
121 case 274: return "Orientation";
122 case 277: return "Samples Per Pixel";
123 case 278: return "Rows Per Strip";
124 case 279: return "Strip Byte Counts";
125 case 280: return "Min Sample Value";
126 case 281: return "Max Sample Value";
127 case 282: return "X Resolution";
128 case 283: return "Y Resolution";
129 case 284: return "Planar Configuration";
130 case 285: return "Page Name";
131 case 286: return "X Position";
132 case 287: return "Y Position";
133 case 288: return "Free Offsets";
134 case 289: return "Free Byte Counts";
135 case 290: return "Gray Response Unit";
136 case 291: return "Gray Response Curve";
137 case 292: return "T4 Options";
138 case 293: return "T6 Options";
139 case 296: return "Resolution Unit";
140 case 297: return "Page Number";
141 case 305: return "Software";
142 case 306: return "DateTime";
143 case 315: return "Artist";
144 case 316: return "Host Computer";
145 case 320: return "Color Map";
146 case 322: return "Tile Width";
147 case 323: return "Tile Height";
148 case 324: return "Tile Offsets";
149 case 325: return "Tile Byte Counts";
150 case 338: return "Extra Samples";
151 case 339: return "Sample Format";
152 case 529: return "YCbCr Coefficients";
153 case 530: return "YCbCr Subsampling";
154 case 531: return "YCbCr Positioning";
155 case 532: return "Reference Black White";
156 case 32995: return "Matteing";
157 case 32996: return "Data Type"; // obseleted by SampleFormat tag
158 case 32997: return "Image Depth"; // tile / strip calculations
159 case 32998: return "Tile Depth"; // tile / strip calculations
160 case 33432: return "Copyright";
161 case 37439: return "StoNits?";
163 default:
164 return "?";
168 void
169 print_ifd_value(IFDEntry &entry, BFile &file, swap_action swp)
171 switch (entry.tag) {
172 case 254: // NewSubfileType
173 if (entry.count == 1 && entry.fieldType == TIFF_LONG) {
174 if (entry.longval & 1)
175 printf("Low Res (1) ");
176 if (entry.longval & 2)
177 printf("Page (2) ");
178 if (entry.longval & 4)
179 printf("Mask (4) ");
181 printf("(0x%.8lx)", entry.longval);
182 return;
184 break;
186 case 256: // ImageWidth
187 case 257: // ImageHeight
188 if (entry.count == 1) {
189 printf("%d",
190 ((entry.fieldType == TIFF_SHORT) ?
191 entry.shortvals[0] : static_cast<unsigned int>(entry.longval)));
192 return;
194 break;
196 case 259:
197 if (entry.count == 1 && entry.fieldType == TIFF_SHORT) {
198 switch (entry.shortvals[0]) {
199 case 1:
200 printf("No Compression (1)");
201 return;
202 case 2:
203 printf("CCITT Group 3 1-Dimensional Modified Huffman run-length encoding (2)");
204 return;
205 case 3:
206 printf("Fax Group 3 (3)");
207 return;
208 case 4:
209 printf("Fax Group 4 (4)");
210 return;
211 case 5:
212 printf("LZW (5)");
213 return;
214 case 32773:
215 printf("PackBits (32773)");
216 return;
219 break;
221 case 262: // PhotometricInterpretation
222 if (entry.count == 1 && entry.fieldType == TIFF_SHORT) {
223 switch (entry.shortvals[0]) {
224 case 0:
225 printf("White is Zero (%d)", entry.shortvals[0]);
226 return;
227 case 1:
228 printf("Black is Zero (%d)", entry.shortvals[0]);
229 return;
230 case 2:
231 printf("RGB (%d)", entry.shortvals[0]);
232 return;
233 case 3:
234 printf("Palette Color (%d)", entry.shortvals[0]);
235 return;
236 case 4:
237 printf("Transparency Mask (%d)", entry.shortvals[0]);
238 return;
241 break;
243 case 274: // Orientation
244 if (entry.count == 1 && entry.fieldType == TIFF_SHORT) {
245 switch (entry.shortvals[0]) {
246 case 1:
247 printf("top to bottom, left to right (1)");
248 return;
249 case 2:
250 printf("top to bottom, right to left (2)");
251 return;
252 case 3:
253 printf("bottom to top, right to left (3)");
254 return;
255 case 4:
256 printf("bottom to top, left to right (4)");
257 return;
258 case 5:
259 printf("left to right, top to bottom (5)");
260 return;
261 case 6:
262 printf("right to left, top to bottom (6)");
263 return;
264 case 7:
265 printf("right to left, bottom to top (7)");
266 return;
267 case 8:
268 printf("left to right, bottom to top (8)");
269 return;
272 break;
274 case 278: // RowsPerStrip
276 const uint32 ksinglestrip = 0xffffffffUL;
277 printf("%u",
278 static_cast<unsigned int>(entry.longval));
279 if (entry.longval == ksinglestrip)
280 printf(" (All rows in first strip)");
281 return;
284 case 284: // PlanarConfiguration
285 if (entry.count == 1 && entry.fieldType == TIFF_SHORT) {
286 if (entry.shortvals[0] == 1) {
287 printf("Chunky (%d)", entry.shortvals[0]);
288 return;
290 else if (entry.shortvals[0] == 2) {
291 printf("Planar (%d)", entry.shortvals[0]);
292 return;
295 break;
297 case 296: // ResolutionUnit
298 if (entry.count == 1 && entry.fieldType == TIFF_SHORT) {
299 switch (entry.shortvals[0]) {
300 case 1:
301 printf("None (%d)", entry.shortvals[0]);
302 return;
303 case 2:
304 printf("Inch (%d)", entry.shortvals[0]);
305 return;
306 case 3:
307 printf("Cenimeter (%d)", entry.shortvals[0]);
308 return;
311 break;
313 default:
314 if (entry.fieldType == TIFF_ASCII) {
315 char ascfield[256] = { 0 };
317 if (entry.count <= 4)
318 memcpy(ascfield, &entry.longval, entry.count);
319 else if (entry.count > 4 && entry.count < 256) {
320 ssize_t nread = file.ReadAt(entry.longval, ascfield, entry.count);
321 if (nread != static_cast<ssize_t>(entry.count))
322 ascfield[0] = '\0';
325 if (ascfield[0] != '\0') {
326 printf("%s", ascfield);
327 return;
329 } else if (entry.fieldType == TIFF_RATIONAL && entry.count == 1) {
330 struct { uint32 numerator; uint32 denominator; } rational;
332 ssize_t nread = file.ReadAt(entry.longval, &rational, 8);
333 if (nread == 8 &&
334 swap_data(B_UINT32_TYPE, &rational, 8, swp) == B_OK) {
336 printf("%u / %u (offset: 0x%.8lx)",
337 static_cast<unsigned int>(rational.numerator),
338 static_cast<unsigned int>(rational.denominator),
339 entry.longval);
340 return;
342 } else if (entry.fieldType == TIFF_SRATIONAL && entry.count == 1) {
343 struct { int32 numerator; int32 denominator; } srational;
345 ssize_t nread = file.ReadAt(entry.longval, &srational, 8);
346 if (nread == 8 &&
347 swap_data(B_INT32_TYPE, &srational, 8, swp) == B_OK) {
349 printf("%d / %d (offset: 0x%.8lx)",
350 static_cast<int>(srational.numerator),
351 static_cast<int>(srational.denominator),
352 entry.longval);
353 return;
355 } else if (entry.fieldType == TIFF_LONG && entry.count == 1) {
356 printf("%u",
357 static_cast<unsigned int>(entry.longval));
358 return;
359 } else if (entry.fieldType == TIFF_SLONG && entry.count == 1) {
360 printf("%d",
361 static_cast<int>(entry.longval));
362 return;
363 } else if (entry.fieldType == TIFF_SHORT && entry.count <= 2) {
364 for (uint32 i = 0; i < entry.count; i++) {
365 if (i > 0)
366 printf(", ");
367 printf("%u", entry.shortvals[i]);
369 return;
370 } else if (entry.fieldType == TIFF_SSHORT && entry.count <= 2) {
371 for (uint32 i = 0; i < entry.count; i++) {
372 if (i > 0)
373 printf(", ");
374 printf("%d", entry.shortvals[i]);
376 return;
377 } else if (entry.fieldType == TIFF_BYTE && entry.count <= 4) {
378 for (uint32 i = 0; i < entry.count; i++) {
379 if (i > 0)
380 printf(", ");
381 printf("%u", entry.bytevals[i]);
383 return;
384 } else if (entry.fieldType == TIFF_SBYTE && entry.count <= 4) {
385 for (uint32 i = 0; i < entry.count; i++) {
386 if (i > 0)
387 printf(", ");
388 printf("%d", entry.bytevals[i]);
390 return;
391 } else if (entry.fieldType == TIFF_UNDEFINED && entry.count <= 4) {
392 for (uint32 i = 0; i < entry.count; i++) {
393 if (i > 0)
394 printf(", ");
395 printf("0x%.2lx",
396 static_cast<unsigned long>(entry.bytevals[i]));
398 return;
400 break;
402 printf("0x%.8lx", entry.longval);
405 int swap_value_field(IFDEntry &entry, swap_action swp)
407 switch (entry.fieldType) {
408 case TIFF_BYTE:
409 case TIFF_ASCII:
410 case TIFF_SBYTE:
411 case TIFF_UNDEFINED:
412 if (entry.count > 4) {
413 if (swap_data(B_UINT32_TYPE, &entry.longval, 4, swp) != B_OK)
414 return 0;
416 return 1;
418 case TIFF_LONG:
419 case TIFF_SLONG:
420 case TIFF_RATIONAL:
421 case TIFF_SRATIONAL:
422 case TIFF_DOUBLE:
423 if (swap_data(B_UINT32_TYPE, &entry.longval, 4, swp) != B_OK)
424 return 0;
425 return 1;
427 case TIFF_FLOAT:
428 if (swap_data(B_FLOAT_TYPE, &entry.floatval, 4, swp) != B_OK)
429 return 0;
430 return 1;
432 case TIFF_SHORT:
433 case TIFF_SSHORT:
434 if (entry.count <= 2) {
435 if (swap_data(B_UINT16_TYPE, &entry.shortvals,
436 entry.count * 2, swp) != B_OK)
437 return 0;
438 } else {
439 if (swap_data(B_UINT32_TYPE, &entry.longval, 4, swp) != B_OK)
440 return 0;
443 return 1;
446 // no error, but unknown type
447 return 2;
451 report_ifd_entries(BFile &file, uint16 entrycount, swap_action swp)
453 IFDEntry entry;
455 if (sizeof(IFDEntry) != 12) {
456 printf("IFDEntry size must be 12\n");
457 return 0;
460 off_t offset = file.Position();
461 for (uint16 i = 0; i < entrycount; offset += 12, i++) {
462 ssize_t nread = file.Read(&entry, 12);
463 if (nread != 12) {
464 printf("unable to read entire ifd entry\n");
465 return 0;
467 if (swap_data(B_UINT16_TYPE, &entry.tag, 4, swp) != B_OK ||
468 swap_data(B_UINT32_TYPE, &entry.count, 4, swp) != B_OK) {
469 printf("swap_data failed\n");
470 return 0;
473 if (!swap_value_field(entry, swp)) {
474 printf("swap_value_field failed\n");
475 return 0;
478 printf("\nOffset: 0x%.8lx\n", static_cast<unsigned long>(offset));
479 printf( " Tag: %s (%d)\n", get_tag_string(entry.tag), entry.tag);
480 printf( " Type: %s (%d)\n", get_type_string(entry.fieldType),
481 entry.fieldType);
482 printf( " Count: %d\n", static_cast<int>(entry.count));
483 printf( " Value: ");
484 print_ifd_value(entry, file, swp);
485 printf("\n");
488 return 1;
492 report_ifd(BFile &file, uint32 ifdoffset, swap_action swp)
494 printf("\n<< BEGIN: IFD at 0x%.8lx >>\n\n", ifdoffset);
496 if (file.Seek(ifdoffset, SEEK_SET) != ifdoffset) {
497 printf("failed to seek to IFD offset: %d\n",
498 static_cast<unsigned int>(ifdoffset));
499 return 0;
502 uint16 entrycount = 0;
503 ssize_t nread = file.Read(&entrycount, 2);
504 if (nread != 2) {
505 printf("unable to read entry count\n");
506 return 0;
508 if (swap_data(B_UINT16_TYPE, &entrycount, sizeof(uint16), swp) != B_OK) {
509 printf("failed to swap entrycount\n");
510 return 0;
512 printf("Entry Count: %d\n", entrycount);
514 // Print out entries
515 int ret = report_ifd_entries(file, entrycount, swp);
517 if (ret) {
518 uint32 nextIFDOffset = 0;
520 nread = file.Read(&nextIFDOffset, 4);
521 if (nread != 4) {
522 printf("unable to read next IFD\n");
523 return 0;
525 if (swap_data(B_UINT32_TYPE, &nextIFDOffset, sizeof(uint32), swp) != B_OK) {
526 printf("failed to swap next IFD\n");
527 return 0;
530 printf("Next IFD Offset: 0x%.8lx\n", nextIFDOffset);
531 printf("\n<< END: IFD at 0x%.8lx >>\n\n", ifdoffset);
533 if (nextIFDOffset != 0)
534 return report_ifd(file, nextIFDOffset, swp);
535 else
536 return 1;
538 } else
539 return 0;
542 int generate_report(const char *filepath)
544 BFile file(filepath, B_READ_ONLY);
546 if (file.InitCheck() == B_OK) {
548 uint8 buffer[64];
550 // Byte Order
551 const uint8 kleSig[] = { 0x49, 0x49, 0x2a, 0x00 };
552 const uint8 kbeSig[] = { 0x4d, 0x4d, 0x00, 0x2a };
554 ssize_t nread = file.Read(buffer, 4);
555 if (nread != 4) {
556 printf("Unable to read first 4 bytes\n");
557 return 0;
560 swap_action swp;
561 if (memcmp(buffer, kleSig, 4) == 0) {
562 swp = B_SWAP_LENDIAN_TO_HOST;
563 printf("Byte Order: little endian\n");
565 } else if (memcmp(buffer, kbeSig, 4) == 0) {
566 swp = B_SWAP_BENDIAN_TO_HOST;
567 printf("Byte Order: big endian\n");
569 } else {
570 printf("Invalid byte order value\n");
571 return 0;
574 // Location of first IFD
575 uint32 firstIFDOffset = 0;
576 nread = file.Read(&firstIFDOffset, 4);
577 if (nread != 4) {
578 printf("Unable to read first IFD offset\n");
579 return 0;
581 if (swap_data(B_UINT32_TYPE, &firstIFDOffset, sizeof(uint32), swp) != B_OK) {
582 printf("swap_data() error\n");
583 return 0;
585 printf("First IFD: 0x%.8lx\n", firstIFDOffset);
587 // print out first IFD
588 report_ifd(file, firstIFDOffset, swp);
590 return 1;
593 return 0;
596 int main(int argc, char **argv)
598 printf("\n");
599 // put a line break at the beginning of output
600 // to improve readability
602 if (argc == 2) {
604 printf("TIFF Image: %s\n\n", argv[1]);
605 generate_report(argv[1]);
607 } else {
609 printf("tiffinfo - reports information about a TIFF image\n");
610 printf("\nUsage:\n");
611 printf("tiffinfo filename.tif\n\n");
614 return 0;