• 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 
01184         if (!success) {
01185             error(Event::FileSaveError,
01186                   "TiffIfd::writeImage: Can't add needed tags to IFD");
01187             return false;
01188         }
01189 
01190         dprintf(5, "TiffIfd::writeImage: Image written.\n");
01191         return true;
01192     }
01193 //
01194 // Methods for TiffFile
01195 //
01196 
01197     TiffFile::TiffFile(): valid(false), fp(NULL), offsetToIfd0(0) {
01198     }
01199 
01200     TiffFile::TiffFile(const std::string &file): valid(false), fp(NULL), offsetToIfd0(0) {
01201         readFrom(file);
01202     }
01203 
01204     TiffFile::~TiffFile() {
01205         eraseIfds();
01206         if (fp) fclose(fp);
01207     }
01208 
01209     bool TiffFile::readFrom(const std::string &file) {
01210         dprintf(DBG_MINOR, "TiffFile::readFrom(): Starting read of %s\n", file.c_str());
01211 
01212         // Make sure we start with a blank slate here
01213         if (fp) {
01214             fclose(fp); fp = NULL;
01215         }
01216         eraseIfds();
01217 
01218         valid = false;
01219 
01220         // Try to open the file
01221         fp = fopen(file.c_str(), "rb");
01222         _filename = file;
01223         if (fp == NULL) {
01224             std::stringstream errMsg;
01225             errMsg << "Unable to open file: "<<strerror(errno);
01226             setError("readFrom", errMsg.str());
01227             return false;
01228         }
01229 
01230         // Read in TIFF directories
01231 
01232         bool success = readHeader();
01233         if (!success) return false;
01234 
01235         uint32_t nextIfdOffset = offsetToIfd0;
01236         while (nextIfdOffset != 0) {
01237             TiffIfd *ifd = new TiffIfd(this);
01238             success = readIfd(nextIfdOffset, ifd, &nextIfdOffset);
01239             if (!success) {
01240                 delete ifd;
01241                 return false;
01242             }
01243             _ifds.push_back(ifd);
01244         }
01245 
01246         valid = true;
01247         return true;
01248     }
01249 
01250     bool TiffFile::writeTo(const std::string &file) {
01251         dprintf(4, "TIFFile::writeTo: %s: Beginning write\n", file.c_str());
01252         // Check that we have enough of an image to write
01253         if (ifds().size() == 0) {
01254             error(Event::FileSaveError,
01255                   "TiffFile::writeTo: %s: Nothing to write",
01256                   file.c_str());
01257             return false;
01258         }
01259         FILE *fw = NULL;
01260         fw = fopen(file.c_str(), "wb");
01261         if (!fw) {
01262             error(Event::FileSaveError,
01263                   "TiffFile::writeTo: %s: Can't open file for writing",
01264                   file.c_str());
01265             return false;
01266         }
01267 
01268         // Write out TIFF header
01269         int count = 0;
01270         uint32_t headerOffset = 0;
01271         count = fwrite(&littleEndianMarker, sizeof(littleEndianMarker), 1, fw);
01272         if (count == 1)
01273             count = fwrite(&tiffMagicNumber, sizeof(tiffMagicNumber), 1 , fw);
01274         // Write a dummy value for IFD0 offset for now. Will come back later, so store offset
01275         uint32_t headerIfd0Offset = ftell(fw);
01276         if (count == 1)
01277             count = fwrite(&headerOffset, sizeof(headerOffset), 1, fw);
01278         if (count != 1) {
01279             error(Event::FileSaveError,
01280                   "TiffFile::writeTo: %s: Can't write TIFF file header",
01281                   file.c_str());
01282             fclose(fw);
01283             return false;
01284         }
01285 
01286         // Write out all the IFDs, reverse order to minimize fseeks
01287         bool success;
01288         uint32_t nextIfdOffset = 0;
01289         for (size_t i=ifds().size(); i > 0; i--) {
01290             dprintf(4, "TIFFile::writeTo: %s: Writing IFD %d\n", file.c_str(), i-1);
01291             success = ifds(i-1)->write(fw, nextIfdOffset, &nextIfdOffset);
01292             if (!success) {
01293                 error(Event::FileSaveError,
01294                       "TiffFile::writeTo: %s: Can't write entry data blocks",
01295                       file.c_str());
01296                 fclose(fw);
01297                 return false;
01298             }
01299         }
01300 
01301         // Go back to the start and write the offset to the first IFD (last written)
01302         fseek(fw, headerIfd0Offset, SEEK_SET);
01303         count = fwrite(&nextIfdOffset, sizeof(uint32_t), 1, fw);
01304         if (count != 1) {
01305             error(Event::FileSaveError,
01306                   "TiffFile::writeTo: %s: Can't write Ifd offset into header",
01307                   file.c_str());
01308             fclose(fw);
01309             return false;
01310         }
01311 
01312         fclose(fw);
01313         return true;
01314     }
01315 
01316     const std::string& TiffFile::filename() const {
01317         return _filename;
01318     }
01319 
01320     TiffIfd* TiffFile::addIfd() {
01321         TiffIfd *ifd = new TiffIfd(this);
01322         _ifds.push_back(ifd);
01323         return ifd;
01324     }
01325 
01326     void TiffFile::eraseIfds() {
01327         for (size_t i=0; i < _ifds.size(); i++) {
01328             delete _ifds[i];
01329         }
01330         _ifds.clear();
01331     }
01332 
01333     const std::vector<TiffIfd *>& TiffFile::ifds() const {
01334         return _ifds;
01335     }
01336 
01337     TiffIfd* TiffFile::ifds(int index) {
01338         return _ifds[index];
01339     }
01340 
01341 // TIFF subpart-reading functions. These access the file pointer and seek around the TIFF file, so don't trust
01342 // the file pointer to be in the right place after calling these.
01343 
01344     bool TiffFile::readHeader() {
01345         // Read in the TIFF header at start of file
01346         fseek(fp, 0, SEEK_SET);
01347 
01348         int count;
01349         uint16_t byteOrder, tiffHeaderNumber;
01350         count = fread(&byteOrder, sizeof(byteOrder), 1, fp);
01351         if (count == 1)
01352             count = fread(&tiffHeaderNumber, sizeof(tiffHeaderNumber), 1, fp);
01353         if (count == 1)
01354             count = fread(&offsetToIfd0, sizeof(offsetToIfd0), 1, fp);
01355         if (count != 1) {
01356             setError("readHeader", "Unable to read TIFF header!");
01357             fclose(fp); fp = NULL;
01358             return false;
01359         }
01360 
01361         // Then find out the endianness of the TIFF file.
01362         if (byteOrder == littleEndianMarker) {
01363             littleEndian = true;
01364         } else if (byteOrder == bigEndianMarker) {
01365             littleEndian = false;
01366         } else {
01367             setError("readHeader", "Malformed TIFF header");
01368             fclose(fp); fp = NULL;
01369             return false;
01370         }
01371         dprintf(4, "TiffFile::readHeader(): %s is %s-endian\n", filename().c_str(), littleEndian ? "little" : "big");
01372 
01373         // Now we can use the convXXX convenience functions, and check the magic number
01374         tiffHeaderNumber = convShort(&tiffHeaderNumber);
01375         if (tiffHeaderNumber != tiffMagicNumber) {
01376             std::stringstream errMsg;
01377             errMsg << "TIFF header magic number is incorrect. This is not a valid TIFF or DNG file. (got "
01378                    <<tiffHeaderNumber<<", expected "<<tiffMagicNumber;
01379             setError("readHeader", errMsg.str());
01380             fclose(fp); fp = NULL;
01381             return false;
01382         }
01383 
01384         // Let's get the offset to the start of the first directory
01385         offsetToIfd0 = convLong(&offsetToIfd0);
01386         dprintf(4, "TiffFile::readHeader(): %s: IFD0 offset is 0x%x\n", filename().c_str(), offsetToIfd0);
01387 
01388         // Sanity check it
01389         if (offsetToIfd0 < 8) {
01390             std::stringstream errMsg;
01391             errMsg << "Offset to first IFD in TIFF file is " << offsetToIfd0 
01392                    << ". This is not a valid TIFF or DNG file.";
01393             setError("readHeader", errMsg.str());
01394             fclose(fp); fp = NULL;
01395             return false;
01396         }
01397 
01398         return true;
01399     }
01400 
01401     bool TiffFile::readIfd(uint32_t offsetToIFD, TiffIfd *ifd, uint32_t *offsetToNextIFD) {
01402         int err;
01403 
01404         err = fseek(fp, offsetToIFD, SEEK_SET);
01405         if (err != 0) {
01406             std::stringstream errMsg;
01407             errMsg << "Unable to seek to IFD at "<<offsetToIFD << ": "<<strerror(errno);
01408             setError("readIfd", errMsg.str());
01409             fclose(fp); fp = NULL;
01410             return false;
01411         }
01412 
01413         // Read in number of entries in IFD
01414         int count;
01415         uint16_t ifdEntries;
01416         count = fread(&ifdEntries, sizeof(uint16_t), 1, fp);
01417         if (count != 1) {
01418             std::stringstream errMsg;
01419             errMsg << "Unable to read header for IFD at "<<offsetToIFD;
01420             setError("readIfd", errMsg.str());
01421             fclose(fp); fp = NULL;
01422             return false;
01423         }
01424         ifdEntries = convShort(&ifdEntries);
01425         dprintf(4, "TiffFile::readIfd(): In %s, IFD at 0x%x contains %d entries\n", filename().c_str(), (int)offsetToIFD, (int)ifdEntries);
01426 
01427         // Read in IFD entries
01428         for (int i=0; i < ifdEntries; i++) {
01429             RawTiffIfdEntry entry;
01430             count = fread(&entry.tag, sizeof(entry.tag), 1, fp);
01431             if (count == 1)
01432                 count = fread(&entry.type, sizeof(entry.type), 1, fp);
01433             if (count == 1)
01434                 count = fread(&entry.count, sizeof(entry.count), 1, fp);
01435             if (count == 1)
01436                 count = fread(&entry.offset, sizeof(entry.offset), 1, fp);
01437             if (count != 1) {
01438                 std::stringstream errMsg;
01439                 errMsg << "Unable to read IFD entry "<<i <<" for IFD at "<<offsetToIFD;
01440                 setError("readIfd", errMsg.str());
01441                 fclose(fp); fp = NULL;
01442                 return false;
01443             }
01444             entry.tag = convShort(&entry.tag);
01445             entry.type = convShort(&entry.type);
01446             entry.count = convLong(&entry.count);
01447             // Not endian-adjusting entry.offset, as its interpretation is not known yet
01448             dprintf(5, "TiffFile::readIfd(): IFD entry %d: Tag: %d (%s), Type: %d, Count: %d, Offset: 0x%x\n",
01449                     i, entry.tag, tiffEntryLookup(entry.tag) == NULL ? "Unknown" : tiffEntryLookup(entry.tag)->name, entry.type, entry.count, entry.offset);
01450             ifd->add(entry);
01451         }
01452 
01453         // Read in next IFD offset
01454         if (offsetToNextIFD) {
01455             count = fread(offsetToNextIFD, sizeof(uint32_t), 1, fp);
01456             if (count != 1) {
01457                 std::stringstream errMsg;
01458                 errMsg << "Unable to read next-IFD offset field for IFD at "<<offsetToIFD;
01459                 setError("readIfd", errMsg.str());
01460                 fclose(fp); fp = NULL;
01461                 return false;
01462             }
01463             *offsetToNextIFD = convLong(offsetToNextIFD);
01464             dprintf(DBG_MINOR, "TiffFile::readIfd(): In file %s, IFD at %x has next-IFD offset field of %x\n",
01465                     filename().c_str(), offsetToIFD, *offsetToNextIFD);
01466         }
01467 
01468         bool success = readSubIfds(ifd);
01469 
01470         return success;
01471     }
01472 
01473     bool TiffFile::readSubIfds(TiffIfd *ifd) {
01474         // Read in subIFDs
01475         ifd->eraseSubIfds();
01476 
01477         bool success;
01478         const TiffIfdEntry *subIfdEntry = ifd->find(TIFF_TAG_SubIFDs);
01479         if (subIfdEntry) {
01480             TagValue val = subIfdEntry->value();
01481             if (!val.valid()) {
01482                 setError("readSubIfds", "Unable to read TIFF subIFDs");
01483                 fclose(fp); fp = NULL;
01484                 return false;
01485             }
01486             std::vector<int> subIfdOffsets;
01487             if (val.type == TagValue::Int) {
01488                 subIfdOffsets.push_back(val.asInt());
01489             } else {
01490                 subIfdOffsets = val;
01491             }
01492             dprintf(DBG_MINOR, "TiffFile::readSubIfds(): %s: IFD has %d subIFDs\n",
01493                     filename().c_str(), subIfdOffsets.size());
01494             for (unsigned int i=0; i < subIfdOffsets.size(); i++) {
01495                 TiffIfd *subIfd = ifd->addSubIfd();
01496                 // Not supporting subIfd chains, just trees
01497                 success = readIfd(subIfdOffsets[i], subIfd, NULL);
01498                 if (!success) {
01499                     return false;
01500                 }
01501             }
01502         }
01503 
01504         return true;
01505     }
01506 
01507     uint16_t TiffFile::convShort(void const *src) {
01508         uint16_t s = *(uint16_t const *)src;
01509         if (!littleEndian) s = (s << 8) || (s >> 8);
01510         return s;
01511     }
01512 
01513     uint32_t TiffFile::convLong(void const *src) {
01514         uint32_t l = *(uint32_t const *)src;
01515         if (!littleEndian) l = ((l & 0x000000FF) << 24) ||
01516                                ((l & 0x0000FF00) << 8 ) ||
01517                                ((l & 0x00FF0000) >> 8 ) ||
01518                                ((l & 0xFF000000) >> 24 );
01519         return l;
01520     }
01521 
01522     float TiffFile::convFloat(void const *src) {
01523         return *reinterpret_cast<float *>(convLong(src));
01524     }
01525 
01526     double TiffFile::convDouble(void const *src) {
01527         double d;
01528         if (!littleEndian) {
01529             uint8_t *ptr = reinterpret_cast<uint8_t *>(&d);
01530             for (int i=0;i<  8;i++) {
01531                 *(ptr++) = *(((uint8_t const *)src)+7-i);
01532             }
01533         } else {
01534             d = *reinterpret_cast<double const *>(src);
01535         }
01536         return d;
01537     }
01538 
01539     bool TiffFile::readByteArray(uint32_t offset, uint32_t count, uint8_t *dest) {
01540         if (!dest) return false;
01541 
01542         int err = fseek(fp, offset, SEEK_SET);
01543         if (err != 0) {
01544             return false;
01545         }
01546         size_t trueCount = fread(dest, sizeof(uint8_t), count, fp);
01547         if (trueCount != count) return false;
01548 
01549         return true;
01550     }
01551 
01552     bool TiffFile::readShortArray(uint32_t offset, uint32_t count, uint16_t *dest) {
01553         if (!dest) return false;
01554 
01555         int err = fseek(fp, offset, SEEK_SET);
01556         if (err != 0) {
01557             return false;
01558         }
01559         size_t trueCount = fread(dest, sizeof(uint16_t), count, fp);
01560         if (trueCount != count) return false;
01561 
01562         if (!littleEndian) {
01563             for (size_t i=0; i < count; i++) {
01564                 uint16_t s = dest[i];
01565                 dest[i] = (s << 8) || (s >> 8);
01566             }
01567         }
01568         return true;
01569     }
01570 
01571     TiffRational TiffFile::convRational(void const *src) {
01572         TiffRational r;
01573         r.numerator = convLong(src);
01574         r.denominator = convLong((unsigned char *)src+4);
01575         return r;
01576     }
01577 
01578 
01579 }

Generated on Mon Aug 16 2010 14:25:45 for FCam by  doxygen 1.7.1