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

src/processing/TIFF.cpp

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

Generated on Fri Sep 24 2010 15:53:00 for FCam by  doxygen 1.7.1