• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/processing/TIFF.cpp

00001 #include "string.h"
00002 #include <sstream>
00003 
00004 #include "TIFF.h"
00005 #include "../Debug.h"
00006 
00007 namespace FCam {
00008 
00009 //
00010 // Methods for TIFFFile::IfdEntry
00011 //
00012 
00013     TIFFFile::IfdEntry::IfdEntry(const TiffIfdEntry &entry, TIFFFile *parent):
00014         entry(entry), info(NULL), parent(parent), state(UNREAD), val()
00015     {
00016         info = tiffEntryLookup(entry.tag);
00017     }
00018 
00019     TIFFFile::IfdEntry::IfdEntry(uint16_t tag, const TagValue &val, TIFFFile *parent):
00020         entry(), info(NULL), parent(parent), state(INVALID), val(val)
00021     {
00022         entry.tag = tag;
00023         entry.count = 0;
00024         entry.offset = 0;
00025         info = tiffEntryLookup(tag);
00026         if (info) entry.type = info->type;
00027         setValue(val);
00028     }
00029 
00030     TIFFFile::IfdEntry::IfdEntry(uint16_t tag, TIFFFile *parent): entry(), info(NULL), parent(parent), state(INVALID), val() {
00031         entry.tag = tag;
00032     }
00033 
00034     bool TIFFFile::IfdEntry::valid() const {
00035         return state != INVALID;
00036     }
00037 
00038     uint16_t TIFFFile::IfdEntry::tag() const {
00039         return entry.tag;
00040     }
00041 
00042     const char* TIFFFile::IfdEntry::name() const {
00043         if (info == NULL) return "UnknownTag";
00044         else return info->name;
00045     }
00046 
00047     const TagValue& TIFFFile::IfdEntry::value() const {
00048         if (state == UNREAD) {
00049             val = parse();
00050             if (!val.valid()) state = INVALID;
00051         }
00052         return val;
00053     }
00054 
00055     bool TIFFFile::IfdEntry::setValue(const TagValue &newVal) {
00056         if (info == NULL) {
00057             switch(newVal.type) {
00058             case TagValue::Null:
00059                 warning(Event::FileSaveWarning, "IfdEntry: NULL value passed in for tag %d", tag() );
00060                 state = INVALID;
00061                 return false;
00062                 break;
00063             case TagValue::Int:
00064             case TagValue::IntVector:
00065                 entry.type = TIFF_SLONG;
00066                 break;
00067             case TagValue::Float:
00068             case TagValue::FloatVector:
00069                 entry.type = TIFF_FLOAT;
00070                 break;
00071             case TagValue::Double:
00072             case TagValue::DoubleVector:
00073                 entry.type = TIFF_DOUBLE;
00074                 break;
00075             case TagValue::String:
00076             case TagValue::StringVector:
00077                 entry.type = TIFF_ASCII;
00078                 break;
00079             case TagValue::Time:
00080             case TagValue::TimeVector:
00081                 warning(Event::FileSaveWarning, "IfdEntry: Can't store TagValue::Time values in TIFF tag %d", tag() );
00082                 state = INVALID;
00083                 val = TagValue();
00084                 return false;
00085                 break;
00086             }
00087         } else {
00088             bool typeMismatch = false;
00089             switch(newVal.type) {
00090             case TagValue::Null:
00091                 warning(Event::FileSaveWarning, "IfdEntry: NULL value passed in for tag %d", tag() );
00092                 state = INVALID;
00093                 return false;
00094                 break;
00095             case TagValue::Int:
00096             case TagValue::IntVector:
00097                 if (entry.type != TIFF_BYTE &&
00098                     entry.type != TIFF_SHORT &&
00099                     entry.type != TIFF_LONG &&
00100                     entry.type != TIFF_SBYTE &&
00101                     entry.type != TIFF_SSHORT &&
00102                     entry.type != TIFF_SLONG &&
00103                     entry.type != TIFF_IFD) {
00104                     typeMismatch= true;
00105                 }
00106                 break;
00107             case TagValue::Float:
00108             case TagValue::FloatVector:
00109                 if (entry.type != TIFF_FLOAT &&
00110                     entry.type != TIFF_DOUBLE) {
00111                     typeMismatch= true;
00112                 }
00113                 break;
00114             case TagValue::Double:
00115             case TagValue::DoubleVector:
00116                 if (entry.type != TIFF_DOUBLE &&
00117                     entry.type != TIFF_FLOAT &&
00118                     entry.type != TIFF_RATIONAL &&
00119                     entry.type != TIFF_SRATIONAL) {
00120                     typeMismatch= true;
00121                 }
00122                 break;
00123             case TagValue::String:
00124             case TagValue::StringVector:
00125                 if (entry.type != TIFF_ASCII &&
00126                     entry.type != TIFF_BYTE &&
00127                     entry.type != TIFF_SBYTE) {
00128                     typeMismatch= true;
00129                 }
00130                 break;
00131             case TagValue::Time:
00132             case TagValue::TimeVector:
00133                 typeMismatch = true;
00134                 break;
00135             }
00136             if (typeMismatch) {
00137                 warning(Event::FileSaveWarning, "IfdEntry: Trying to set tag %d (%s) of type %d to incompatible TagValue type %d",
00138                         tag(), name(), entry.type, newVal.type);
00139                 state = INVALID;
00140                 return false;
00141             }
00142         }
00143         val = newVal;
00144         state = WRITTEN;
00145         return true;
00146     }
00147 
00148     bool TIFFFile::IfdEntry::writeDataBlock(FILE *fw) {
00149         const TagValue &v = value();
00150         if (state == INVALID) {
00151             error(Event::FileSaveError,
00152                   "IfdEntry::writeDataBlock: Trying to write invalid tag %d (%s)",
00153                   tag(), name());
00154             return false;
00155         }
00156 
00157         unsigned int bytesPerElement=0;
00158         switch (entry.type) {
00159         case TIFF_BYTE:      bytesPerElement = 1; break;
00160         case TIFF_ASCII:     bytesPerElement = 1; break;
00161         case TIFF_SHORT:     bytesPerElement = 2; break;
00162         case TIFF_LONG:      bytesPerElement = 4; break;
00163         case TIFF_RATIONAL:  bytesPerElement = 8; break;
00164         case TIFF_SBYTE:     bytesPerElement = 1; break;
00165         case TIFF_UNDEFINED: bytesPerElement = 1; break;
00166         case TIFF_SSHORT:    bytesPerElement = 2; break;
00167         case TIFF_SLONG:     bytesPerElement = 4; break;
00168         case TIFF_SRATIONAL: bytesPerElement = 8; break;
00169         case TIFF_FLOAT:     bytesPerElement = 4; break;
00170         case TIFF_DOUBLE:    bytesPerElement = 8; break;
00171         case TIFF_IFD:       bytesPerElement = 4; break;
00172         }
00173         unsigned int elements = 0;
00174         switch (v.type) {
00175         case TagValue::Int:
00176         case TagValue::Float:
00177         case TagValue::Double:
00178             elements = 1;
00179             break;
00180         case TagValue::IntVector: {
00181             std::vector<int> &vi = v;
00182             elements = vi.size();
00183             break;
00184         }
00185         case TagValue::FloatVector: {
00186             std::vector<float> &vf = v;
00187             elements = vf.size();
00188             break;
00189         }
00190         case TagValue::DoubleVector: {
00191             std::vector<double> &vd = v;
00192             elements = vd.size();
00193             break;
00194         }
00195         case TagValue::String: {
00196             std::string &vs = v;
00197             if (entry.type == TIFF_ASCII) {
00198                 elements = vs.size() + 1; // Account for having to add a null termination
00199             } else {
00200                 elements = vs.size();
00201             }
00202             break;
00203         }
00204         case TagValue::StringVector: {
00205             std::vector<std::string> &strs = v;
00206             for (size_t i=0; i < strs.size(); i++) {
00207                 elements += strs[i].size()+1; // Account for having to add a null termination
00208             }
00209             break;
00210         }
00211         default:
00212             error(Event::FileSaveError, "IfdEntry::writeDataBlock: Unexpected TagValue type.");
00213             return false;
00214             break;
00215         }
00216 
00217         entry.count = elements;
00218 
00219         uint32_t dataBytes = bytesPerElement * elements;
00220 
00221         if (dataBytes <= 4) {
00222             // Just keep the data in the offset field
00223             switch(entry.type) {
00224             case TIFF_BYTE: {
00225                 uint8_t *off = (uint8_t *)&entry.offset;
00226                 if (v.type == TagValue::Int) {
00227                     uint8_t byte = (int)v;
00228                     *off = byte;
00229                 } else if (v.type == TagValue::IntVector) {
00230                     std::vector<int> &bytes = v;
00231                     for (size_t i=0; i < elements; i++) {
00232                         *off++ = bytes[i];
00233                     }
00234                 } else { // must be std::string
00235                     std::string &bytes = v;
00236                     for (size_t i=0; i < elements; i++) {
00237                         *off++ = bytes[i];
00238                     }
00239                 }
00240                 break;
00241             }
00242             case TIFF_ASCII: {
00243                 uint8_t *off = (uint8_t *)&entry.offset;
00244                 if (v.type == TagValue::String) {
00245                     std::string &ascii = v;
00246                     for (size_t i=0; i < ascii.size(); i++) {
00247                         *off++ = ascii[i];
00248                     }
00249                     *off = 0;
00250                 } else { // must be std::vector<std::string>
00251                     std::vector<std::string> &asciis = v;
00252                     for (size_t i=0; i < asciis.size(); i++) {
00253                         for (size_t j=0; j < asciis[i].size(); j++) {
00254                             *off++ = asciis[i][j];
00255                         }
00256                         *off++ = 0;
00257                     }
00258                 }
00259                 break;
00260             }
00261             case TIFF_SHORT: {
00262                 uint16_t *off = (uint16_t *)(void *)&entry.offset;
00263                 if (v.type == TagValue::Int) {
00264                     uint16_t vs = (int)v;
00265                     *off = vs;
00266                 } else { // must be int vector
00267                     std::vector<int> &shorts = v;
00268                     for (size_t i=0; i < elements; i++) {
00269                         *off++ = shorts[i];
00270                     }
00271                 }
00272                 break;
00273             }
00274             case TIFF_IFD:
00275             case TIFF_LONG: {
00276                 if (v.type == TagValue::Int) {
00277                     uint32_t vs = (int)v;
00278                     entry.offset = vs;
00279                 } else {
00280                     std::vector<int> &vi = v;
00281                     entry.offset = (uint32_t)vi[0];
00282                 }
00283                 break;
00284             }
00285             case TIFF_SBYTE:  {
00286                 int8_t *off = (int8_t *)&entry.offset;
00287                 if (v.type == TagValue::Int) {
00288                     int8_t byte = (int)v;
00289                     *off = byte;
00290                 } else if (v.type == TagValue::IntVector) {
00291                     std::vector<int> &bytes = v;
00292                     for (size_t i=0; i < elements; i++) {
00293                         *off++ = bytes[i];
00294                     }
00295                 } else { // must be std::string
00296                     std::string &bytes = v;
00297                     for (size_t i=0; i < elements; i++) {
00298                         *off++ = bytes[i];
00299                     }
00300                 }
00301                 break;
00302             }
00303             case TIFF_UNDEFINED: { // must be std::string
00304                 uint8_t *off = (uint8_t *)&entry.offset;
00305                 std::string &bytes = v;
00306                 for (size_t i=0; i < elements; i++) {
00307                     *off++ = bytes[i];
00308                 }
00309                 break;
00310             }
00311             case TIFF_SSHORT: { // v must be int or std::vector<int>
00312                 int16_t *off = (int16_t *)(void *)&entry.offset;
00313                 if (v.type == TagValue::Int) {
00314                     int16_t vs = (int)v;
00315                     *off = vs;
00316                 } else {
00317                     std::vector<int> &shorts = v;
00318                     for (size_t i=0; i < elements; i++) {
00319                         *off++ = shorts[i];
00320                     }
00321                 }
00322                 break;
00323             }
00324             case TIFF_SLONG: {
00325                 if (v.type == TagValue::Int) {
00326                     int32_t vs = (int)v;
00327                     entry.offset = vs;
00328                 } else { // must be int vector
00329                     std::vector<int> &vi = v;
00330                     entry.offset = vi[0];
00331                 }
00332                 break;
00333             }
00334             case TIFF_FLOAT: {
00335                 float *off = (float *)(void *)&entry.offset;
00336                 if (v.type == TagValue::Float) {
00337                     float vf = v;
00338                     *off = vf;
00339                 } else { // must be float vector
00340                     std::vector<float> &vf = v;
00341                     *off = vf[0];
00342                 }
00343                 break;
00344             }
00345             }
00346         } else {
00347 
00348             // Without this guard, v.toString() probably always gets evaluated
00349             // if DEBUG is defined.
00350             #if FCAM_DEBUG_LEVEL >= 6
00351             dprintf(6, "TIFFile::IfdEntry::writeDataBlock: Tag %d (%s) data: %s\n", entry.tag, name(), v.toString().substr(0,200).c_str());
00352             #else
00353             dprintf(5, "TIFFile::IfdEntry::writeDataBlock: Writing tag %d (%s) data block.\n", entry.tag, name());
00354             #endif
00355 
00356             // Entry data doesn't fit in the offset field
00357             // Need to write the data block to disk now
00358             entry.offset = ftell(fw);
00359             size_t written = 0;
00360             switch(entry.type) {
00361             case TIFF_BYTE: {
00362                 if (v.type == TagValue::IntVector) {
00363                     std::vector<int> &vi = v;
00364                     std::vector<uint8_t> bytes(vi.begin(), vi.end());
00365                     written = fwrite(&bytes[0], sizeof(uint8_t), elements, fw);
00366                 } else { // must be std::string
00367                     std::string &vs = v;
00368                     written = fwrite(vs.data(), sizeof(uint8_t), elements, fw);
00369                 }
00370                 break;
00371             }
00372             case TIFF_ASCII: {
00373                 if (v.type == TagValue::String) {
00374                     std::string &ascii = v;
00375                     written = fwrite(ascii.c_str(), sizeof(char), elements, fw);
00376                 } else { // must be std::vector<std::string>
00377                     std::vector<std::string> &asciis = v;
00378                     for (size_t i=0; i < asciis.size(); i++) {
00379                         written += fwrite(asciis[i].c_str(), sizeof(char), asciis[i].size()+1, fw);
00380                     }
00381                 }
00382                 break;
00383             }
00384             case TIFF_SHORT: { // v must be std::vector<int>
00385                 std::vector<int> &vi = v;
00386                 std::vector<uint16_t> shorts(vi.begin(), vi.end());
00387                 written = fwrite(&shorts[0], sizeof(uint16_t), shorts.size(), fw);
00388                 break;
00389             }
00390             case TIFF_IFD:
00391             case TIFF_LONG: { // v must be std::vector<int>
00392                 std::vector<int> &vi = v;
00393                 written = fwrite(&vi[0], sizeof(uint32_t), vi.size(), fw);
00394                 break;
00395             }
00396             case TIFF_SRATIONAL:
00397             case TIFF_RATIONAL: {
00398                 if (v.type == TagValue::Double) {
00399                     double vd = v;
00400                     if (entry.type == TIFF_RATIONAL && vd < 0 ) {
00401                         vd = 0;
00402                         warning(Event::FileSaveWarning, "IfdEntry: Entry value less than zero when writing a RATIONAL entry. Clamped to zero.");
00403                     }
00404                     // \todo Fix Rationals
00405                     int32_t num = vd * (1 << 20);
00406                     int32_t den = 1 << 20;
00407                     written = fwrite(&num, sizeof(int32_t), 1, fw);
00408                     written += fwrite(&den, sizeof(int32_t), 1, fw);
00409                     written /= 2;
00410                 } else {
00411                     std::vector<double> &vd = v;
00412                     written = 0;
00413                     for (size_t i=0; i < vd.size(); i++) {
00414                         if (entry.type == TIFF_RATIONAL && vd[i] < 0 ) {
00415                             vd[i] = 0;
00416                             warning(Event::FileSaveWarning, "IfdEntry: Entry value less than zero when writing a RATIONAL entry. Clamped to zero.");
00417                         }
00418                         int32_t num = vd[i] * (1 << 20);
00419                         int32_t den = 1 << 20;
00420                         written += fwrite(&num, sizeof(int32_t), 1, fw);
00421                         written += fwrite(&den, sizeof(int32_t), 1, fw);
00422                     }
00423                     written /= 2;
00424                 }
00425                 break;
00426             }
00427             case TIFF_SBYTE:  {
00428                 if (v.type == TagValue::IntVector) {
00429                     std::vector<int> &vi = v;
00430                     std::vector<int8_t> bytes(vi.begin(), vi.end());
00431                     written = fwrite(&bytes[0], sizeof(int8_t), elements, fw);
00432                 } else { // must be std::string
00433                     std::string &vs = v;
00434                     written = fwrite(vs.data(), sizeof(int8_t), elements, fw);
00435                 }
00436                 break;
00437             }
00438             case TIFF_UNDEFINED: { // must be std::string
00439                 std::string &vs = v;
00440                 written = fwrite(vs.data(), sizeof(int8_t), elements, fw);
00441                 break;
00442             }
00443             case TIFF_SSHORT: { // v must be std::vector<int>
00444                 std::vector<int> &vi = v;
00445                 std::vector<int16_t> shorts(vi.begin(), vi.end());
00446                 written = fwrite(&shorts[0], sizeof(int16_t), elements, fw);
00447                 break;
00448             }
00449             case TIFF_SLONG: { // v must be int vector
00450                 std::vector<int> &vi = v;
00451                 written = fwrite(&vi[0], sizeof(uint32_t), elements, fw);
00452                 break;
00453             }
00454             case TIFF_FLOAT: { // v must be a float vector
00455                 std::vector<float> &vf = v;
00456                 written = fwrite(&vf[0], sizeof(float), elements, fw);
00457                 break;
00458             }
00459             case TIFF_DOUBLE: {
00460                 if (elements == 1) {
00461                     double vd = v;
00462                     written = fwrite(&vd, sizeof(double), elements, fw);
00463                 } else {
00464                     std::vector<double> &vd = v;
00465                     written = fwrite(&vd[0], sizeof(double), elements, fw);
00466                 }
00467                 break;
00468             }
00469             }
00470             if (written != elements) {
00471                 error(Event::FileSaveError, "TIFFFile::IfdEntry::writeDataBlock: Can't write data to file (tried to write %d, only wrote %d)", elements, written);
00472                 return false;
00473             }
00474         }
00475 
00476         return true;
00477     }
00478 
00479     bool TIFFFile::IfdEntry::write(FILE *fw) {
00480         dprintf(5, "TIFFile::IfdEntry::write: Writing tag entry %d (%s): %d %d %d\n", tag(), name(), entry.type, entry.count, entry.offset);
00481         int count;
00482         count = fwrite(&entry.tag, sizeof(entry.tag), 1, fw);
00483         if (count == 1) fwrite(&entry.type, sizeof(entry.type), 1, fw);
00484         if (count == 1) fwrite(&entry.count, sizeof(entry.count), 1, fw);
00485         if (count == 1) fwrite(&entry.offset, sizeof(entry.offset), 1, fw);
00486 
00487         if (count != 1) {
00488             error(Event::FileSaveError, "TIFFile::IfdEntry::write: Can't write IFD entry to file.");
00489             return false;
00490         }
00491         return true;
00492 
00493     }
00494 
00495     bool TIFFFile::IfdEntry::operator<(const IfdEntry &other) const {
00496         return tag() < other.tag();
00497     }
00498 
00499     TagValue TIFFFile::IfdEntry::parse() const {
00500         TagValue tag;
00501 
00502         if (info != NULL) {
00503             // Known tag, check for type mismatches
00504             bool typeMismatch=false;
00505             switch(info->type) {
00506             case TIFF_BYTE:
00507             case TIFF_SHORT:
00508             case TIFF_LONG:
00509                 // Accept any unsigned integer type in any other's place
00510                 if (entry.type != TIFF_BYTE &&
00511                     entry.type != TIFF_SHORT &&
00512                     entry.type != TIFF_LONG)
00513                     typeMismatch = true;
00514                 break;
00515             case TIFF_SBYTE:
00516             case TIFF_SSHORT:
00517             case TIFF_SLONG:
00518                 // Accept any signed integer type in any other's place
00519                 if (entry.type != TIFF_SBYTE &&
00520                     entry.type != TIFF_SSHORT &&
00521                     entry.type != TIFF_SLONG)
00522                     typeMismatch = true;
00523                 break;
00524             case TIFF_ASCII:
00525             case TIFF_RATIONAL:
00526             case TIFF_UNDEFINED:
00527             case TIFF_SRATIONAL:
00528             case TIFF_FLOAT:
00529             case TIFF_DOUBLE:
00530                 // Strict matching for these types
00531                 if (entry.type != info->type) typeMismatch = true;
00532                 break;
00533             case TIFF_IFD:
00534                 // Can also be LONG
00535                 if (entry.type != TIFF_LONG &&
00536                     entry.type != TIFF_IFD) typeMismatch = true;
00537                 break;
00538             }
00539             if (typeMismatch) {
00540                 warning(Event::FileLoadWarning,
00541                         "In %s, type mismatch reading TIFF tag %d (%s), expected type %d, got %d\n",
00542                         parent->filename.c_str(), entry.tag, info->name, info->type, entry.type);
00543                 return tag;
00544             }
00545         }
00546         // Now sort out how much data we're looking at
00547         unsigned int bytesPerElement=0;
00548         switch (entry.type) {
00549         case TIFF_BYTE:      bytesPerElement = 1; break;
00550         case TIFF_ASCII:     bytesPerElement = 1; break;
00551         case TIFF_SHORT:     bytesPerElement = 2; break;
00552         case TIFF_LONG:      bytesPerElement = 4; break;
00553         case TIFF_RATIONAL:  bytesPerElement = 8; break;
00554         case TIFF_SBYTE:     bytesPerElement = 1; break;
00555         case TIFF_UNDEFINED: bytesPerElement = 1; break;
00556         case TIFF_SSHORT:    bytesPerElement = 2; break;
00557         case TIFF_SLONG:     bytesPerElement = 4; break;
00558         case TIFF_SRATIONAL: bytesPerElement = 8; break;
00559         case TIFF_FLOAT:     bytesPerElement = 4; break;
00560         case TIFF_DOUBLE:    bytesPerElement = 8; break;
00561         case TIFF_IFD:       bytesPerElement = 4; break;
00562         }
00563         unsigned int totalBytes = entry.count*bytesPerElement;
00564         std::vector<uint8_t> data(totalBytes);
00565 
00566         // Read in the data, possibly seeking if needed
00567         if (entry.count > 4/bytesPerElement) {
00568             // Data doesn't fit in entry.offset field, go fetch it
00569             int adjOffset = parent->convLong(&entry.offset);
00570             bool success = parent->readByteArray(adjOffset, totalBytes,  &data[0]);
00571             if (!success) {
00572                 warning(Event::FileLoadWarning,
00573                         "In %s, unable to read TIFF tag %d (%s) data at offset 0x%x\n",
00574                         parent->filename.c_str(), entry.tag, name(), entry.offset);
00575                 return tag;
00576             }
00577         } else {
00578             uint8_t *ptr = (uint8_t*)&entry.offset;
00579             for (size_t i=0; i < data.size(); i++) {
00580                 data[i] = *(ptr++);
00581             }
00582         }
00583         // Got undifferentiated byte soup, now interpret it and swap endianness as needed
00584         switch (entry.type) {
00585         case TIFF_BYTE:
00586         case TIFF_SBYTE:
00587         case TIFF_UNDEFINED:
00588             tag = std::string(data.begin(), data.end());
00589             break;
00590         case TIFF_ASCII: {
00591             // A TIFF ASCII field can contain multiple strings separated by null characters
00592             std::vector<std::string> strings;
00593             std::vector<uint8_t>::iterator start = data.begin();
00594             for (std::vector<uint8_t>::iterator it=data.begin(); it < data.end(); it++) {
00595                 if (*it == 0) {
00596                     strings.push_back(std::string(start, it));
00597                     start = it + 1;
00598                 }
00599             }
00600             if (strings.size() > 1) {
00601                 tag = strings;
00602             } else {
00603                 tag = strings[0];
00604             }
00605             break;
00606         }
00607         case TIFF_SHORT:
00608             if (entry.count > 1) {
00609                 std::vector<int> vals(entry.count);
00610                 uint8_t *ptr = &data[0];
00611                 for (size_t i=0; i < entry.count; i++) {
00612                     vals[i] = parent->convShort(ptr);
00613                     ptr+=bytesPerElement;
00614                 }
00615                 tag = vals;
00616             } else {
00617                 tag = parent->convShort(&data[0]);
00618             }
00619             break;
00620         case TIFF_IFD:
00621         case TIFF_LONG:
00622             // TagValues are signed, so possible reinterpretation problem here.
00623             if (entry.count > 1) {
00624                 std::vector<int> vals(entry.count);
00625                 uint8_t *ptr = &data[0];
00626                 for (size_t i=0; i < entry.count; i++) {
00627                     vals[i] = (int)parent->convLong(ptr);
00628                     ptr+=bytesPerElement;
00629                 }
00630                 tag = vals;
00631             } else {
00632                 tag = (int)parent->convLong(&data[0]);
00633             }
00634             break;
00635         case TIFF_RATIONAL:
00636             if (entry.count > 1) {
00637                 std::vector<double> vals(entry.count);
00638                 uint8_t *ptr = &data[0];
00639                 for (size_t i=0; i < entry.count; i++) {
00640                     TIFFRational r = parent->convRational(ptr);
00641                     // Precision loss here
00642                     vals[i] = ((double)r.numerator)/((double)r.denominator);
00643                     ptr+=bytesPerElement;
00644                 }
00645                 tag = vals;
00646             } else {
00647                 TIFFRational r = parent->convRational(&data[0]);
00648                 tag = ((double)r.numerator)/((double)r.denominator);
00649             }
00650             break;
00651         case TIFF_SSHORT:
00652             if (entry.count > 1) {
00653                 std::vector<int> vals(entry.count);
00654                 uint8_t *ptr = &data[0];
00655                 for (size_t i=0; i < entry.count; i++) {
00656                     uint16_t val = parent->convShort(ptr);
00657                     vals[i] = *reinterpret_cast<int16_t *>(&val);
00658                     ptr+=bytesPerElement;
00659                 }
00660                 tag = vals;
00661             } else {
00662                 uint16_t val = parent->convShort(&data[0]);
00663                 tag = *reinterpret_cast<int16_t *>(&val);
00664             }
00665             break;
00666 
00667         case TIFF_SLONG:
00668             if (entry.count > 1) {
00669                 std::vector<int> vals(entry.count);
00670                 uint8_t *ptr = &data[0];
00671                 for (size_t i=0; i < entry.count; i++) {
00672                     uint32_t val = parent->convLong(ptr);
00673                     vals[i] = *reinterpret_cast<int32_t *>(&val);
00674                     ptr+=bytesPerElement;
00675                 }
00676                 tag = vals;
00677             } else {
00678                 uint32_t val = parent->convLong(&data[0]);
00679                 tag = *reinterpret_cast<int32_t *>(&val);
00680             }
00681             break;
00682         case TIFF_SRATIONAL:
00683             if (entry.count > 1) {
00684                 std::vector<double> vals(entry.count);
00685                 uint8_t *ptr = &data[0];
00686                 for (size_t i=0; i < entry.count; i++) {
00687                     TIFFRational r = parent->convRational(ptr);
00688                     // Precision loss here
00689                     vals[i] = (static_cast<double>(*reinterpret_cast<int32_t *>(&r.numerator)))
00690                         /(static_cast<double>(*reinterpret_cast<int32_t *>(&r.denominator)));
00691                     ptr+=bytesPerElement;
00692                 }
00693                 tag = vals;
00694             } else {
00695                 TIFFRational r = parent->convRational(&data[0]);
00696                 tag = (static_cast<double>(*reinterpret_cast<int32_t *>(&r.numerator)))
00697                         /(static_cast<double>(*reinterpret_cast<int32_t *>(&r.denominator)));
00698             }
00699             break;
00700         case TIFF_FLOAT:
00701             if (entry.count > 1) {
00702                 std::vector<float> vals(entry.count);
00703                 uint8_t *ptr = &data[0];
00704                 for (size_t i=0; i < entry.count; i++) {
00705                     vals[i] = parent->convFloat(ptr);
00706                     ptr+=bytesPerElement;
00707                 }
00708                 tag = vals;
00709             } else {
00710                 tag = parent->convFloat(&data[0]);
00711             }
00712             break;
00713         case TIFF_DOUBLE:
00714             if (entry.count > 1) {
00715                 std::vector<double> vals(entry.count);
00716                 uint8_t *ptr = &data[0];
00717                 for (size_t i=0; i < entry.count; i++) {
00718                     vals[i] = parent->convDouble(ptr);
00719                     ptr+=bytesPerElement;
00720                 }
00721                 tag = vals;
00722             } else {
00723                 tag = parent->convDouble(&data[0]);
00724             }
00725             break;
00726         };
00727 
00728         state = READ;
00729 
00730         return tag;
00731     }
00732 
00733 //
00734 // Methods for TIFFFile::Ifd
00735 //
00736 
00737     TIFFFile::Ifd::Ifd(TIFFFile *parent): parent(parent), imgState(UNREAD) {
00738     }
00739 
00740     TIFFFile::Ifd::~Ifd() {
00741         eraseSubIfds();
00742     }
00743 
00744     const TIFFFile::IfdEntry* TIFFFile::Ifd::find(uint16_t tag) const {
00745         entryMap::const_iterator match;
00746         match=entries.find(tag);
00747         if (match == entries.end()) return NULL;
00748         else return &(match->second);
00749     }
00750 
00751     TIFFFile::IfdEntry* TIFFFile::Ifd::find(uint16_t tag) {
00752         entryMap::iterator match;
00753         match=entries.find(tag);
00754         if (match == entries.end()) return NULL;
00755         else return &(match->second);
00756     }
00757 
00758     bool TIFFFile::Ifd::add(const TiffIfdEntry &rawEntry) {
00759         IfdEntry entry(rawEntry, parent);
00760 
00761         entries.insert(entries.end(), entryMap::value_type(rawEntry.tag, entry));
00762         return true;
00763     }
00764 
00765     bool TIFFFile::Ifd::add(uint16_t tag, const TagValue &val) {
00766         IfdEntry entry(tag, val, parent);
00767         if (!entry.valid()) return false;
00768         IfdEntry *existingEntry = find(tag);
00769         if (existingEntry) existingEntry->setValue(val);
00770         else {
00771             entries.insert(entryMap::value_type(tag, entry));
00772         }
00773         return true;
00774     }
00775 
00776     bool TIFFFile::Ifd::add(const std::string &tagName, const TagValue &val) {
00777         const TiffEntryInfo *info = tiffEntryLookup(tagName);
00778         if (info) {
00779             return add(info->tag, val);
00780         }
00781         return false;
00782     }
00783 
00784     TIFFFile::Ifd* TIFFFile::Ifd::addSubIfd() {
00785         Ifd *ifd = new Ifd(parent);
00786         _subIfds.push_back(ifd);
00787         return ifd;
00788     }
00789 
00790     void TIFFFile::Ifd::eraseSubIfds() {
00791         for (size_t i=0; i < _subIfds.size(); i++) {
00792             delete _subIfds[i];
00793         }
00794         _subIfds.clear();
00795     }
00796 
00797     const std::vector<TIFFFile::Ifd *>& TIFFFile::Ifd::subIfds() {
00798         return _subIfds;
00799     }
00800 
00801     TIFFFile::Ifd* TIFFFile::Ifd::subIfds(int index) {
00802         return _subIfds[index];
00803     }
00804 
00805     Image TIFFFile::Ifd::getImage() {
00806         if (imgState == NONE || imgState == CACHED) return imgCache;
00807 
00808         const IfdEntry *entry;
00809 
00810         const char *file = parent->filename.c_str();
00811 
00812         entry = find(TIFF_TAG_PhotometricInterpretation);
00813         if (!entry) {
00814             imgState = NONE;
00815             return imgCache;
00816         }
00817         int photometricInterpretation = entry->value();
00818 
00819 #define fatalError(...) \
00820         do { \
00821             warning(Event::FileLoadError, __VA_ARGS__);        \
00822             imgState = NONE; \
00823             return imgCache; \
00824         } while(0);
00825 
00826         ImageFormat fmt = UNKNOWN;
00827         switch (photometricInterpretation) {
00828         case TIFF_PhotometricInterpretation_WhiteIsZero:
00829         case TIFF_PhotometricInterpretation_BlackIsZero:
00830         case TIFF_PhotometricInterpretation_PaletteRGB:
00831         case TIFF_PhotometricInterpretation_TransparencyMask:
00832         case TIFF_PhotometricInterpretation_CMYK:
00833         case TIFF_PhotometricInterpretation_CIELAB:
00834         case TIFF_PhotometricInterpretation_ICCLAB:
00835         case TIFF_PhotometricInterpretation_ITULAB:
00836         case TIFF_PhotometricInterpretation_YCbCr:
00837             // Deal with unsupported formats first
00838             fatalError("Ifd::getImage(): %s: Unsupported pixel format (PhotometricInterpretation) %d.",
00839                        file,
00840                        photometricInterpretation);
00841             break;
00842         case TIFF_PhotometricInterpretation_RGB:
00843             fmt = RGB24;
00844             break;
00845         case TIFF_PhotometricInterpretation_LinearRaw:
00846             fatalError("Ifd::getImage(): %s: Linear RAW is not supported.",
00847                        file);
00848             break;
00849         case TIFF_PhotometricInterpretation_CFA:
00850             fmt = RAW;
00851             break;
00852 
00853         }
00854 
00855         int compression = TIFF_Compression_DEFAULT;
00856         entry = find(TIFF_TAG_Compression);
00857         if (entry) compression = entry->value();
00858 
00859         switch (compression) {
00860         case TIFF_Compression_Uncompressed:
00861             // ok
00862             break;
00863         default:
00864             fatalError("Ifd::getImage(): %s: Unsupported compression type %d.",
00865                        file,
00866                        compression);
00867             break;
00868         }
00869 
00870         // Now assuming uncompressed RAW or RGB24
00871         int samplesPerPixel = TIFF_SamplesPerPixel_DEFAULT;
00872         entry = find(TIFF_TAG_SamplesPerPixel);
00873         if (entry) samplesPerPixel = entry->value();
00874         switch (fmt) {
00875         case RAW:
00876             if (samplesPerPixel != 1) {
00877                 fatalError("Ifd::getImage(): %s: RAW images cannot have more than 1 sample per pixel.",
00878                            file);
00879             } 
00880             break;
00881         case RGB24:
00882             if (samplesPerPixel != 3) {
00883                 fatalError("Ifd::getImage(): %s: RGB24 images must have 3 samples per pixel", file);
00884             }
00885             break;               
00886         default: // shouldn't be here
00887             fatalError("Ifd::getImage(): %s: Unexpected branch in the road", file);
00888             break;
00889         }
00890 
00891         entry = find(TIFF_TAG_BitsPerSample);
00892         if (!entry) fatalError("Ifd::getImage(): %s: No BitsPerSample entry found.", file);
00893 
00894         switch (fmt) {
00895         case RAW: {
00896             int bitsPerSample = entry->value();
00897             if (bitsPerSample != 16) fatalError("Ifd::getImage(): %s: Only 16-bpp RAW images supported.", file);
00898             break;
00899         }
00900         case RGB24: {
00901             std::vector<int> bitsPerSample = entry->value();
00902             if (bitsPerSample[0] != 8 ||
00903                 bitsPerSample[1] != 8||
00904                 bitsPerSample[2] != 8) fatalError("Ifd::getImage(): %s: Only 24-bpp RGB images supported.", file);
00905             break;
00906         }
00907         default: // shouldn't be here
00908             fatalError("Ifd::getImage(): %s: Unexpected branch in the road", file);
00909             break;
00910         }
00911 
00912         entry = find(TIFF_TAG_Orientation);
00913         if (!entry) fatalError("Ifd::getImage(): %s: No orientation entry found, required for RAW.", file);
00914         int orientation = entry->value();
00915 
00916         if (orientation != 1) fatalError("Ifd::getImage(): %s: Unsupported orientation value %d", file, orientation);
00917 
00918         // Read in image dimensions
00919         entry = find(TIFF_TAG_ImageWidth);
00920         if (!entry) fatalError("Ifd::getImage(): %s: No ImageWidth entry found.", file);
00921         int imageWidth = entry->value();
00922 
00923         entry = find(TIFF_TAG_ImageLength);
00924         if (!entry) fatalError("Ifd::getImage(): %s: No ImageLength entry found.", file);
00925         int imageLength = entry->value();
00926 
00927         dprintf(4,"Ifd::getImage(): %s: Image size is %d x %d\n", file, imageWidth, imageLength);
00928 
00929         // Read in image strip information
00930         entry = find(TIFF_TAG_RowsPerStrip);
00931         int rowsPerStrip = TIFF_RowsPerStrip_DEFAULT;
00932         uint32_t stripsPerImage = 1;
00933         if (entry) {
00934             rowsPerStrip = entry->value();
00935             stripsPerImage = imageLength / rowsPerStrip; // Full strips
00936             if (imageLength % rowsPerStrip != 0) stripsPerImage++; // Final partial strip
00937         }
00938 
00939         entry = find(TIFF_TAG_StripOffsets);
00940         if (!entry) fatalError("Ifd::getImage(): %s: No image strip data found, and tiled data is not supported.", file);
00941         std::vector<int> stripOffsets = entry->value();
00942         if (stripOffsets.size() != stripsPerImage)
00943             fatalError("Ifd::getImage(): %s: Malformed IFD - conflicting values on number of image strips.", file);
00944 
00945         dprintf(5, "Ifd::getImage(): %s: Image data in %d strips of %d rows each.\n", file, stripsPerImage, rowsPerStrip);
00946 
00947         //
00948         // Read in image data
00949         Image img(imageWidth, imageLength, fmt);
00950 
00951         uint32_t bytesPerStrip = rowsPerStrip * imageWidth * img.bytesPerPixel();
00952         uint32_t bytesLeft = imageLength * imageWidth * img.bytesPerPixel();
00953         for (uint32_t strip=0; strip < stripsPerImage; strip++) {
00954             uint32_t bytesToRead = std::min(bytesLeft, bytesPerStrip);
00955             bool success = parent->readByteArray(stripOffsets[strip], bytesToRead, img(0,rowsPerStrip*strip) );
00956             if (!success) {
00957                 fatalError("Ifd::getImage(): %s: Cannot read in all image data.\n", file);
00958             }
00959             bytesLeft -= bytesToRead;
00960         }
00961 
00962 #undef fatalError
00963 
00964         imgCache = img;
00965         imgState = CACHED;
00966         return imgCache;
00967     }
00968 
00969     bool TIFFFile::Ifd::setImage(Image newImg) {
00970         if (newImg.type() != RAW &&
00971             newImg.type() != RGB24) {
00972             error(Event::FileSaveError, "Ifd::setImage(): Can only save RAW or RGB24 images");
00973             return false;
00974         }
00975         imgCache = newImg;
00976         imgState = CACHED;
00977         return true;
00978     }
00979 
00980     bool TIFFFile::Ifd::write(FILE *fw, uint32_t nextIfdOffset, uint32_t *offset) {
00981         bool success;
00982         // First write out all subIFDs, if any
00983         if (_subIfds.size() > 0) {
00984             std::vector<int> subIfdOffsets;
00985             // Write all subIfd data first
00986             for (size_t i=0; i < _subIfds.size(); i++ ) {
00987                 uint32_t subIfdOffset;
00988                 dprintf(4, "TIFFile::Ifd::write: Writing subIFD %d\n", i);
00989                 success = _subIfds[i]->write(fw, 0, &subIfdOffset);
00990                 if (!success) return false;
00991                 subIfdOffsets.push_back(subIfdOffset);
00992             }
00993             // Then update our subIfd offset entry with returned locations
00994             IfdEntry *subIfdEntry = find(TIFF_TAG_SubIFDs);
00995             if (subIfdEntry != NULL) {
00996                 success = subIfdEntry->setValue(TagValue(subIfdOffsets));
00997             } else {
00998                 success = add(TIFF_TAG_SubIFDs, TagValue(subIfdOffsets));
00999             }
01000             if (!success) return false;
01001         }
01002         // Then write out the image, if any
01003         success = writeImage(fw);
01004         if (!success) return false;
01005 
01006         // Then write out entry extra data fields
01007         dprintf(5, "TIFFile::Ifd::write: Writing Ifd entry data blocks.\n");
01008 
01009         for (entryMap::iterator it=entries.begin(); it != entries.end(); it++) {
01010             success = it->second.writeDataBlock(fw);
01011             if (!success) return false;
01012         }
01013 
01014         // Record starting offset for IFD
01015         *offset = ftell(fw);
01016         // Now write out the IFD itself
01017         int count;
01018         uint16_t entryCount = entries.size();
01019         count = fwrite(&entryCount, sizeof(uint16_t), 1, fw);
01020         if (count != 1) return false;
01021 
01022         dprintf(5, "TIFFile::Ifd::write: Writing IFD entries\n");
01023         for (entryMap::iterator it=entries.begin(); it != entries.end(); it++) {
01024             success = it->second.write(fw);
01025             if (!success) return false;
01026         }
01027         count = fwrite(&nextIfdOffset, sizeof(uint32_t), 1, fw);
01028         if (count != 1) return false;
01029 
01030         dprintf(5, "TIFFile::Ifd::write: IFD written\n");
01031         return true;
01032     }
01033 
01034     bool TIFFFile::Ifd::writeImage(FILE *fw) {
01035         Image img = getImage();
01036         if (imgState == NONE) return true;
01037         dprintf(5, "TIFFile::Ifd::writeImage: Beginning image write\n");
01038         if (!img.valid()) {
01039             error(Event::FileSaveError, "TIFFFile::Ifd::writeImage: Invalid image");
01040             return false;
01041         }
01042 
01043         int photometricInterpretation = 0;
01044         int samplesPerPixel = 0;
01045         std::vector<int> bitsPerSample;
01046         switch (img.type()) {
01047         case RGB24:
01048             photometricInterpretation = TIFF_PhotometricInterpretation_RGB;
01049             samplesPerPixel = 3;
01050             bitsPerSample = std::vector<int>(3,8);
01051             break;
01052         case RGB16:
01053             photometricInterpretation = TIFF_PhotometricInterpretation_RGB;
01054             samplesPerPixel = 3;
01055             bitsPerSample.push_back(5);
01056             bitsPerSample.push_back(6);
01057             bitsPerSample.push_back(5);
01058             break;
01059         case UYVY:
01060         case YUV24:
01061             error(Event::FileSaveError, "TIFFFile::Ifd::writeImage: UYVY/YUV images not supported yet.\n");
01062             return false;
01063             break;
01064         case RAW:
01065             photometricInterpretation = TIFF_PhotometricInterpretation_CFA;
01066             samplesPerPixel = 1;
01067             bitsPerSample.push_back(16);
01068             break;
01069         case UNKNOWN:
01070             error(Event::FileSaveError,
01071                   "TIFFFile::Ifd::writeImage: Can't save UNKNOWN images.");
01072             return false;
01073             break;
01074         }
01075 
01076         int width = img.width();
01077         int height = img.height();
01078 
01079         const uint32_t targetBytesPerStrip = 64 * 1024; // 64 K strips if possible
01080         const uint32_t minRowsPerStrip = 10; // But at least 10 rows per strip
01081 
01082         uint32_t bytesPerRow = img.bytesPerPixel() * width;
01083         int rowsPerStrip;
01084         if (minRowsPerStrip*bytesPerRow > targetBytesPerStrip) {
01085             rowsPerStrip = minRowsPerStrip;
01086         } else {
01087             rowsPerStrip = targetBytesPerStrip / bytesPerRow;
01088         }
01089         uint32_t stripsPerImage = height / rowsPerStrip;
01090         if (height % rowsPerStrip != 0) stripsPerImage++;
01091 
01092         std::vector<int> stripOffsets;
01093         std::vector<int> stripByteCounts;
01094 
01095         for (int ys=0; ys < height; ys += rowsPerStrip) {
01096             size_t lastRow = std::min(height, ys + rowsPerStrip);
01097             int bytesToWrite = (lastRow - ys) * bytesPerRow;
01098 
01099             stripOffsets.push_back(ftell(fw));
01100             stripByteCounts.push_back(bytesToWrite);
01101 
01102             int bytesWritten = 0;
01103             for (size_t y=ys; y < lastRow; y++) {
01104                 bytesWritten += fwrite(img(0,y), sizeof(uint8_t), bytesPerRow, fw);
01105             }
01106             if (bytesWritten != bytesToWrite) {
01107                 error(Event::FileSaveError, "TIFFFile::Ifd::writeImage: Unable to write image data to file (wanted to write %d bytes, able to write %d).", bytesToWrite, bytesWritten);
01108                 return false;
01109             }
01110         }
01111 
01112         bool success;
01113         success = add(TIFF_TAG_PhotometricInterpretation, photometricInterpretation);
01114         if (success) success = add(TIFF_TAG_SamplesPerPixel, samplesPerPixel);
01115         if (success) success = add(TIFF_TAG_BitsPerSample, bitsPerSample);
01116 
01117         if (success) success = add(TIFF_TAG_ImageWidth, width);
01118         if (success) success = add(TIFF_TAG_ImageLength, height);
01119         if (success) success = add(TIFF_TAG_RowsPerStrip, rowsPerStrip);
01120 
01121         if (success) success = add(TIFF_TAG_StripOffsets, stripOffsets);
01122         if (success) success = add(TIFF_TAG_StripByteCounts, stripByteCounts);
01123         if (success) success = add(TIFF_TAG_Orientation, TIFF_Orientation_TopLeft);
01124 
01125         if (!success) {
01126             error(Event::FileSaveError,
01127                   "TIFFFile::Ifd::writeImage: Can't add needed tags to IFD");
01128             return false;
01129         }
01130 
01131         dprintf(5, "TIFFile::Ifd::writeImage: Image written.\n");
01132         return true;
01133     }
01134 //
01135 // Methods for TIFFFile
01136 //
01137 
01138     TIFFFile::TIFFFile(): valid(false), fp(NULL), offsetToIfd0(0) {
01139     }
01140 
01141     TIFFFile::TIFFFile(const std::string &file): valid(false), fp(NULL), offsetToIfd0(0) {
01142         readFrom(file);
01143     }
01144 
01145     TIFFFile::~TIFFFile() {
01146         eraseIfds();
01147         if (fp) fclose(fp);
01148     }
01149 
01150     bool TIFFFile::readFrom(const std::string &file) {
01151         dprintf(DBG_MINOR, "TIFFFile::readFrom(): Starting read of %s\n", file.c_str());
01152 
01153         // Make sure we start with a blank slate here
01154         if (fp) {
01155             fclose(fp); fp = NULL;
01156         }
01157         eraseIfds();
01158 
01159         valid = false;
01160 
01161         // Try to open the file
01162         fp = fopen(file.c_str(), "rb");
01163         filename = file;
01164         if (fp == NULL) {
01165             std::stringstream errMsg;
01166             errMsg << "Unable to open file: "<<strerror(errno);
01167             setError("readFrom", errMsg.str());
01168             return false;
01169         }
01170 
01171         // Read in TIFF directories
01172 
01173         bool success = readHeader();
01174         if (!success) return false;
01175 
01176         uint32_t nextIfdOffset = offsetToIfd0;
01177         while (nextIfdOffset != 0) {
01178             Ifd *ifd = new Ifd(this);
01179             success = readIfd(nextIfdOffset, ifd, &nextIfdOffset);
01180             if (!success) {
01181                 delete ifd;
01182                 return false;
01183             }
01184             _ifds.push_back(ifd);
01185         }
01186 
01187         valid = true;
01188         return true;
01189     }
01190 
01191     bool TIFFFile::writeTo(const std::string &file) {
01192         dprintf(4, "TIFFile::writeTo: %s: Beginning write\n", file.c_str());
01193         // Check that we have enough of an image to write
01194         if (ifds().size() == 0) {
01195             error(Event::FileSaveError,
01196                   "TIFFFile::writeTo: %s: Nothing to write",
01197                   file.c_str());
01198             return false;
01199         }
01200         FILE *fw = NULL;
01201         fw = fopen(file.c_str(), "wb");
01202         if (!fw) {
01203             error(Event::FileSaveError,
01204                   "TIFFFile::writeTo: %s: Can't open file for writing",
01205                   file.c_str());
01206             return false;
01207         }
01208 
01209         // Write out TIFF header
01210         int count = 0;
01211         uint32_t headerOffset = 0;
01212         count = fwrite(&littleEndianMarker, sizeof(littleEndianMarker), 1, fw);
01213         if (count == 1)
01214             count = fwrite(&tiffMagicNumber, sizeof(tiffMagicNumber), 1 , fw);
01215         // Write a dummy value for IFD0 offset for now. Will come back later, so store offset
01216         uint32_t headerIfd0Offset = ftell(fw);
01217         if (count == 1)
01218             count = fwrite(&headerOffset, sizeof(headerOffset), 1, fw);
01219         if (count != 1) {
01220             error(Event::FileSaveError,
01221                   "TIFFFile::writeTo: %s: Can't write TIFF file header",
01222                   file.c_str());
01223             fclose(fw);
01224             return false;
01225         }
01226 
01227         // Write out all the IFDs, reverse order to minimize fseeks
01228         bool success;
01229         uint32_t nextIfdOffset = 0;
01230         for (size_t i=ifds().size(); i > 0; i--) {
01231             dprintf(4, "TIFFile::writeTo: %s: Writing IFD %d\n", file.c_str(), i-1);
01232             success = ifds(i-1)->write(fw, nextIfdOffset, &nextIfdOffset);
01233             if (!success) {
01234                 error(Event::FileSaveError,
01235                       "TIFFFile::writeTo: %s: Can't write entry data blocks",
01236                       file.c_str());
01237                 fclose(fw);
01238                 return false;
01239             }
01240         }
01241 
01242         // Go back to the start and write the offset to the first IFD (last written)
01243         fseek(fw, headerIfd0Offset, SEEK_SET);
01244         count = fwrite(&nextIfdOffset, sizeof(uint32_t), 1, fw);
01245         if (count != 1) {
01246             error(Event::FileSaveError,
01247                   "TIFFFile::writeTo: %s: Can't write Ifd offset into header",
01248                   file.c_str());
01249             fclose(fw);
01250             return false;
01251         }
01252 
01253         fclose(fw);
01254         return true;
01255     }
01256 
01257     TIFFFile::Ifd* TIFFFile::addIfd() {
01258         Ifd *ifd = new Ifd(this);
01259         _ifds.push_back(ifd);
01260         return ifd;
01261     }
01262 
01263     void TIFFFile::eraseIfds() {
01264         for (size_t i=0; i < _ifds.size(); i++) {
01265             delete _ifds[i];
01266         }
01267         _ifds.clear();
01268     }
01269 
01270     const std::vector<TIFFFile::Ifd *>& TIFFFile::ifds() const {
01271         return _ifds;
01272     }
01273 
01274     TIFFFile::Ifd* TIFFFile::ifds(int index) {
01275         return _ifds[index];
01276     }
01277 
01278 // TIFF subpart-reading functions. These access the file pointer and seek around the TIFF file, so don't trust
01279 // the file pointer to be in the right place after calling these.
01280 
01281     bool TIFFFile::readHeader() {
01282         // Read in the TIFF header at start of file
01283         fseek(fp, 0, SEEK_SET);
01284 
01285         int count;
01286         uint16_t byteOrder, tiffHeaderNumber;
01287         count = fread(&byteOrder, sizeof(byteOrder), 1, fp);
01288         if (count == 1)
01289             count = fread(&tiffHeaderNumber, sizeof(tiffHeaderNumber), 1, fp);
01290         if (count == 1)
01291             count = fread(&offsetToIfd0, sizeof(offsetToIfd0), 1, fp);
01292         if (count != 1) {
01293             setError("readHeader", "Unable to read TIFF header!");
01294             fclose(fp); fp = NULL;
01295             return false;
01296         }
01297 
01298         // Then find out the endianness of the TIFF file.
01299         if (byteOrder == littleEndianMarker) {
01300             littleEndian = true;
01301         } else if (byteOrder == bigEndianMarker) {
01302             littleEndian = false;
01303         } else {
01304             setError("readHeader", "Malformed TIFF header");
01305             fclose(fp); fp = NULL;
01306             return false;
01307         }
01308         dprintf(4, "TIFFFile::readHeader(): %s is %s-endian\n", filename.c_str(), littleEndian ? "little" : "big");
01309 
01310         // Now we can use the convXXX convenience functions, and check the magic number
01311         tiffHeaderNumber = convShort(&tiffHeaderNumber);
01312         if (tiffHeaderNumber != tiffMagicNumber) {
01313             std::stringstream errMsg;
01314             errMsg << "TIFF header magic number is incorrect. This is not a valid TIFF or DNG file. (got "
01315                    <<tiffHeaderNumber<<", expected "<<tiffMagicNumber;
01316             setError("readHeader", errMsg.str());
01317             fclose(fp); fp = NULL;
01318             return false;
01319         }
01320 
01321         // Let's get the offset to the start of the first directory
01322         offsetToIfd0 = convLong(&offsetToIfd0);
01323         dprintf(4, "TIFFFile::readHeader(): %s: IFD0 offset is 0x%x\n", filename.c_str(), offsetToIfd0);
01324 
01325         return true;
01326     }
01327 
01328     bool TIFFFile::readIfd(uint32_t offsetToIFD, Ifd *ifd, uint32_t *offsetToNextIFD) {
01329         int err;
01330 
01331         err = fseek(fp, offsetToIFD, SEEK_SET);
01332         if (err != 0) {
01333             std::stringstream errMsg;
01334             errMsg << "Unable to seek to IFD at "<<offsetToIFD << ": "<<strerror(errno);
01335             setError("readIfd", errMsg.str());
01336             fclose(fp); fp = NULL;
01337             return false;
01338         }
01339 
01340         // Read in number of entries in IFD
01341         int count;
01342         uint16_t ifdEntries;
01343         count = fread(&ifdEntries, sizeof(uint16_t), 1, fp);
01344         if (count != 1) {
01345             std::stringstream errMsg;
01346             errMsg << "Unable to read header for IFD at "<<offsetToIFD;
01347             setError("readIfd", errMsg.str());
01348             fclose(fp); fp = NULL;
01349             return false;
01350         }
01351         ifdEntries = convShort(&ifdEntries);
01352         dprintf(4, "TIFFFile::readIfd(): In %s, IFD at 0x%x contains %d entries\n", filename.c_str(), (int)offsetToIFD, (int)ifdEntries);
01353 
01354         // Read in IFD entries
01355         for (int i=0; i < ifdEntries; i++) {
01356             TiffIfdEntry entry;
01357             count = fread(&entry.tag, sizeof(entry.tag), 1, fp);
01358             if (count == 1)
01359                 count = fread(&entry.type, sizeof(entry.type), 1, fp);
01360             if (count == 1)
01361                 count = fread(&entry.count, sizeof(entry.count), 1, fp);
01362             if (count == 1)
01363                 count = fread(&entry.offset, sizeof(entry.offset), 1, fp);
01364             if (count != 1) {
01365                 std::stringstream errMsg;
01366                 errMsg << "Unable to read IFD entry "<<i <<" for IFD at "<<offsetToIFD;
01367                 setError("readIfd", errMsg.str());
01368                 fclose(fp); fp = NULL;
01369                 return false;
01370             }
01371             entry.tag = convShort(&entry.tag);
01372             entry.type = convShort(&entry.type);
01373             entry.count = convLong(&entry.count);
01374             // Not endian-adjusting entry.offset, as its interpretation is not known yet
01375             dprintf(5, "TIFFFile::readIfd(): IFD entry %d: Tag: %d (%s), Type: %d, Count: %d, Offset: 0x%x\n",
01376                     i, entry.tag, tiffEntryLookup(entry.tag) == NULL ? "Unknown" : tiffEntryLookup(entry.tag)->name, entry.type, entry.count, entry.offset);
01377             ifd->add(entry);
01378         }
01379 
01380         // Read in next IFD offset
01381         if (offsetToNextIFD) {
01382             count = fread(offsetToNextIFD, sizeof(uint32_t), 1, fp);
01383             if (count != 1) {
01384                 std::stringstream errMsg;
01385                 errMsg << "Unable to read next-IFD offset field for IFD at "<<offsetToIFD;
01386                 setError("readIfd", errMsg.str());
01387                 fclose(fp); fp = NULL;
01388                 return false;
01389             }
01390             *offsetToNextIFD = convLong(offsetToNextIFD);
01391             dprintf(DBG_MINOR, "TIFFFile::readIfd(): In file %s, IFD at %x has next-IFD offset field of %x\n",
01392                     filename.c_str(), offsetToIFD, *offsetToNextIFD);
01393         }
01394 
01395         bool success = readSubIfds(ifd);
01396 
01397         return success;
01398     }
01399 
01400     bool TIFFFile::readSubIfds(Ifd *ifd) {
01401         // Read in subIFDs
01402         ifd->eraseSubIfds();
01403 
01404         bool success;
01405         const IfdEntry *subIfdEntry = ifd->find(TIFF_TAG_SubIFDs);
01406         if (subIfdEntry) {
01407             TagValue val = subIfdEntry->value();
01408             if (!val.valid()) {
01409                 fclose(fp); fp = NULL;
01410                 return false;
01411             }
01412             std::vector<int> subIfdOffsets;
01413             if (val.type == TagValue::Int) {
01414                 subIfdOffsets.push_back(val.asInt());
01415             } else {
01416                 subIfdOffsets = val;
01417             }
01418             dprintf(DBG_MINOR, "TIFFFile::readSubIfds(): %s: IFD has %d subIFDs\n",
01419                     filename.c_str(), subIfdOffsets.size());
01420             for (unsigned int i=0; i < subIfdOffsets.size(); i++) {
01421                 Ifd *subIfd = ifd->addSubIfd();
01422                 // Not supporting subIfd chains, just trees
01423                 success = readIfd(subIfdOffsets[i], subIfd, NULL);
01424                 if (!success) {
01425                     return false;
01426                 }
01427             }
01428         }
01429 
01430         return true;
01431     }
01432 
01433     uint16_t TIFFFile::convShort(void const *src) {
01434         uint16_t s = *(uint16_t const *)src;
01435         if (!littleEndian) s = (s << 8) || (s >> 8);
01436         return s;
01437     }
01438 
01439     uint32_t TIFFFile::convLong(void const *src) {
01440         uint32_t l = *(uint32_t const *)src;
01441         if (!littleEndian) l = ((l & 0x000000FF) << 24) ||
01442                                ((l & 0x0000FF00) << 8 ) ||
01443                                ((l & 0x00FF0000) >> 8 ) ||
01444                                ((l & 0xFF000000) >> 24 );
01445         return l;
01446     }
01447 
01448     float TIFFFile::convFloat(void const *src) {
01449         return *reinterpret_cast<float *>(convLong(src));
01450     }
01451 
01452     double TIFFFile::convDouble(void const *src) {
01453         double d;
01454         if (!littleEndian) {
01455             uint8_t *ptr = reinterpret_cast<uint8_t *>(&d);
01456             for (int i=0;i<  8;i++) {
01457                 *(ptr++) = *(((uint8_t const *)src)+7-i);
01458             }
01459         } else {
01460             d = *reinterpret_cast<double const *>(src);
01461         }
01462         return d;
01463     }
01464 
01465     bool TIFFFile::readByteArray(uint32_t offset, uint32_t count, uint8_t *dest) {
01466         if (!dest) return false;
01467 
01468         int err = fseek(fp, offset, SEEK_SET);
01469         if (err != 0) {
01470             return false;
01471         }
01472         size_t trueCount = fread(dest, sizeof(uint8_t), count, fp);
01473         if (trueCount != count) return false;
01474 
01475         return true;
01476     }
01477 
01478     bool TIFFFile::readShortArray(uint32_t offset, uint32_t count, uint16_t *dest) {
01479         if (!dest) return false;
01480 
01481         int err = fseek(fp, offset, SEEK_SET);
01482         if (err != 0) {
01483             return false;
01484         }
01485         size_t trueCount = fread(dest, sizeof(uint16_t), count, fp);
01486         if (trueCount != count) return false;
01487 
01488         if (!littleEndian) {
01489             for (size_t i=0; i < count; i++) {
01490                 uint16_t s = dest[i];
01491                 dest[i] = (s << 8) || (s >> 8);
01492             }
01493         }
01494         return true;
01495     }
01496 
01497     TIFFRational TIFFFile::convRational(void const *src) {
01498         TIFFRational r;
01499         r.numerator = convLong(src);
01500         r.denominator = convLong((unsigned char *)src+4);
01501         return r;
01502     }
01503 
01504 
01505 }

Generated on Thu Jul 22 2010 17:50:34 for FCam by  doxygen 1.7.1