• 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                     // \todo Fix Rationals
00401                     uint32_t num = vd * (2 << 20);
00402                     uint32_t den = 2 << 20;;
00403                     written = fwrite(&num, sizeof(uint32_t), 1, fw);
00404                     written += fwrite(&den, sizeof(uint32_t), 1, fw);
00405                     written /= 2;
00406                 } else {
00407                     std::vector<double> &vd = v;
00408                     written = 0;
00409                     for (size_t i=0; i < vd.size(); i++) {
00410                         uint32_t num = vd[i] * (2 << 20);
00411                         uint32_t den = 2 << 20;
00412                         written += fwrite(&num, sizeof(uint32_t), 1, fw);
00413                         written += fwrite(&den, sizeof(uint32_t), 1, fw);
00414                     }
00415                     written /= 2;
00416                 }
00417                 break;
00418             }
00419             case TIFF_SBYTE:  {
00420                 if (v.type == TagValue::IntVector) {
00421                     std::vector<int> &vi = v;
00422                     std::vector<int8_t> bytes(vi.begin(), vi.end());
00423                     written = fwrite(&bytes[0], sizeof(int8_t), elements, fw);
00424                 } else { // must be std::string
00425                     std::string &vs = v;
00426                     written = fwrite(vs.data(), sizeof(int8_t), elements, fw);
00427                 }
00428                 break;
00429             }
00430             case TIFF_UNDEFINED: { // must be std::string
00431                 std::string &vs = v;
00432                 written = fwrite(vs.data(), sizeof(int8_t), elements, fw);
00433                 break;
00434             }
00435             case TIFF_SSHORT: { // v must be std::vector<int>
00436                 std::vector<int> &vi = v;
00437                 std::vector<int16_t> shorts(vi.begin(), vi.end());
00438                 written = fwrite(&shorts[0], sizeof(int16_t), elements, fw);
00439                 break;
00440             }
00441             case TIFF_SLONG: { // v must be int vector
00442                 std::vector<int> &vi = v;
00443                 written = fwrite(&vi[0], sizeof(uint32_t), elements, fw);
00444                 break;
00445             }
00446             case TIFF_FLOAT: { // v must be a float vector
00447                 std::vector<float> &vf = v;
00448                 written = fwrite(&vf[0], sizeof(float), elements, fw);
00449                 break;
00450             }
00451             case TIFF_DOUBLE: {
00452                 if (elements == 1) {
00453                     double vd = v;
00454                     written = fwrite(&vd, sizeof(double), elements, fw);
00455                 } else {
00456                     std::vector<double> &vd = v;
00457                     written = fwrite(&vd[0], sizeof(double), elements, fw);
00458                 }
00459                 break;
00460             }
00461             }
00462             if (written != elements) {
00463                 error(Event::FileSaveError, "TIFFFile::IfdEntry::writeDataBlock: Can't write data to file (tried to write %d, only wrote %d)", elements, written);
00464                 return false;
00465             }
00466         }
00467 
00468         return true;
00469     }
00470 
00471     bool TIFFFile::IfdEntry::write(FILE *fw) {
00472         dprintf(5, "TIFFile::IfdEntry::write: Writing tag entry %d (%s): %d %d %d\n", tag(), name(), entry.type, entry.count, entry.offset);
00473         int count;
00474         count = fwrite(&entry.tag, sizeof(entry.tag), 1, fw);
00475         if (count == 1) fwrite(&entry.type, sizeof(entry.type), 1, fw);
00476         if (count == 1) fwrite(&entry.count, sizeof(entry.count), 1, fw);
00477         if (count == 1) fwrite(&entry.offset, sizeof(entry.offset), 1, fw);
00478 
00479         if (count != 1) {
00480             error(Event::FileSaveError, "TIFFile::IfdEntry::write: Can't write IFD entry to file.");
00481             return false;
00482         }
00483         return true;
00484 
00485     }
00486 
00487     bool TIFFFile::IfdEntry::operator<(const IfdEntry &other) const {
00488         return tag() < other.tag();
00489     }
00490 
00491     TagValue TIFFFile::IfdEntry::parse() const {
00492         TagValue tag;
00493 
00494         if (info != NULL) {
00495             // Known tag, check for type mismatches
00496             bool typeMismatch=false;
00497             switch(info->type) {
00498             case TIFF_BYTE:
00499             case TIFF_SHORT:
00500             case TIFF_LONG:
00501                 // Accept any unsigned integer type in any other's place
00502                 if (entry.type != TIFF_BYTE &&
00503                     entry.type != TIFF_SHORT &&
00504                     entry.type != TIFF_LONG)
00505                     typeMismatch = true;
00506                 break;
00507             case TIFF_SBYTE:
00508             case TIFF_SSHORT:
00509             case TIFF_SLONG:
00510                 // Accept any signed integer type in any other's place
00511                 if (entry.type != TIFF_SBYTE &&
00512                     entry.type != TIFF_SSHORT &&
00513                     entry.type != TIFF_SLONG)
00514                     typeMismatch = true;
00515                 break;
00516             case TIFF_ASCII:
00517             case TIFF_RATIONAL:
00518             case TIFF_UNDEFINED:
00519             case TIFF_SRATIONAL:
00520             case TIFF_FLOAT:
00521             case TIFF_DOUBLE:
00522                 // Strict matching for these types
00523                 if (entry.type != info->type) typeMismatch = true;
00524                 break;
00525             case TIFF_IFD:
00526                 // Can also be LONG
00527                 if (entry.type != TIFF_LONG &&
00528                     entry.type != TIFF_IFD) typeMismatch = true;
00529                 break;
00530             }
00531             if (typeMismatch) {
00532                 warning(Event::FileLoadWarning,
00533                         "In %s, type mismatch reading TIFF tag %d (%s), expected type %d, got %d\n",
00534                         parent->filename.c_str(), entry.tag, info->name, info->type, entry.type);
00535                 return tag;
00536             }
00537         }
00538         // Now sort out how much data we're looking at
00539         unsigned int bytesPerElement=0;
00540         switch (entry.type) {
00541         case TIFF_BYTE:      bytesPerElement = 1; break;
00542         case TIFF_ASCII:     bytesPerElement = 1; break;
00543         case TIFF_SHORT:     bytesPerElement = 2; break;
00544         case TIFF_LONG:      bytesPerElement = 4; break;
00545         case TIFF_RATIONAL:  bytesPerElement = 8; break;
00546         case TIFF_SBYTE:     bytesPerElement = 1; break;
00547         case TIFF_UNDEFINED: bytesPerElement = 1; break;
00548         case TIFF_SSHORT:    bytesPerElement = 2; break;
00549         case TIFF_SLONG:     bytesPerElement = 4; break;
00550         case TIFF_SRATIONAL: bytesPerElement = 8; break;
00551         case TIFF_FLOAT:     bytesPerElement = 4; break;
00552         case TIFF_DOUBLE:    bytesPerElement = 8; break;
00553         case TIFF_IFD:       bytesPerElement = 4; break;
00554         }
00555         unsigned int totalBytes = entry.count*bytesPerElement;
00556         std::vector<uint8_t> data(totalBytes);
00557 
00558         // Read in the data, possibly seeking if needed
00559         if (entry.count > 4/bytesPerElement) {
00560             // Data doesn't fit in entry.offset field, go fetch it
00561             int adjOffset = parent->convLong(&entry.offset);
00562             bool success = parent->readByteArray(adjOffset, totalBytes,  &data[0]);
00563             if (!success) {
00564                 warning(Event::FileLoadWarning,
00565                         "In %s, unable to read TIFF tag %d (%s) data at offset 0x%x\n",
00566                         parent->filename.c_str(), entry.tag, name(), entry.offset);
00567                 return tag;
00568             }
00569         } else {
00570             uint8_t *ptr = (uint8_t*)&entry.offset;
00571             for (size_t i=0; i < data.size(); i++) {
00572                 data[i] = *(ptr++);
00573             }
00574         }
00575         // Got undifferentiated byte soup, now interpret it and swap endianness as needed
00576         switch (entry.type) {
00577         case TIFF_BYTE:
00578         case TIFF_SBYTE:
00579         case TIFF_UNDEFINED:
00580             tag = std::string(data.begin(), data.end());
00581             break;
00582         case TIFF_ASCII: {
00583             // A TIFF ASCII field can contain multiple strings separated by null characters
00584             std::vector<std::string> strings;
00585             std::vector<uint8_t>::iterator start = data.begin();
00586             for (std::vector<uint8_t>::iterator it=data.begin(); it < data.end(); it++) {
00587                 if (*it == 0) {
00588                     strings.push_back(std::string(start, it));
00589                     start = it + 1;
00590                 }
00591             }
00592             if (strings.size() > 1) {
00593                 tag = strings;
00594             } else {
00595                 tag = strings[0];
00596             }
00597             break;
00598         }
00599         case TIFF_SHORT:
00600             if (entry.count > 1) {
00601                 std::vector<int> vals(entry.count);
00602                 uint8_t *ptr = &data[0];
00603                 for (size_t i=0; i < entry.count; i++) {
00604                     vals[i] = parent->convShort(ptr);
00605                     ptr+=bytesPerElement;
00606                 }
00607                 tag = vals;
00608             } else {
00609                 tag = parent->convShort(&data[0]);
00610             }
00611             break;
00612         case TIFF_IFD:
00613         case TIFF_LONG:
00614             // TagValues are signed, so possible reinterpretation problem here.
00615             if (entry.count > 1) {
00616                 std::vector<int> vals(entry.count);
00617                 uint8_t *ptr = &data[0];
00618                 for (size_t i=0; i < entry.count; i++) {
00619                     vals[i] = (int)parent->convLong(ptr);
00620                     ptr+=bytesPerElement;
00621                 }
00622                 tag = vals;
00623             } else {
00624                 tag = (int)parent->convLong(&data[0]);
00625             }
00626             break;
00627         case TIFF_RATIONAL:
00628             if (entry.count > 1) {
00629                 std::vector<double> vals(entry.count);
00630                 uint8_t *ptr = &data[0];
00631                 for (size_t i=0; i < entry.count; i++) {
00632                     TIFFRational r = parent->convRational(ptr);
00633                     // Precision loss here
00634                     vals[i] = ((double)r.numerator)/((double)r.denominator);
00635                     ptr+=bytesPerElement;
00636                 }
00637                 tag = vals;
00638             } else {
00639                 TIFFRational r = parent->convRational(&data[0]);
00640                 tag = ((double)r.numerator)/((double)r.denominator);
00641             }
00642             break;
00643         case TIFF_SSHORT:
00644             if (entry.count > 1) {
00645                 std::vector<int> vals(entry.count);
00646                 uint8_t *ptr = &data[0];
00647                 for (size_t i=0; i < entry.count; i++) {
00648                     uint16_t val = parent->convShort(ptr);
00649                     vals[i] = *reinterpret_cast<int16_t *>(&val);
00650                     ptr+=bytesPerElement;
00651                 }
00652                 tag = vals;
00653             } else {
00654                 uint16_t val = parent->convShort(&data[0]);
00655                 tag = *reinterpret_cast<int16_t *>(&val);
00656             }
00657             break;
00658 
00659         case TIFF_SLONG:
00660             if (entry.count > 1) {
00661                 std::vector<int> vals(entry.count);
00662                 uint8_t *ptr = &data[0];
00663                 for (size_t i=0; i < entry.count; i++) {
00664                     uint32_t val = parent->convLong(ptr);
00665                     vals[i] = *reinterpret_cast<int32_t *>(&val);
00666                     ptr+=bytesPerElement;
00667                 }
00668                 tag = vals;
00669             } else {
00670                 uint32_t val = parent->convLong(&data[0]);
00671                 tag = *reinterpret_cast<int32_t *>(&val);
00672             }
00673             break;
00674         case TIFF_SRATIONAL:
00675             if (entry.count > 1) {
00676                 std::vector<double> vals(entry.count);
00677                 uint8_t *ptr = &data[0];
00678                 for (size_t i=0; i < entry.count; i++) {
00679                     TIFFRational r = parent->convRational(ptr);
00680                     // Precision loss here
00681                     vals[i] = (static_cast<double>(*reinterpret_cast<int32_t *>(&r.numerator)))
00682                         /(static_cast<double>(*reinterpret_cast<int32_t *>(&r.denominator)));
00683                     ptr+=bytesPerElement;
00684                 }
00685                 tag = vals;
00686             } else {
00687                 TIFFRational r = parent->convRational(&data[0]);
00688                 tag = (static_cast<double>(*reinterpret_cast<int32_t *>(&r.numerator)))
00689                         /(static_cast<double>(*reinterpret_cast<int32_t *>(&r.denominator)));
00690             }
00691             break;
00692         case TIFF_FLOAT:
00693             if (entry.count > 1) {
00694                 std::vector<float> vals(entry.count);
00695                 uint8_t *ptr = &data[0];
00696                 for (size_t i=0; i < entry.count; i++) {
00697                     vals[i] = parent->convFloat(ptr);
00698                     ptr+=bytesPerElement;
00699                 }
00700                 tag = vals;
00701             } else {
00702                 tag = parent->convFloat(&data[0]);
00703             }
00704             break;
00705         case TIFF_DOUBLE:
00706             if (entry.count > 1) {
00707                 std::vector<double> vals(entry.count);
00708                 uint8_t *ptr = &data[0];
00709                 for (size_t i=0; i < entry.count; i++) {
00710                     vals[i] = parent->convDouble(ptr);
00711                     ptr+=bytesPerElement;
00712                 }
00713                 tag = vals;
00714             } else {
00715                 tag = parent->convDouble(&data[0]);
00716             }
00717             break;
00718         };
00719 
00720         state = READ;
00721 
00722         return tag;
00723     }
00724 
00725 //
00726 // Methods for TIFFFile::Ifd
00727 //
00728 
00729     TIFFFile::Ifd::Ifd(TIFFFile *parent): parent(parent), imgState(UNREAD) {
00730     }
00731 
00732     TIFFFile::Ifd::~Ifd() {
00733         eraseSubIfds();
00734     }
00735 
00736     const TIFFFile::IfdEntry* TIFFFile::Ifd::find(uint16_t tag) const {
00737         entryMap::const_iterator match;
00738         match=entries.find(tag);
00739         if (match == entries.end()) return NULL;
00740         else return &(match->second);
00741     }
00742 
00743     TIFFFile::IfdEntry* TIFFFile::Ifd::find(uint16_t tag) {
00744         entryMap::iterator match;
00745         match=entries.find(tag);
00746         if (match == entries.end()) return NULL;
00747         else return &(match->second);
00748     }
00749 
00750     bool TIFFFile::Ifd::add(const TiffIfdEntry &rawEntry) {
00751         IfdEntry entry(rawEntry, parent);
00752 
00753         entries.insert(entries.end(), entryMap::value_type(rawEntry.tag, entry));
00754         return true;
00755     }
00756 
00757     bool TIFFFile::Ifd::add(uint16_t tag, const TagValue &val) {
00758         IfdEntry entry(tag, val, parent);
00759         if (!entry.valid()) return false;
00760         IfdEntry *existingEntry = find(tag);
00761         if (existingEntry) existingEntry->setValue(val);
00762         else {
00763             entries.insert(entryMap::value_type(tag, entry));
00764         }
00765         return true;
00766     }
00767 
00768     bool TIFFFile::Ifd::add(const std::string &tagName, const TagValue &val) {
00769         const TiffEntryInfo *info = tiffEntryLookup(tagName);
00770         if (info) {
00771             return add(info->tag, val);
00772         }
00773         return false;
00774     }
00775 
00776     TIFFFile::Ifd* TIFFFile::Ifd::addSubIfd() {
00777         Ifd *ifd = new Ifd(parent);
00778         _subIfds.push_back(ifd);
00779         return ifd;
00780     }
00781 
00782     void TIFFFile::Ifd::eraseSubIfds() {
00783         for (size_t i=0; i < _subIfds.size(); i++) {
00784             delete _subIfds[i];
00785         }
00786         _subIfds.clear();
00787     }
00788 
00789     const std::vector<TIFFFile::Ifd *>& TIFFFile::Ifd::subIfds() {
00790         return _subIfds;
00791     }
00792 
00793     TIFFFile::Ifd* TIFFFile::Ifd::subIfds(int index) {
00794         return _subIfds[index];
00795     }
00796 
00797     Image TIFFFile::Ifd::getImage() {
00798         if (imgState == NONE || imgState == CACHED) return imgCache;
00799 
00800         const IfdEntry *entry;
00801 
00802         const char *file = parent->filename.c_str();
00803 
00804         entry = find(TIFF_TAG_PhotometricInterpretation);
00805         if (!entry) {
00806             imgState = NONE;
00807             return imgCache;
00808         }
00809         int photometricInterpretation = entry->value();
00810 
00811 #define fatalError(...) \
00812         do { \
00813             warning(Event::FileLoadError, __VA_ARGS__); \
00814             imgState = NONE; \
00815             return imgCache; \
00816         } while(0);
00817 
00818         ImageFormat fmt = UNKNOWN;
00819         switch (photometricInterpretation) {
00820         case TIFF_PhotometricInterpretation_WhiteIsZero:
00821         case TIFF_PhotometricInterpretation_BlackIsZero:
00822         case TIFF_PhotometricInterpretation_PaletteRGB:
00823         case TIFF_PhotometricInterpretation_TransparencyMask:
00824         case TIFF_PhotometricInterpretation_CMYK:
00825         case TIFF_PhotometricInterpretation_CIELAB:
00826         case TIFF_PhotometricInterpretation_ICCLAB:
00827         case TIFF_PhotometricInterpretation_ITULAB:
00828         case TIFF_PhotometricInterpretation_YCbCr:
00829             // Deal with unsupported formats first
00830             fatalError("Ifd::getImage(): %s: Unsupported pixel format (PhotometricInterpretation) %d.",
00831                        file,
00832                        photometricInterpretation);
00833             break;
00834         case TIFF_PhotometricInterpretation_RGB:
00835             fmt = RGB24;
00836             break;
00837         case TIFF_PhotometricInterpretation_LinearRaw:
00838             fatalError("Ifd::getImage(): %s: Linear RAW is not supported.",
00839                        file);
00840             break;
00841         case TIFF_PhotometricInterpretation_CFA:
00842             fmt = RAW;
00843             break;
00844 
00845         }
00846 
00847         int compression = TIFF_Compression_DEFAULT;
00848         entry = find(TIFF_TAG_Compression);
00849         if (entry) compression = entry->value();
00850 
00851         switch (compression) {
00852         case TIFF_Compression_Uncompressed:
00853             // ok
00854             break;
00855         default:
00856             fatalError("Ifd::getImage(): %s: Unsupported compression type %d.",
00857                        file,
00858                        compression);
00859             break;
00860         }
00861 
00862         // Now assuming uncompressed RAW or RGB24
00863         int samplesPerPixel = TIFF_SamplesPerPixel_DEFAULT;
00864         entry = find(TIFF_TAG_SamplesPerPixel);
00865         if (entry) samplesPerPixel = entry->value();
00866         switch (fmt) {
00867         case RAW:
00868             if (samplesPerPixel != 1) {
00869                 fatalError("Ifd::getImage(): %s: RAW images cannot have more than 1 sample per pixel.",
00870                            file);
00871             } 
00872             break;
00873         case RGB24:
00874             if (samplesPerPixel != 3) {
00875                 fatalError("Ifd::getImage(): %s: RGB24 images must have 3 samples per pixel", file);
00876             }
00877             break;               
00878         default: // shouldn't be here
00879             fatalError("Ifd::getImage(): %s: Unexpected branch in the road", file);
00880             break;
00881         }
00882 
00883         entry = find(TIFF_TAG_BitsPerSample);
00884         if (!entry) fatalError("Ifd::getImage(): %s: No BitsPerSample entry found.", file);
00885 
00886         switch (fmt) {
00887         case RAW: {
00888             int bitsPerSample = entry->value();
00889             if (bitsPerSample != 16) fatalError("Ifd::getImage(): %s: Only 16-bpp RAW images supported.", file);
00890             break;
00891         }
00892         case RGB24: {
00893             std::vector<int> bitsPerSample = entry->value();
00894             if (bitsPerSample[0] != 8 ||
00895                 bitsPerSample[1] != 8||
00896                 bitsPerSample[2] != 8) fatalError("Ifd::getImage(): %s: Only 24-bpp RGB images supported.", file);
00897             break;
00898         }
00899         default: // shouldn't be here
00900             fatalError("Ifd::getImage(): %s: Unexpected branch in the road", file);
00901             break;
00902         }
00903 
00904         entry = find(TIFF_TAG_Orientation);
00905         if (!entry) fatalError("Ifd::getImage(): %s: No orientation entry found, required for RAW.", file);
00906         int orientation = entry->value();
00907 
00908         if (orientation != 1) fatalError("Ifd::getImage(): %s: Unsupported orientation value %d", file, orientation);
00909 
00910         // Read in image dimensions
00911         entry = find(TIFF_TAG_ImageWidth);
00912         if (!entry) fatalError("Ifd::getImage(): %s: No ImageWidth entry found.", file);
00913         int imageWidth = entry->value();
00914 
00915         entry = find(TIFF_TAG_ImageLength);
00916         if (!entry) fatalError("Ifd::getImage(): %s: No ImageLength entry found.", file);
00917         int imageLength = entry->value();
00918 
00919         dprintf(4,"Ifd::getImage(): %s: Image size is %d x %d\n", file, imageWidth, imageLength);
00920 
00921         // Read in image strip information
00922         entry = find(TIFF_TAG_RowsPerStrip);
00923         int rowsPerStrip = TIFF_RowsPerStrip_DEFAULT;
00924         uint32_t stripsPerImage = 1;
00925         if (entry) {
00926             rowsPerStrip = entry->value();
00927             stripsPerImage = imageLength / rowsPerStrip; // Full strips
00928             if (imageLength % rowsPerStrip != 0) stripsPerImage++; // Final partial strip
00929         }
00930 
00931         entry = find(TIFF_TAG_StripOffsets);
00932         if (!entry) fatalError("Ifd::getImage(): %s: No image strip data found, and tiled data is not supported.", file);
00933         std::vector<int> stripOffsets = entry->value();
00934         if (stripOffsets.size() != stripsPerImage)
00935             fatalError("Ifd::getImage(): %s: Malformed IFD - conflicting values on number of image strips.", file);
00936 
00937         dprintf(5, "Ifd::getImage(): %s: Image data in %d strips of %d rows each.\n", file, stripsPerImage, rowsPerStrip);
00938 
00939         //
00940         // Read in image data
00941         Image img(imageWidth, imageLength, fmt);
00942 
00943         uint32_t bytesPerStrip = rowsPerStrip * imageWidth * img.bytesPerPixel();
00944         uint32_t bytesLeft = imageLength * imageWidth * img.bytesPerPixel();
00945         for (uint32_t strip=0; strip < stripsPerImage; strip++) {
00946             uint32_t bytesToRead = std::min(bytesLeft, bytesPerStrip);
00947             bool success = parent->readByteArray(stripOffsets[strip], bytesToRead, img(0,rowsPerStrip*strip) );
00948             if (!success) {
00949                 fatalError("Ifd::getImage(): %s: Cannot read in all image data.\n", file);
00950             }
00951             bytesLeft -= bytesToRead;
00952         }
00953 
00954 #undef fatalError
00955 
00956         imgCache = img;
00957         imgState = CACHED;
00958         return imgCache;
00959     }
00960 
00961     bool TIFFFile::Ifd::setImage(Image newImg) {
00962         if (newImg.type() != RAW &&
00963             newImg.type() != RGB24) {
00964             error(Event::FileSaveError, "Ifd::setImage(): Can only save RAW or RGB24 images");
00965             return false;
00966         }
00967         imgCache = newImg;
00968         imgState = CACHED;
00969         return true;
00970     }
00971 
00972     bool TIFFFile::Ifd::write(FILE *fw, uint32_t nextIfdOffset, uint32_t *offset) {
00973         bool success;
00974         // First write out all subIFDs, if any
00975         if (_subIfds.size() > 0) {
00976             std::vector<int> subIfdOffsets;
00977             // Write all subIfd data first
00978             for (size_t i=0; i < _subIfds.size(); i++ ) {
00979                 uint32_t subIfdOffset;
00980                 dprintf(4, "TIFFile::Ifd::write: Writing subIFD %d\n", i);
00981                 success = _subIfds[i]->write(fw, 0, &subIfdOffset);
00982                 if (!success) return false;
00983                 subIfdOffsets.push_back(subIfdOffset);
00984             }
00985             // Then update our subIfd offset entry with returned locations
00986             IfdEntry *subIfdEntry = find(TIFF_TAG_SubIFDs);
00987             if (subIfdEntry != NULL) {
00988                 success = subIfdEntry->setValue(TagValue(subIfdOffsets));
00989             } else {
00990                 success = add(TIFF_TAG_SubIFDs, TagValue(subIfdOffsets));
00991             }
00992             if (!success) return false;
00993         }
00994         // Then write out the image, if any
00995         success = writeImage(fw);
00996         if (!success) return false;
00997 
00998         // Then write out entry extra data fields
00999         dprintf(5, "TIFFile::Ifd::write: Writing Ifd entry data blocks.\n");
01000 
01001         for (entryMap::iterator it=entries.begin(); it != entries.end(); it++) {
01002             success = it->second.writeDataBlock(fw);
01003             if (!success) return false;
01004         }
01005 
01006         // Record starting offset for IFD
01007         *offset = ftell(fw);
01008         // Now write out the IFD itself
01009         int count;
01010         uint16_t entryCount = entries.size();
01011         count = fwrite(&entryCount, sizeof(uint16_t), 1, fw);
01012         if (count != 1) return false;
01013 
01014         dprintf(5, "TIFFile::Ifd::write: Writing IFD entries\n");
01015         for (entryMap::iterator it=entries.begin(); it != entries.end(); it++) {
01016             success = it->second.write(fw);
01017             if (!success) return false;
01018         }
01019         count = fwrite(&nextIfdOffset, sizeof(uint32_t), 1, fw);
01020         if (count != 1) return false;
01021 
01022         dprintf(5, "TIFFile::Ifd::write: IFD written\n");
01023         return true;
01024     }
01025 
01026     bool TIFFFile::Ifd::writeImage(FILE *fw) {
01027         Image img = getImage();
01028         if (imgState == NONE) return true;
01029         dprintf(5, "TIFFile::Ifd::writeImage: Beginning image write\n");
01030         if (!img.valid()) {
01031             error(Event::FileSaveError, "TIFFFile::Ifd::writeImage: Invalid image");
01032             return false;
01033         }
01034 
01035         int photometricInterpretation = 0;
01036         int samplesPerPixel = 0;
01037         std::vector<int> bitsPerSample;
01038         switch (img.type()) {
01039         case RGB24:
01040             photometricInterpretation = TIFF_PhotometricInterpretation_RGB;
01041             samplesPerPixel = 3;
01042             bitsPerSample = std::vector<int>(3,8);
01043             break;
01044         case RGB16:
01045             photometricInterpretation = TIFF_PhotometricInterpretation_RGB;
01046             samplesPerPixel = 3;
01047             bitsPerSample.push_back(5);
01048             bitsPerSample.push_back(6);
01049             bitsPerSample.push_back(5);
01050             break;
01051         case UYVY:
01052         case YUV24:
01053             error(Event::FileSaveError, "TIFFFile::Ifd::writeImage: UYVY/YUV images not supported yet.\n");
01054             return false;
01055             break;
01056         case RAW:
01057             photometricInterpretation = TIFF_PhotometricInterpretation_CFA;
01058             samplesPerPixel = 1;
01059             bitsPerSample.push_back(16);
01060             break;
01061         case UNKNOWN:
01062             error(Event::FileSaveError,
01063                   "TIFFFile::Ifd::writeImage: Can't save UNKNOWN images.");
01064             return false;
01065             break;
01066         }
01067 
01068         int width = img.width();
01069         int height = img.height();
01070 
01071         const uint32_t targetBytesPerStrip = 64 * 1024; // 64 K strips if possible
01072         const uint32_t minRowsPerStrip = 10; // But at least 10 rows per strip
01073 
01074         uint32_t bytesPerRow = img.bytesPerPixel() * width;
01075         int rowsPerStrip;
01076         if (minRowsPerStrip*bytesPerRow > targetBytesPerStrip) {
01077             rowsPerStrip = minRowsPerStrip;
01078         } else {
01079             rowsPerStrip = targetBytesPerStrip / bytesPerRow;
01080         }
01081         uint32_t stripsPerImage = height / rowsPerStrip;
01082         if (height % rowsPerStrip != 0) stripsPerImage++;
01083 
01084         std::vector<int> stripOffsets;
01085         std::vector<int> stripByteCounts;
01086 
01087         for (int ys=0; ys < height; ys += rowsPerStrip) {
01088             size_t lastRow = std::min(height, ys + rowsPerStrip);
01089             int bytesToWrite = (lastRow - ys) * bytesPerRow;
01090 
01091             stripOffsets.push_back(ftell(fw));
01092             stripByteCounts.push_back(bytesToWrite);
01093 
01094             int bytesWritten = 0;
01095             for (size_t y=ys; y < lastRow; y++) {
01096                 bytesWritten += fwrite(img(0,y), sizeof(uint8_t), bytesPerRow, fw);
01097             }
01098             if (bytesWritten != bytesToWrite) {
01099                 error(Event::FileSaveError, "TIFFFile::Ifd::writeImage: Unable to write image data to file (wanted to write %d bytes, able to write %d).", bytesToWrite, bytesWritten);
01100                 return false;
01101             }
01102         }
01103 
01104         bool success;
01105         success = add(TIFF_TAG_PhotometricInterpretation, photometricInterpretation);
01106         if (success) success = add(TIFF_TAG_SamplesPerPixel, samplesPerPixel);
01107         if (success) success = add(TIFF_TAG_BitsPerSample, bitsPerSample);
01108 
01109         if (success) success = add(TIFF_TAG_ImageWidth, width);
01110         if (success) success = add(TIFF_TAG_ImageLength, height);
01111         if (success) success = add(TIFF_TAG_RowsPerStrip, rowsPerStrip);
01112 
01113         if (success) success = add(TIFF_TAG_StripOffsets, stripOffsets);
01114         if (success) success = add(TIFF_TAG_StripByteCounts, stripByteCounts);
01115         if (success) success = add(TIFF_TAG_Orientation, TIFF_Orientation_TopLeft);
01116 
01117         if (!success) {
01118             error(Event::FileSaveError,
01119                   "TIFFFile::Ifd::writeImage: Can't add needed tags to IFD");
01120             return false;
01121         }
01122 
01123         dprintf(5, "TIFFile::Ifd::writeImage: Image written.\n");
01124         return true;
01125     }
01126 //
01127 // Methods for TIFFFile
01128 //
01129 
01130     TIFFFile::TIFFFile(): valid(false), fp(NULL), offsetToIfd0(0) {
01131     }
01132 
01133     TIFFFile::TIFFFile(const std::string &file): valid(false), fp(NULL), offsetToIfd0(0) {
01134         readFrom(file);
01135     }
01136 
01137     TIFFFile::~TIFFFile() {
01138         eraseIfds();
01139         if (fp) fclose(fp);
01140     }
01141 
01142     bool TIFFFile::readFrom(const std::string &file) {
01143         dprintf(DBG_MINOR, "TIFFFile::readFrom(): Starting read of %s\n", file.c_str());
01144 
01145         // Make sure we start with a blank slate here
01146         if (fp) {
01147             fclose(fp); fp = NULL;
01148         }
01149         eraseIfds();
01150 
01151         valid = false;
01152 
01153         // Try to open the file
01154         fp = fopen(file.c_str(), "rb");
01155         filename = file;
01156         if (fp == NULL) {
01157             std::stringstream errMsg;
01158             errMsg << "Unable to open file: "<<strerror(errno);
01159             setError("readFrom", errMsg.str());
01160             return false;
01161         }
01162 
01163         // Read in TIFF directories
01164 
01165         bool success = readHeader();
01166         if (!success) return false;
01167 
01168         uint32_t nextIfdOffset = offsetToIfd0;
01169         while (nextIfdOffset != 0) {
01170             Ifd *ifd = new Ifd(this);
01171             success = readIfd(nextIfdOffset, ifd, &nextIfdOffset);
01172             if (!success) {
01173                 delete ifd;
01174                 return false;
01175             }
01176             _ifds.push_back(ifd);
01177         }
01178 
01179         valid = true;
01180         return true;
01181     }
01182 
01183     bool TIFFFile::writeTo(const std::string &file) {
01184         dprintf(4, "TIFFile::writeTo: %s: Beginning write\n", file.c_str());
01185         // Check that we have enough of an image to write
01186         if (ifds().size() == 0) {
01187             error(Event::FileSaveError,
01188                   "TIFFFile::writeTo: %s: Nothing to write",
01189                   file.c_str());
01190             return false;
01191         }
01192         FILE *fw = NULL;
01193         fw = fopen(file.c_str(), "wb");
01194         if (!fw) {
01195             error(Event::FileSaveError,
01196                   "TIFFFile::writeTo: %s: Can't open file for writing",
01197                   file.c_str());
01198             return false;
01199         }
01200 
01201         // Write out TIFF header
01202         int count = 0;
01203         uint32_t headerOffset = 0;
01204         count = fwrite(&littleEndianMarker, sizeof(littleEndianMarker), 1, fw);
01205         if (count == 1)
01206             count = fwrite(&tiffMagicNumber, sizeof(tiffMagicNumber), 1 , fw);
01207         // Write a dummy value for IFD0 offset for now. Will come back later, so store offset
01208         uint32_t headerIfd0Offset = ftell(fw);
01209         if (count == 1)
01210             count = fwrite(&headerOffset, sizeof(headerOffset), 1, fw);
01211         if (count != 1) {
01212             error(Event::FileSaveError,
01213                   "TIFFFile::writeTo: %s: Can't write TIFF file header",
01214                   file.c_str());
01215             fclose(fw);
01216             return false;
01217         }
01218 
01219         // Write out all the IFDs, reverse order to minimize fseeks
01220         bool success;
01221         uint32_t nextIfdOffset = 0;
01222         for (size_t i=ifds().size(); i > 0; i--) {
01223             dprintf(4, "TIFFile::writeTo: %s: Writing IFD %d\n", file.c_str(), i-1);
01224             success = ifds(i-1)->write(fw, nextIfdOffset, &nextIfdOffset);
01225             if (!success) {
01226                 error(Event::FileSaveError,
01227                       "TIFFFile::writeTo: %s: Can't write entry data blocks",
01228                       file.c_str());
01229                 fclose(fw);
01230                 return false;
01231             }
01232         }
01233 
01234         // Go back to the start and write the offset to the first IFD (last written)
01235         fseek(fw, headerIfd0Offset, SEEK_SET);
01236         count = fwrite(&nextIfdOffset, sizeof(uint32_t), 1, fw);
01237         if (count != 1) {
01238             error(Event::FileSaveError,
01239                   "TIFFFile::writeTo: %s: Can't write Ifd offset into header",
01240                   file.c_str());
01241             fclose(fw);
01242             return false;
01243         }
01244 
01245         fclose(fw);
01246         return true;
01247     }
01248 
01249     TIFFFile::Ifd* TIFFFile::addIfd() {
01250         Ifd *ifd = new Ifd(this);
01251         _ifds.push_back(ifd);
01252         return ifd;
01253     }
01254 
01255     void TIFFFile::eraseIfds() {
01256         for (size_t i=0; i < _ifds.size(); i++) {
01257             delete _ifds[i];
01258         }
01259         _ifds.clear();
01260     }
01261 
01262     const std::vector<TIFFFile::Ifd *>& TIFFFile::ifds() const {
01263         return _ifds;
01264     }
01265 
01266     TIFFFile::Ifd* TIFFFile::ifds(int index) {
01267         return _ifds[index];
01268     }
01269 
01270 // TIFF subpart-reading functions. These access the file pointer and seek around the TIFF file, so don't trust
01271 // the file pointer to be in the right place after calling these.
01272 
01273     bool TIFFFile::readHeader() {
01274         // Read in the TIFF header at start of file
01275         fseek(fp, 0, SEEK_SET);
01276 
01277         int count;
01278         uint16_t byteOrder, tiffHeaderNumber;
01279         count = fread(&byteOrder, sizeof(byteOrder), 1, fp);
01280         if (count == 1)
01281             count = fread(&tiffHeaderNumber, sizeof(tiffHeaderNumber), 1, fp);
01282         if (count == 1)
01283             count = fread(&offsetToIfd0, sizeof(offsetToIfd0), 1, fp);
01284         if (count != 1) {
01285             setError("readHeader", "Unable to read TIFF header!");
01286             fclose(fp); fp = NULL;
01287             return false;
01288         }
01289 
01290         // Then find out the endianness of the TIFF file.
01291         if (byteOrder == littleEndianMarker) {
01292             littleEndian = true;
01293         } else if (byteOrder == bigEndianMarker) {
01294             littleEndian = false;
01295         } else {
01296             setError("readHeader", "Malformed TIFF header");
01297             fclose(fp); fp = NULL;
01298             return false;
01299         }
01300         dprintf(4, "TIFFFile::readHeader(): %s is %s-endian\n", filename.c_str(), littleEndian ? "little" : "big");
01301 
01302         // Now we can use the convXXX convenience functions, and check the magic number
01303         tiffHeaderNumber = convShort(&tiffHeaderNumber);
01304         if (tiffHeaderNumber != tiffMagicNumber) {
01305             std::stringstream errMsg;
01306             errMsg << "TIFF header magic number is incorrect. This is not a valid TIFF or DNG file. (got "
01307                    <<tiffHeaderNumber<<", expected "<<tiffMagicNumber;
01308             setError("readHeader", errMsg.str());
01309             fclose(fp); fp = NULL;
01310             return false;
01311         }
01312 
01313         // Let's get the offset to the start of the first directory
01314         offsetToIfd0 = convLong(&offsetToIfd0);
01315         dprintf(4, "TIFFFile::readHeader(): %s: IFD0 offset is 0x%x\n", filename.c_str(), offsetToIfd0);
01316 
01317         return true;
01318     }
01319 
01320     bool TIFFFile::readIfd(uint32_t offsetToIFD, Ifd *ifd, uint32_t *offsetToNextIFD) {
01321         int err;
01322 
01323         err = fseek(fp, offsetToIFD, SEEK_SET);
01324         if (err != 0) {
01325             std::stringstream errMsg;
01326             errMsg << "Unable to seek to IFD at "<<offsetToIFD << ": "<<strerror(errno);
01327             setError("readIfd", errMsg.str());
01328             fclose(fp); fp = NULL;
01329             return false;
01330         }
01331 
01332         // Read in number of entries in IFD
01333         int count;
01334         uint16_t ifdEntries;
01335         count = fread(&ifdEntries, sizeof(uint16_t), 1, fp);
01336         if (count != 1) {
01337             std::stringstream errMsg;
01338             errMsg << "Unable to read header for IFD at "<<offsetToIFD;
01339             setError("readIfd", errMsg.str());
01340             fclose(fp); fp = NULL;
01341             return false;
01342         }
01343         ifdEntries = convShort(&ifdEntries);
01344         dprintf(4, "TIFFFile::readIfd(): In %s, IFD at 0x%x contains %d entries\n", filename.c_str(), (int)offsetToIFD, (int)ifdEntries);
01345 
01346         // Read in IFD entries
01347         for (int i=0; i < ifdEntries; i++) {
01348             TiffIfdEntry entry;
01349             count = fread(&entry.tag, sizeof(entry.tag), 1, fp);
01350             if (count == 1)
01351                 count = fread(&entry.type, sizeof(entry.type), 1, fp);
01352             if (count == 1)
01353                 count = fread(&entry.count, sizeof(entry.count), 1, fp);
01354             if (count == 1)
01355                 count = fread(&entry.offset, sizeof(entry.offset), 1, fp);
01356             if (count != 1) {
01357                 std::stringstream errMsg;
01358                 errMsg << "Unable to read IFD entry "<<i <<" for IFD at "<<offsetToIFD;
01359                 setError("readIfd", errMsg.str());
01360                 fclose(fp); fp = NULL;
01361                 return false;
01362             }
01363             entry.tag = convShort(&entry.tag);
01364             entry.type = convShort(&entry.type);
01365             entry.count = convLong(&entry.count);
01366             // Not endian-adjusting entry.offset, as its interpretation is not known yet
01367             dprintf(5, "TIFFFile::readIfd(): IFD entry %d: Tag: %d (%s), Type: %d, Count: %d, Offset: 0x%x\n",
01368                     i, entry.tag, tiffEntryLookup(entry.tag) == NULL ? "Unknown" : tiffEntryLookup(entry.tag)->name, entry.type, entry.count, entry.offset);
01369             ifd->add(entry);
01370         }
01371 
01372         // Read in next IFD offset
01373         if (offsetToNextIFD) {
01374             count = fread(offsetToNextIFD, sizeof(uint32_t), 1, fp);
01375             if (count != 1) {
01376                 std::stringstream errMsg;
01377                 errMsg << "Unable to read next-IFD offset field for IFD at "<<offsetToIFD;
01378                 setError("readIfd", errMsg.str());
01379                 fclose(fp); fp = NULL;
01380                 return false;
01381             }
01382             *offsetToNextIFD = convLong(offsetToNextIFD);
01383             dprintf(DBG_MINOR, "TIFFFile::readIfd(): In file %s, IFD at %x has next-IFD offset field of %x\n",
01384                     filename.c_str(), offsetToIFD, *offsetToNextIFD);
01385         }
01386 
01387         bool success = readSubIfds(ifd);
01388 
01389         return success;
01390     }
01391 
01392     bool TIFFFile::readSubIfds(Ifd *ifd) {
01393         // Read in subIFDs
01394         ifd->eraseSubIfds();
01395 
01396         bool success;
01397         const IfdEntry *subIfdEntry = ifd->find(TIFF_TAG_SubIFDs);
01398         if (subIfdEntry) {
01399             TagValue val = subIfdEntry->value();
01400             if (!val.valid()) {
01401                 fclose(fp); fp = NULL;
01402                 return false;
01403             }
01404             std::vector<int> subIfdOffsets;
01405             if (val.type == TagValue::Int) {
01406                 subIfdOffsets.push_back(val.asInt());
01407             } else {
01408                 subIfdOffsets = val;
01409             }
01410             dprintf(DBG_MINOR, "TIFFFile::readSubIfds(): %s: IFD has %d subIFDs\n",
01411                     filename.c_str(), subIfdOffsets.size());
01412             for (unsigned int i=0; i < subIfdOffsets.size(); i++) {
01413                 Ifd *subIfd = ifd->addSubIfd();
01414                 // Not supporting subIfd chains, just trees
01415                 success = readIfd(subIfdOffsets[i], subIfd, NULL);
01416                 if (!success) {
01417                     return false;
01418                 }
01419             }
01420         }
01421 
01422         return true;
01423     }
01424 
01425     uint16_t TIFFFile::convShort(void const *src) {
01426         uint16_t s = *(uint16_t const *)src;
01427         if (!littleEndian) s = (s << 8) || (s >> 8);
01428         return s;
01429     }
01430 
01431     uint32_t TIFFFile::convLong(void const *src) {
01432         uint32_t l = *(uint32_t const *)src;
01433         if (!littleEndian) l = ((l & 0x000000FF) << 24) ||
01434                                ((l & 0x0000FF00) << 8 ) ||
01435                                ((l & 0x00FF0000) >> 8 ) ||
01436                                ((l & 0xFF000000) >> 24 );
01437         return l;
01438     }
01439 
01440     float TIFFFile::convFloat(void const *src) {
01441         return *reinterpret_cast<float *>(convLong(src));
01442     }
01443 
01444     double TIFFFile::convDouble(void const *src) {
01445         double d;
01446         if (!littleEndian) {
01447             uint8_t *ptr = reinterpret_cast<uint8_t *>(&d);
01448             for (int i=0;i<  8;i++) {
01449                 *(ptr++) = *(((uint8_t const *)src)+7-i);
01450             }
01451         } else {
01452             d = *reinterpret_cast<double const *>(src);
01453         }
01454         return d;
01455     }
01456 
01457     bool TIFFFile::readByteArray(uint32_t offset, uint32_t count, uint8_t *dest) {
01458         if (!dest) return false;
01459 
01460         int err = fseek(fp, offset, SEEK_SET);
01461         if (err != 0) {
01462             return false;
01463         }
01464         size_t trueCount = fread(dest, sizeof(uint8_t), count, fp);
01465         if (trueCount != count) return false;
01466 
01467         return true;
01468     }
01469 
01470     bool TIFFFile::readShortArray(uint32_t offset, uint32_t count, uint16_t *dest) {
01471         if (!dest) return false;
01472 
01473         int err = fseek(fp, offset, SEEK_SET);
01474         if (err != 0) {
01475             return false;
01476         }
01477         size_t trueCount = fread(dest, sizeof(uint16_t), count, fp);
01478         if (trueCount != count) return false;
01479 
01480         if (!littleEndian) {
01481             for (size_t i=0; i < count; i++) {
01482                 uint16_t s = dest[i];
01483                 dest[i] = (s << 8) || (s >> 8);
01484             }
01485         }
01486         return true;
01487     }
01488 
01489     TIFFRational TIFFFile::convRational(void const *src) {
01490         TIFFRational r;
01491         r.numerator = convLong(src);
01492         r.denominator = convLong((unsigned char *)src+4);
01493         return r;
01494     }
01495 
01496 
01497 }

Generated on Thu Jul 15 2010 17:51:28 for FCam by  doxygen 1.7.1