initial checkin for tiffinfo, a command line tool for displaying information about TIFF image files
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3311 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
069801512a
commit
610eca212f
4
src/tools/translation/tiffinfo/Jamfile
Normal file
4
src/tools/translation/tiffinfo/Jamfile
Normal file
@ -0,0 +1,4 @@
|
||||
SubDir OBOS_TOP src tools translation tiffinfo ;
|
||||
|
||||
BinCommand tiffinfo : tiffinfo.cpp : be ;
|
||||
|
557
src/tools/translation/tiffinfo/tiffinfo.cpp
Normal file
557
src/tools/translation/tiffinfo/tiffinfo.cpp
Normal file
@ -0,0 +1,557 @@
|
||||
/*****************************************************************************/
|
||||
// tiffinfo
|
||||
// Written by Michael Wilber, OBOS Translation Kit Team
|
||||
//
|
||||
// Version:
|
||||
//
|
||||
// tiffinfo is a command line program for displaying text information about
|
||||
// TIFF images. This information includes a listing of every field (tag) in
|
||||
// the TIFF file, for every image in the file. Also, for some fields,
|
||||
// the numerical value for the field is converted to descriptive text.
|
||||
//
|
||||
// This application and all source files used in its construction, except
|
||||
// where noted, are licensed under the MIT License, and have been written
|
||||
// and are:
|
||||
//
|
||||
// Copyright (c) 2003 OpenBeOS Project
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
/*****************************************************************************/
|
||||
#include <ByteOrder.h>
|
||||
#include <File.h>
|
||||
#include <iostream.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct IFDEntry {
|
||||
uint16 tag;
|
||||
// uniquely identifies the field
|
||||
uint16 fieldType;
|
||||
// number, string, float, etc.
|
||||
uint32 count;
|
||||
// length / number of values
|
||||
|
||||
// The actual value or the file offset
|
||||
// where the actual value is located
|
||||
union {
|
||||
float floatval;
|
||||
uint32 longval;
|
||||
uint16 shortvals[2];
|
||||
uint8 bytevals[4];
|
||||
};
|
||||
};
|
||||
|
||||
enum ENTRY_TYPE {
|
||||
TIFF_BYTE = 1,
|
||||
TIFF_ASCII,
|
||||
TIFF_SHORT,
|
||||
TIFF_LONG,
|
||||
TIFF_RATIONAL,
|
||||
TIFF_SBYTE,
|
||||
TIFF_UNDEFINED,
|
||||
TIFF_SSHORT,
|
||||
TIFF_SRATIONAL,
|
||||
TIFF_FLOAT,
|
||||
TIFF_DOUBLE
|
||||
};
|
||||
|
||||
const char *
|
||||
get_type_string(uint16 type)
|
||||
{
|
||||
const char *kstrTypes[] = {
|
||||
"Byte",
|
||||
"ASCII",
|
||||
"Short",
|
||||
"Long",
|
||||
"Rational",
|
||||
"Signed Byte",
|
||||
"Undefined",
|
||||
"Signed Short",
|
||||
"Signed Long",
|
||||
"Signed Rational",
|
||||
"Float",
|
||||
"Double"
|
||||
};
|
||||
|
||||
if (type >= 1 && type <= 12)
|
||||
return kstrTypes[type - 1];
|
||||
else
|
||||
return "?";
|
||||
}
|
||||
|
||||
const char *
|
||||
get_tag_string(uint16 tag)
|
||||
{
|
||||
switch (tag) {
|
||||
case 254: return "New Subfile Type";
|
||||
case 255: return "Subfile Type";
|
||||
case 256: return "Image Width";
|
||||
case 257: return "Image Height";
|
||||
case 258: return "Bits Per Sample";
|
||||
case 259: return "Compression";
|
||||
case 262: return "Photometric Interpretation";
|
||||
case 263: return "Thresholding";
|
||||
case 264: return "CellWidth";
|
||||
case 265: return "CellLength";
|
||||
case 266: return "Fill Order";
|
||||
case 269: return "Document Name";
|
||||
case 270: return "Image Description";
|
||||
case 271: return "Make";
|
||||
case 272: return "Model";
|
||||
case 273: return "Strip Offsets";
|
||||
case 274: return "Orientation";
|
||||
case 277: return "Samples Per Pixel";
|
||||
case 278: return "Rows Per Strip";
|
||||
case 279: return "Strip Byte Counts";
|
||||
case 280: return "Min Sample Value";
|
||||
case 281: return "Max Sample Value";
|
||||
case 282: return "X Resolution";
|
||||
case 283: return "Y Resolution";
|
||||
case 284: return "Planar Configuration";
|
||||
case 285: return "Page Name";
|
||||
case 286: return "X Position";
|
||||
case 287: return "Y Position";
|
||||
case 288: return "Free Offsets";
|
||||
case 289: return "Free Byte Counts";
|
||||
case 290: return "Gray Response Unit";
|
||||
case 291: return "Gray Response Curve";
|
||||
case 292: return "T4 Options";
|
||||
case 293: return "T6 Options";
|
||||
case 296: return "Resolution Unit";
|
||||
case 297: return "Page Number";
|
||||
case 305: return "Software";
|
||||
case 306: return "DateTime";
|
||||
case 315: return "Artist";
|
||||
case 316: return "Host Computer";
|
||||
case 320: return "Color Map";
|
||||
case 322: return "Tile Width";
|
||||
case 323: return "Tile Height";
|
||||
case 324: return "Tile Offsets";
|
||||
case 325: return "Tile Byte Counts";
|
||||
case 338: return "Extra Samples";
|
||||
case 339: return "Sample Format";
|
||||
case 529: return "YCbCr Coefficients";
|
||||
case 530: return "YCbCr Subsampling";
|
||||
case 531: return "YCbCr Positioning";
|
||||
case 532: return "Reference Black White";
|
||||
case 32995: return "Matteing";
|
||||
case 32996: return "Data Type"; // obseleted by SampleFormat tag
|
||||
case 32997: return "Image Depth"; // tile / strip calculations
|
||||
case 32998: return "Tile Depth"; // tile / strip calculations
|
||||
case 33432: return "Copyright";
|
||||
case 37439: return "StoNits?";
|
||||
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_ifd_value(IFDEntry &entry, BFile &file, swap_action swp)
|
||||
{
|
||||
switch (entry.tag) {
|
||||
case 254: // NewSubfileType
|
||||
if (entry.count == 1 && entry.fieldType == TIFF_LONG) {
|
||||
if (entry.longval & 1)
|
||||
printf("Low Res ");
|
||||
if (entry.longval & 2)
|
||||
printf("Page ");
|
||||
if (entry.longval & 4)
|
||||
printf("Mask ");
|
||||
|
||||
printf("(0x%.8lx)", entry.longval);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 256: // ImageWidth
|
||||
case 257: // ImageHeight
|
||||
if (entry.count == 1) {
|
||||
printf("%d",
|
||||
((entry.fieldType == TIFF_SHORT) ?
|
||||
entry.shortvals[0] : static_cast<unsigned int>(entry.longval)));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 259:
|
||||
if (entry.count == 1 && entry.fieldType == TIFF_SHORT) {
|
||||
switch (entry.shortvals[0]) {
|
||||
case 1:
|
||||
printf("No Compression");
|
||||
return;
|
||||
case 2:
|
||||
printf("CCITT Group 3 1-Dimensional Modified Huffman run-length encoding");
|
||||
return;
|
||||
case 5:
|
||||
printf("LZW");
|
||||
return;
|
||||
case 32773:
|
||||
printf("PackBits");
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 262: // PhotometricInterpretation
|
||||
if (entry.count == 1 && entry.fieldType == TIFF_SHORT) {
|
||||
switch (entry.shortvals[0]) {
|
||||
case 0:
|
||||
printf("White is Zero (%d)", entry.shortvals[0]);
|
||||
return;
|
||||
case 1:
|
||||
printf("Black is Zero (%d)", entry.shortvals[0]);
|
||||
return;
|
||||
case 2:
|
||||
printf("RGB (%d)", entry.shortvals[0]);
|
||||
return;
|
||||
case 3:
|
||||
printf("Palette Color (%d)", entry.shortvals[0]);
|
||||
return;
|
||||
case 4:
|
||||
printf("Transparency Mask (%d)", entry.shortvals[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 274: // Orientation
|
||||
if (entry.count == 1 && entry.fieldType == TIFF_SHORT) {
|
||||
switch (entry.shortvals[0]) {
|
||||
case 1:
|
||||
printf("top to bottom, left to right");
|
||||
return;
|
||||
case 2:
|
||||
printf("top to bottom, right to left");
|
||||
return;
|
||||
case 3:
|
||||
printf("bottom to top, right to left");
|
||||
return;
|
||||
case 4:
|
||||
printf("bottom to top, left to right");
|
||||
return;
|
||||
case 5:
|
||||
printf("left to right, top to bottom");
|
||||
return;
|
||||
case 6:
|
||||
printf("right to left, top to bottom");
|
||||
return;
|
||||
case 7:
|
||||
printf("right to left, bottom to top");
|
||||
return;
|
||||
case 8:
|
||||
printf("left to right, bottom to top");
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 284: // PlanarConfiguration
|
||||
if (entry.count == 1 && entry.fieldType == TIFF_SHORT) {
|
||||
if (entry.shortvals[0] == 1) {
|
||||
printf("Chunky (%d)", entry.shortvals[0]);
|
||||
return;
|
||||
}
|
||||
else if (entry.shortvals[0] == 2) {
|
||||
printf("Planar (%d)", entry.shortvals[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 296: // ResolutionUnit
|
||||
if (entry.count == 1 && entry.fieldType == TIFF_SHORT) {
|
||||
switch (entry.shortvals[0]) {
|
||||
case 1:
|
||||
printf("None (%d)", entry.shortvals[0]);
|
||||
return;
|
||||
case 2:
|
||||
printf("Inch (%d)", entry.shortvals[0]);
|
||||
return;
|
||||
case 3:
|
||||
printf("Cenimeter (%d)", entry.shortvals[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (entry.fieldType == TIFF_ASCII) {
|
||||
char ascfield[256] = { 0 };
|
||||
|
||||
if (entry.count <= 4)
|
||||
memcpy(ascfield, &entry.longval, entry.count);
|
||||
else if (entry.count > 4 && entry.count < 256) {
|
||||
ssize_t nread = file.ReadAt(entry.longval, ascfield, entry.count);
|
||||
if (nread != static_cast<ssize_t>(entry.count))
|
||||
ascfield[0] = '\0';
|
||||
}
|
||||
|
||||
if (ascfield[0] != '\0') {
|
||||
printf("%s", ascfield);
|
||||
return;
|
||||
}
|
||||
} else if (entry.fieldType == TIFF_RATIONAL && entry.count == 1) {
|
||||
struct { uint32 numerator; uint32 denominator; } rational;
|
||||
|
||||
ssize_t nread = file.ReadAt(entry.longval, &rational, 8);
|
||||
if (nread == 8 &&
|
||||
swap_data(B_UINT32_TYPE, &rational, 8, swp) == B_OK) {
|
||||
|
||||
printf("%d / %d",
|
||||
static_cast<unsigned int>(rational.numerator),
|
||||
static_cast<unsigned int>(rational.denominator));
|
||||
return;
|
||||
}
|
||||
} else if (entry.fieldType == TIFF_LONG && entry.count == 1) {
|
||||
printf("%d",
|
||||
static_cast<unsigned int>(entry.longval));
|
||||
return;
|
||||
} else if (entry.fieldType == TIFF_SHORT && entry.count <= 2) {
|
||||
for (uint32 i = 0; i < entry.count; i++) {
|
||||
if (i > 0)
|
||||
printf(", ");
|
||||
printf("%d", entry.shortvals[i]);
|
||||
}
|
||||
return;
|
||||
} else if (entry.fieldType == TIFF_BYTE && entry.count <= 4) {
|
||||
for (uint32 i = 0; i < entry.count; i++) {
|
||||
if (i > 0)
|
||||
printf(", ");
|
||||
printf("%d", entry.bytevals[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
printf("0x%.8lx", entry.longval);
|
||||
}
|
||||
|
||||
int swap_value_field(IFDEntry &entry, swap_action swp)
|
||||
{
|
||||
switch (entry.fieldType) {
|
||||
case TIFF_BYTE:
|
||||
case TIFF_ASCII:
|
||||
case TIFF_SBYTE:
|
||||
case TIFF_UNDEFINED:
|
||||
if (entry.count > 4) {
|
||||
if (swap_data(B_UINT32_TYPE, &entry.longval, 4, swp) != B_OK)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
case TIFF_LONG:
|
||||
case TIFF_RATIONAL:
|
||||
case TIFF_SRATIONAL:
|
||||
case TIFF_DOUBLE:
|
||||
if (swap_data(B_UINT32_TYPE, &entry.longval, 4, swp) != B_OK)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
case TIFF_FLOAT:
|
||||
if (swap_data(B_FLOAT_TYPE, &entry.floatval, 4, swp) != B_OK)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
case TIFF_SHORT:
|
||||
case TIFF_SSHORT:
|
||||
if (entry.count <= 2) {
|
||||
if (swap_data(B_UINT16_TYPE, &entry.shortvals,
|
||||
entry.count * 2, swp) != B_OK)
|
||||
return 0;
|
||||
} else {
|
||||
if (swap_data(B_UINT32_TYPE, &entry.longval, 4, swp) != B_OK)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// no error, but unknown type
|
||||
return 2;
|
||||
}
|
||||
|
||||
int
|
||||
report_ifd_entries(BFile &file, uint16 entrycount, swap_action swp)
|
||||
{
|
||||
IFDEntry entry;
|
||||
|
||||
if (sizeof(IFDEntry) != 12) {
|
||||
printf("IFDEntry size must be 12\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
off_t offset = file.Position();
|
||||
for (uint16 i = 0; i < entrycount; offset += 12, i++) {
|
||||
ssize_t nread = file.Read(&entry, 12);
|
||||
if (nread != 12) {
|
||||
printf("unable to read entire ifd entry\n");
|
||||
return 0;
|
||||
}
|
||||
if (swap_data(B_UINT16_TYPE, &entry.tag, 4, swp) != B_OK ||
|
||||
swap_data(B_UINT32_TYPE, &entry.count, 4, swp) != B_OK) {
|
||||
printf("swap_data failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!swap_value_field(entry, swp)) {
|
||||
printf("swap_value_field failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("\nOffset: 0x%.8lx\n", static_cast<unsigned long>(offset));
|
||||
printf( " Tag: %s (%d)\n", get_tag_string(entry.tag), entry.tag);
|
||||
printf( " Type: %s (%d)\n", get_type_string(entry.fieldType),
|
||||
entry.fieldType);
|
||||
printf( " Count: %d\n", static_cast<int>(entry.count));
|
||||
printf( " Value: ");
|
||||
print_ifd_value(entry, file, swp);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
report_ifd(BFile &file, uint32 ifdoffset, swap_action swp)
|
||||
{
|
||||
printf("\n<< BEGIN: IFD at 0x%.8lx >>\n\n", ifdoffset);
|
||||
|
||||
if (file.Seek(ifdoffset, SEEK_SET) != ifdoffset) {
|
||||
printf("failed to seek to IFD offset: %d\n",
|
||||
static_cast<unsigned int>(ifdoffset));
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16 entrycount = 0;
|
||||
ssize_t nread = file.Read(&entrycount, 2);
|
||||
if (nread != 2) {
|
||||
printf("unable to read entry count\n");
|
||||
return 0;
|
||||
}
|
||||
if (swap_data(B_UINT16_TYPE, &entrycount, sizeof(uint16), swp) != B_OK) {
|
||||
printf("failed to swap entrycount\n");
|
||||
return 0;
|
||||
}
|
||||
printf("Entry Count: %d\n", entrycount);
|
||||
|
||||
// Print out entries
|
||||
int ret = report_ifd_entries(file, entrycount, swp);
|
||||
|
||||
if (ret) {
|
||||
uint32 nextIFDOffset = 0;
|
||||
|
||||
nread = file.Read(&nextIFDOffset, 4);
|
||||
if (nread != 4) {
|
||||
printf("unable to read next IFD\n");
|
||||
return 0;
|
||||
}
|
||||
if (swap_data(B_UINT32_TYPE, &nextIFDOffset, sizeof(uint32), swp) != B_OK) {
|
||||
printf("failed to swap next IFD\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Next IFD Offset: 0x%.8lx\n", nextIFDOffset);
|
||||
printf("\n<< END: IFD at 0x%.8lx >>\n\n", ifdoffset);
|
||||
|
||||
if (nextIFDOffset != 0)
|
||||
return report_ifd(file, nextIFDOffset, swp);
|
||||
else
|
||||
return 1;
|
||||
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int generate_report(const char *filepath)
|
||||
{
|
||||
BFile file(filepath, B_READ_ONLY);
|
||||
|
||||
if (file.InitCheck() == B_OK) {
|
||||
|
||||
uint8 buffer[64];
|
||||
|
||||
// Byte Order
|
||||
const uint8 kleSig[] = { 0x49, 0x49, 0x2a, 0x00 };
|
||||
const uint8 kbeSig[] = { 0x4d, 0x4d, 0x00, 0x2a };
|
||||
|
||||
ssize_t nread = file.Read(buffer, 4);
|
||||
if (nread != 4) {
|
||||
printf("Unable to read first 4 bytes\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
swap_action swp;
|
||||
if (memcmp(buffer, kleSig, 4) == 0) {
|
||||
swp = B_SWAP_LENDIAN_TO_HOST;
|
||||
printf("Byte Order: little endian\n");
|
||||
|
||||
} else if (memcmp(buffer, kbeSig, 4) == 0) {
|
||||
swp = B_SWAP_BENDIAN_TO_HOST;
|
||||
printf("Byte Order: big endian\n");
|
||||
|
||||
} else {
|
||||
printf("Invalid byte order value\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Location of first IFD
|
||||
uint32 firstIFDOffset = 0;
|
||||
nread = file.Read(&firstIFDOffset, 4);
|
||||
if (nread != 4) {
|
||||
printf("Unable to read first IFD offset\n");
|
||||
return 0;
|
||||
}
|
||||
if (swap_data(B_UINT32_TYPE, &firstIFDOffset, sizeof(uint32), swp) != B_OK) {
|
||||
printf("swap_data() error\n");
|
||||
return 0;
|
||||
}
|
||||
printf("First IFD: 0x%.8lx\n", firstIFDOffset);
|
||||
|
||||
// print out first IFD
|
||||
report_ifd(file, firstIFDOffset, swp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("\n");
|
||||
// put a line break at the beginning of output
|
||||
// to improve readability
|
||||
|
||||
if (argc == 2) {
|
||||
|
||||
printf("TIFF Image: %s\n\n", argv[1]);
|
||||
generate_report(argv[1]);
|
||||
|
||||
} else {
|
||||
|
||||
printf("tiffinfo - reports information about a TIFF image\n");
|
||||
printf("\nUsage:\n");
|
||||
printf("tiffinfo filename.tif\n\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user