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

src/processing/DNG.cpp

00001 #include <fstream>
00002 #include <sstream>
00003 #include <stdio.h>
00004 #include <string.h>
00005 #include <time.h>
00006 #include <sched.h>
00007 #include <cmath>
00008 #include <errno.h>
00009 
00010 #include <FCam/processing/DNG.h>
00011 #include <FCam/processing/Color.h>
00012 #include <FCam/processing/Demosaic.h>
00013 #include <FCam/Event.h>
00014 #include <FCam/Frame.h>
00015 #include <FCam/Platform.h>
00016 
00017 #include "TIFF.h"
00018 #include "../Debug.h"
00019 
00020 namespace FCam {
00021 
00022     _DNGFrame::_DNGFrame(): dngFile(NULL) {
00023         dngFile = new TiffFile;
00024     }
00025 
00026     _DNGFrame::~_DNGFrame() {
00027         delete dngFile;
00028     }
00029 
00030     void _DNGFrame::rawToRGBColorMatrix(int kelvin, float *matrix) const {
00031         if (dng.numIlluminants == 1) {
00032             for (int i=0;i < 12; i++) matrix[i] = dng.colorMatrix1[i];
00033             return;
00034         }
00035         // Linear interpolate using inverse CCT
00036         float alpha =
00037             (1./kelvin-1./dng.illuminant1)
00038             /(1./dng.illuminant2 - 1./dng.illuminant1);
00039         colorMatrixInterpolate(dng.colorMatrix1,
00040                                dng.colorMatrix2,
00041                                alpha, matrix);
00042     }
00043 
00044     void _DNGFrame::debug(const char *name) const {
00045         printf("\tDump of FCam::DNGFrame %s at %llx:\n", name, (long long unsigned)this);
00046         printf("\t  Source file name: %s\n", dngFile->filename().c_str());
00047         printf("\t  Number of calibration illuminants: %d\n", dng.numIlluminants);
00048         printf("\t  Illuminant 1: %d K, conversion matrix:\n", dng.illuminant1);
00049         const float *matrix = dng.colorMatrix1;
00050         printf("\t\t[ [ %5.3f %5.3f %5.3f %5.3f ]\n", matrix[0], matrix[1], matrix[2], matrix[3]);
00051         printf("\t\t  [ %5.3f %5.3f %5.3f %5.3f ]\n", matrix[4], matrix[5], matrix[6], matrix[7]);
00052         printf("\t\t  [ %5.3f %5.3f %5.3f %5.3f ]\n", matrix[8], matrix[9], matrix[10], matrix[11]);
00053         if (dng.numIlluminants == 2) {
00054             printf("\t Illuminant 2: %d K, conversion matrix:\n", dng.illuminant2);
00055             matrix = dng.colorMatrix2;
00056             printf("\t\t[ [ %5.3f %5.3f %5.3f %5.3f ]\n", matrix[0], matrix[1], matrix[2], matrix[3]);
00057             printf("\t\t  [ %5.3f %5.3f %5.3f %5.3f ]\n", matrix[4], matrix[5], matrix[6], matrix[7]);
00058             printf("\t\t  [ %5.3f %5.3f %5.3f %5.3f ]\n", matrix[8], matrix[9], matrix[10], matrix[11]);
00059         }
00060         printf("\t** Dump of cached DNGFrame thumbnail image data follows\n");
00061         thumbnail.debug("DNGFrame::thumbnail");
00062         printf("\t** Dump of base Frame fields follows\n");
00063         FCam::_Frame::debug("base frame");
00064     }
00065 
00066     DNGFrame::DNGFrame(_DNGFrame *f): FCam::Frame(f) {}
00067     
00068     Image DNGFrame::thumbnail() { 
00069         return get()->thumbnail;
00070     }
00071     
00072     const char tiffEPVersion[4] = {1,0,0,0};
00073     const char understoodDNGVersion[4] = {1,3,0,0};
00074     const char oldestSupportedDNGVersion[4] = {1,2,0,0};
00075     const char privateDataPreamble[] = "stanford.fcam.privatedata";
00076     const int privateDataVersion = 2;
00077     const int backwardPrivateDataVersion = 2;
00078 
00079     // Notes on privateDataVersion:
00080     // version 1:
00081     //   Initial release
00082     // version 2:
00083     //   Added backwards-compatible version field. Readers need to check this to see if they can parse the data.
00084     //   All frame data now stored as a key/value set (a serialized TagMap, in other words)
00085     //   Frame members have known tag names that are searched for and removed from the TagMap. Anything unknown is left,
00086     //   which includes application-added tags and possible frame members from newer implementations.
00087 
00088     void saveDNGPrivateData_v1(const Frame &frame, std::stringstream &privateData,
00089                                const std::vector<float> &rawToRGB3000, const std::vector<float> &rawToRGB6500) {
00090         privateData << TagValue(frame.exposureStartTime()).toBlob();
00091         privateData << TagValue(frame.exposureEndTime()).toBlob();
00092         privateData << TagValue(frame.processingDoneTime()).toBlob();
00093         privateData << TagValue(frame.exposure()).toBlob();
00094         privateData << TagValue(frame.frameTime()).toBlob();
00095         privateData << TagValue(frame.gain()).toBlob();
00096         privateData << TagValue(frame.whiteBalance()).toBlob();
00097         
00098         privateData << TagValue(frame.shot().exposure).toBlob();
00099         privateData << TagValue(frame.shot().frameTime).toBlob();
00100         privateData << TagValue(frame.shot().gain).toBlob();
00101         privateData << TagValue(frame.shot().whiteBalance).toBlob();
00102         
00103         privateData << TagValue(frame.platform().minRawValue()).toBlob();
00104         privateData << TagValue(frame.platform().maxRawValue()).toBlob();
00105         
00106         privateData << TagValue(3000).toBlob();
00107         privateData << TagValue(rawToRGB3000).toBlob();
00108         privateData << TagValue(6500).toBlob();
00109         privateData << TagValue(rawToRGB6500).toBlob();
00110         
00111         // (not writing histogram/sharpness map)
00112         
00113         // Write tags
00114         for (TagMap::const_iterator it = frame.tags().begin(); it != frame.tags().end(); it++) {
00115             privateData << TagValue(it->first) << TagValue(it->second);
00116         }
00117         
00118     }
00119 
00120     void saveDNGPrivateData_v2(const Frame &frame, std::stringstream &privateData, 
00121                                const std::vector<float> &rawToRGB3000, const std::vector<float> &rawToRGB6500) {
00122 
00123         // First write backward-compatibility field
00124         privateData << TagValue(backwardPrivateDataVersion).toBlob();
00125         
00126         // Now write everything using a TagMap
00127         TagMap frameFields;
00128         frameFields["frame.exposureStartTime"] = frame.exposureStartTime();
00129         frameFields["frame.exposureEndTime"] = frame.exposureEndTime();
00130 
00131         frameFields["frame.processingDoneTime"] = frame.processingDoneTime();
00132         frameFields["frame.exposure"] = frame.exposure();
00133         frameFields["frame.frameTime"] = frame.frameTime();
00134         frameFields["frame.gain"] = frame.gain();
00135         frameFields["frame.whiteBalance"] = frame.whiteBalance();
00136         
00137         frameFields["frame.shot.exposure"] = frame.shot().exposure;
00138         frameFields["frame.shot.frameTime"] = frame.shot().frameTime;
00139         frameFields["frame.shot.gain"] = frame.shot().gain;
00140         frameFields["frame.shot.whiteBalance"] = frame.shot().whiteBalance;
00141         frameFields["frame.shot.colorMatrix"] = frame.shot().colorMatrix();
00142 
00143         frameFields["frame.platform.minRawValue"] = frame.platform().minRawValue();
00144         frameFields["frame.platform.maxRawValue"] = frame.platform().maxRawValue();
00145 
00146         frameFields["frame.illuminant1"] = 3000;        
00147         frameFields["frame.colorMatrix1"] = rawToRGB3000;
00148         frameFields["frame.illuminant2"] = 6500;        
00149         frameFields["frame.colorMatrix2"] = rawToRGB6500;
00150                 
00151         // Write frame fields
00152         for (TagMap::const_iterator it = frameFields.begin(); it != frameFields.end(); it++) {
00153             privateData << TagValue(it->first).toBlob() << it->second.toBlob();
00154         }
00155 
00156         // Write tags
00157         for (TagMap::const_iterator it = frame.tags().begin(); it != frame.tags().end(); it++) {
00158             privateData << TagValue(it->first).toBlob() << it->second.toBlob();
00159         }
00160     }
00161 
00162     void saveDNG(Frame frame, const std::string &filename) {
00163         dprintf(DBG_MINOR, "saveDNG: Starting to write %s\n", filename.c_str());
00164 
00165         // Initial error checking
00166 
00167         if (!frame.valid()) {
00168             error(Event::FileSaveError, frame,
00169                   "saveDNG: Cannot save invalid frame as %s.", filename.c_str());
00170             return;
00171         }
00172         if (!frame.image().valid()) {
00173             error(Event::FileSaveError, frame,
00174                   "saveDNG: Cannot save frame with no valid image as %s.", filename.c_str());
00175             return;
00176         }
00177         if (frame.image().type() != RAW) {
00178             error(Event::FileSaveError, frame,
00179                   "saveDNG: Cannot save a non-RAW frame as a DNG %s", filename.c_str());
00180             return;
00181         }
00182         if (frame.platform().bayerPattern() == NotBayer) {
00183             error(Event::FileSaveError, frame,
00184                   "saveDNG: Cannot save non-Bayer pattern RAW data as %s", filename.c_str());
00185             return;
00186         }
00187 
00188         // Figure out the color matrices for this sensor
00189         std::vector<float> rawToRGB3000(12);
00190         std::vector<float> rawToRGB6500(12);
00191         frame.platform().rawToRGBColorMatrix(3000, &rawToRGB3000.front());
00192         frame.platform().rawToRGBColorMatrix(6500, &rawToRGB6500.front());
00193 
00194         // First map from raw to XYZ
00195         std::vector<double> rawToXYZ3000(9);
00196         std::vector<double> rawToXYZ6500(9);
00197         std::vector<double> rawToRGB3000_linear(9);
00198         std::vector<double> rawToRGB6500_linear(9);
00199         for (int i = 0; i < 3; i++) {
00200             for (int j = 0; j < 3; j++) {
00201                 rawToRGB3000_linear[i*3+j] = rawToRGB3000[i*4+j];
00202                 rawToRGB6500_linear[i*3+j] = rawToRGB6500[i*4+j];
00203                 for (int k = 0; k < 3; k++) {
00204                     rawToXYZ3000[i*3+j] += FCam::RGBtoXYZ[i*3+k]*rawToRGB3000[k*4+j];
00205                     rawToXYZ6500[i*3+j] += FCam::RGBtoXYZ[i*3+k]*rawToRGB6500[k*4+j];
00206                 }
00207             }
00208         }
00209 
00210         std::vector<double> xyzToRaw3000(9);
00211         std::vector<double> xyzToRaw6500(9);
00212         // Then invert
00213         invert3x3(&rawToXYZ3000.front(), &xyzToRaw3000.front());
00214         invert3x3(&rawToXYZ6500.front(), &xyzToRaw6500.front());
00215 
00216         // Need to back-calculate black levels as raw sensor values as well
00217         // Black levels may vary as a function of illuminant (glare?), so calculate black level as a function of frame white balance
00218         std::vector<double> rgbToRAW3000(9);
00219         std::vector<double> rgbToRAW6500(9);
00220         invert3x3(&rawToRGB3000_linear.front(), &rgbToRAW3000.front() );
00221         invert3x3(&rawToRGB6500_linear.front(), &rgbToRAW6500.front() );
00222         std::vector<double> blackLevel3000(3), blackLevel6500(3);
00223         for (int i=0; i < 3; i++) {
00224             for (int j=0; j < 3; j++) {
00225                 blackLevel3000[i] += rgbToRAW3000[i*3+j] * rawToRGB3000[3+j*4];
00226                 blackLevel6500[i] += rgbToRAW6500[i*3+j] * rawToRGB6500[3+j*4];
00227             }
00228         }
00229         // linear interpolation with inverse correlated color temperature
00230         float wbInv = 1.0/frame.whiteBalance();
00231         float kInv3000 = 1.0/3000.f;
00232         float kInv6500 = 1.0/6500.f;
00233 
00234         float alpha = (wbInv - kInv6500)/(kInv3000-kInv6500);
00235         std::vector<int> blackLevel(3);
00236         for (int i=0; i < 3; i++) {
00237             blackLevel[i] = static_cast<int>(-std::floor(alpha*blackLevel6500[i]+(1-alpha)*blackLevel3000[i]+0.5));
00238         }
00239         dprintf(5, "saveDNG: Black level 6500k: %f %f %f, 3000k: %f %f %f, WB: %d k, alpha: %f, final black level: %d %d %d\n",
00240                 blackLevel6500[0],blackLevel6500[1],blackLevel6500[2],
00241                 blackLevel3000[0],blackLevel3000[1],blackLevel3000[2],
00242                 frame.whiteBalance(),
00243                 alpha,
00244                 blackLevel[0], blackLevel[1], blackLevel[2]);
00245   
00246         // Start constructing DNG fields
00247 
00248         TiffFile dng;
00249 
00250         TiffIfd *ifd0 = dng.addIfd();
00251 
00252         // Add IFD0 entries
00253 
00254         std::string dngVersion(understoodDNGVersion,4);
00255         ifd0->add(DNG_TAG_DNGVersion, dngVersion);
00256         
00257         std::string dngBackVersion(oldestSupportedDNGVersion,4);
00258         ifd0->add(DNG_TAG_DNGBackwardVersion, dngBackVersion);
00259 
00260         ifd0->add(TIFF_TAG_Make, frame.platform().manufacturer());
00261         ifd0->add(TIFF_TAG_Model, frame.platform().model());
00262         ifd0->add(DNG_TAG_UniqueCameraModel, frame.platform().model());
00263 
00264         if (frame.tags().find("flash.brightness") != frame.tags().end()) {
00265             // \todo Find actual spec on this, implement better
00266             // bit
00267             //       0  : 0 = flash didn't fire, 1 = flash fired
00268             //     21   : 00 = no strobe return detect, 01 = reserved, 10 = strobe return not detected, 11 = strobe return detected
00269             //   43     : 00 = unknown, 01 = compulsory flash, 10 = compulsory flash supress, 11 = auto mode
00270             //  5       : 0 = flash function present, 1 = no flash function
00271             // 6        : 0 = no red-eye reduction, 1 = red-eye reduction supported
00272             ifd0->add(TIFFEP_TAG_Flash, 1);
00273         }
00274 
00275         std::string tiffEPStandardID(tiffEPVersion, 4);
00276         ifd0->add(TIFFEP_TAG_TIFFEPStandardID, tiffEPStandardID);
00277 
00278         time_t tim = frame.exposureStartTime().s();
00279         struct tm *local = localtime(&tim);
00280         char buf[20];
00281         snprintf(buf, 20, "%04d:%02d:%02d %02d:%02d:%02d",
00282                  local->tm_year + 1900,
00283                  local->tm_mon+1,
00284                  local->tm_mday,
00285                  local->tm_hour,
00286                  local->tm_min,
00287                  local->tm_sec);
00288         ifd0->add(TIFF_TAG_DateTime, std::string(buf));
00289 
00290         ifd0->add(DNG_TAG_CalibrationIlluminant1, DNG_TAG_CalibrationIlluminant_StdA);
00291         ifd0->add(DNG_TAG_ColorMatrix1, xyzToRaw3000);
00292 
00293         ifd0->add(DNG_TAG_CalibrationIlluminant2, DNG_TAG_CalibrationIlluminant_D65);
00294         ifd0->add(DNG_TAG_ColorMatrix2, xyzToRaw6500);
00295 
00296         ifd0->add(TIFF_TAG_Orientation, TIFF_Orientation_TopLeft);
00297 
00298         std::vector<double> whiteXY(2);
00299         float x,y;
00300         kelvinToXY(frame.whiteBalance(), &x, &y);
00301         whiteXY[0] = x; whiteXY[1] = y;
00302         ifd0->add(DNG_TAG_AsShotWhiteXY, whiteXY);
00303 
00304         std::vector<double> lensInfo(4);
00305         if (frame.tags().find("lens.minZoom") != frame.tags().end()) {
00306             lensInfo[0] = frame["lens.minZoom"].asFloat();
00307             lensInfo[1] = frame["lens.maxZoom"].asFloat();
00308             lensInfo[2] = frame["lens.wideApertureMin"].asFloat();
00309             lensInfo[3] = frame["lens.wideApertureMax"].asFloat();
00310             ifd0->add(DNG_TAG_LensInfo, lensInfo);
00311         }
00312         
00313         // Add some EXIF tags
00314         TiffIfd *exifIfd = ifd0->addExifIfd();
00315 
00316         exifIfd->add(EXIF_TAG_ExposureTime, double(frame.exposure())/1e6);
00317         if (frame.tags().find("lens.aperture") != frame.tags().end()) {
00318             double fNumber = frame["lens.aperture"].asFloat();
00319             ifd0->add(EXIF_TAG_FNumber, fNumber);
00320         }
00321 
00322         int usecs = frame.exposureStartTime().us();
00323         snprintf(buf, 20, "%06d", usecs);
00324         exifIfd->add(EXIF_TAG_SubsecTime, std::string(buf));
00325 
00326         exifIfd->add(EXIF_TAG_SensitivityType, EXIF_TAG_SensitivityType_ISO);
00327         exifIfd->add(EXIF_TAG_ISOSpeedRatings, (int)(frame.gain()*100) );
00328 
00329         if (frame.tags().find("lens.zoom") != frame.tags().end()) {
00330             double focalLength = frame["lens.zoom"].asFloat();
00331             exifIfd->add(EXIF_TAG_FocalLength, focalLength);
00332         }
00333 
00334         // Create our very own DNG private data!
00335         {
00336             std::stringstream privateData;
00337             // must start with manufacturer and identification string, terminated by null character. No whitespace!
00338             privateData << privateDataPreamble << std::ends;
00339             // never remove this
00340             privateData << TagValue(privateDataVersion).toBlob();
00341             switch (privateDataVersion) {
00342             case 1:
00343                 saveDNGPrivateData_v1(frame, privateData, rawToRGB3000, rawToRGB6500);
00344                 break;
00345             case 2:
00346                 saveDNGPrivateData_v2(frame, privateData, rawToRGB3000, rawToRGB6500);
00347                 break;
00348             }
00349             ifd0->add(DNG_TAG_DNGPrivateData, privateData.str());
00350         }
00351         // Add thumbnail into thumbnail IFD
00352 
00353         dprintf(4, "saveDNG: Adding thumbnail\n");
00354         TiffIfd *thumbIfd = ifd0;
00355         Image thumbnail = makeThumbnail(frame);
00356 
00357         thumbIfd->add(TIFF_TAG_NewSubFileType, (int)TIFF_NewSubfileType_MainPreview);
00358         thumbIfd->setImage(thumbnail);
00359 
00360         // Add RAW Ifd and entries
00361         dprintf(4, "saveDNG: Adding RAW metadata\n");
00362 
00363         TiffIfd *rawIfd = ifd0->addSubIfd();
00364 
00365         rawIfd->add(TIFF_TAG_NewSubFileType, (int)TIFF_NewSubfileType_FullRAW);
00366 
00367         std::vector<int> CFARepeatPatternDim(2,2);
00368         rawIfd->add(TIFFEP_TAG_CFARepeatPatternDim, CFARepeatPatternDim);
00369 
00370         std::string CFAPattern;
00371         std::vector<int> blackLevelPattern;
00372         switch(frame.platform().bayerPattern()) {
00373         case RGGB:
00374             CFAPattern = std::string(TIFFEP_CFAPattern_RGGB,4);
00375             blackLevelPattern.push_back(blackLevel[0]);
00376             blackLevelPattern.push_back(blackLevel[1]);
00377             blackLevelPattern.push_back(blackLevel[1]);
00378             blackLevelPattern.push_back(blackLevel[2]);
00379             break;
00380         case BGGR:
00381             CFAPattern = std::string(TIFFEP_CFAPattern_BGGR,4);
00382             blackLevelPattern.push_back(blackLevel[2]);
00383             blackLevelPattern.push_back(blackLevel[1]);
00384             blackLevelPattern.push_back(blackLevel[1]);
00385             blackLevelPattern.push_back(blackLevel[0]);
00386             break;
00387         case GRBG:
00388             CFAPattern = std::string(TIFFEP_CFAPattern_GRBG,4);
00389             blackLevelPattern.push_back(blackLevel[1]);
00390             blackLevelPattern.push_back(blackLevel[0]);
00391             blackLevelPattern.push_back(blackLevel[2]);
00392             blackLevelPattern.push_back(blackLevel[1]);
00393             break;
00394         case GBRG:
00395             CFAPattern = std::string(TIFFEP_CFAPattern_GBRG,4);
00396             blackLevelPattern.push_back(blackLevel[1]);
00397             blackLevelPattern.push_back(blackLevel[2]);
00398             blackLevelPattern.push_back(blackLevel[0]);
00399             blackLevelPattern.push_back(blackLevel[1]);
00400         default:
00401             error(Event::FileSaveError, "saveDNG: %s: Can't handle non-bayer RAW images", filename.c_str());
00402             return;
00403             break;
00404         }
00405         rawIfd->add(TIFFEP_TAG_CFAPattern, CFAPattern);
00406         rawIfd->add(DNG_TAG_BlackLevel, blackLevelPattern);
00407 
00408         std::vector<int> blackLevelRepeatDim(2,2);
00409         rawIfd->add(DNG_TAG_BlackLevelRepeatDim, blackLevelRepeatDim);
00410 
00411         rawIfd->add(DNG_TAG_WhiteLevel, frame.platform().maxRawValue());
00412 
00413         // Leaving a 4-pixel border around RAW image to allow for loss of data during interpolation
00414         std::vector<int> cropOrigin(2);
00415         cropOrigin[0] = 4;
00416         cropOrigin[1] = 4;
00417         std::vector<int> cropSize(2);
00418         cropSize[0] = frame.image().width()-8;
00419         cropSize[1] = frame.image().height()-8;
00420 
00421         rawIfd->add(DNG_TAG_DefaultCropOrigin, cropOrigin);
00422         rawIfd->add(DNG_TAG_DefaultCropSize, cropSize);
00423 
00424         dprintf(4, "saveDNG: Adding RAW image\n");
00425         rawIfd->setImage(frame.image());
00426 
00427         dprintf(4, "saveDNG: Beginning write to disk\n");
00428         // Constructed all DNG fields, write it to disk
00429         dng.writeTo(filename);
00430 
00431         dprintf(DBG_MINOR, "saveDNG: Done writing %s\n", filename.c_str());
00432     }
00433 
00434     void loadDNGPrivateData_v1(_DNGFrame *_f, std::stringstream &privateData) {
00435         // Deserialize our fields now
00436         // Order below must match DNG save order
00437         TagValue val;
00438         privateData >> val;
00439         _f->exposureStartTime = val;
00440         privateData >> val;
00441         _f->exposureEndTime = val;
00442         privateData >> val;
00443         _f->processingDoneTime = val;
00444         privateData >> val;
00445         _f->exposure = val;
00446         privateData >> val;
00447         _f->frameTime = val;
00448         privateData >> val;
00449         _f->gain = val;
00450         privateData >> val;
00451         _f->whiteBalance = val;
00452         
00453         privateData >> val;
00454         _f->_shot.exposure = val;
00455         privateData >> val;
00456         _f->_shot.frameTime = val;
00457         privateData >> val;
00458         _f->_shot.gain = val;
00459         privateData >> val;
00460         _f->_shot.whiteBalance = val;
00461         
00462         privateData >> val;
00463         _f->dng.minRawValue = val.asInt();
00464         privateData >> val;
00465         _f->dng.maxRawValue = val.asInt();
00466         
00467         _f->dng.numIlluminants = 2;
00468         
00469         privateData >> val;
00470         _f->dng.illuminant1 = val;
00471         privateData >> val;
00472         for (int i=0; i < 12 ; i++)
00473             _f->dng.colorMatrix1[i] = val.asFloatVector()[i];
00474         
00475         privateData >> val;
00476         _f->dng.illuminant2 = val;
00477         privateData >> val;
00478         for (int i=0; i < 12 ; i++)
00479             _f->dng.colorMatrix2[i] = val.asFloatVector()[i];
00480         
00481         // And the tags
00482         TagValue key;
00483         while ((privateData >> key).good()) {
00484             privateData >> val;
00485             _f->tags[key] = val;
00486         }
00487     }
00488 
00489     void loadDNGPrivateData_v2(_DNGFrame *_f, std::stringstream &privateData) {
00490 
00491         // Read everything into the frame tags
00492         TagValue key, val;
00493         while ((privateData >> key).good()) {
00494             privateData >> val;
00495             _f->tags[key] = val;
00496         }
00497 
00498         // And then look for special frame fields and parse them out
00499 
00500         TagMap::iterator it;
00501 
00502 #define grabField(fieldName, fieldDest, asType)      \
00503         do {                                         \
00504             it = _f->tags.find(fieldName);           \
00505             if ( it != _f->tags.end()) {             \
00506                 fieldDest = it->second.asType;       \
00507                 _f->tags.erase(it);                  \
00508             }                                        \
00509         } while(0)
00510 
00511         grabField("frame.exposureStartTime", _f->exposureStartTime, asTime());
00512         grabField("frame.exposureEndTime", _f->exposureEndTime, asTime());
00513 
00514         grabField("frame.processingDoneTime", _f->processingDoneTime, asTime());
00515         grabField("frame.exposure", _f->exposure, asInt());
00516         grabField("frame.frameTime", _f->frameTime, asInt());
00517         grabField("frame.gain", _f->gain, asFloat());
00518 
00519         grabField("frame.whiteBalance", _f->whiteBalance, asInt());
00520 
00521         grabField("frame.shot.exposure", _f->_shot.exposure, asInt());
00522         grabField("frame.shot.frameTime", _f->_shot.frameTime, asInt());
00523         grabField("frame.shot.gain", _f->_shot.gain, asFloat());
00524 
00525         grabField("frame.shot.whiteBalance", _f->_shot.whiteBalance, asInt());
00526         
00527         std::vector<float> cMatrix;
00528         grabField("frame.shot.colorMatrix", cMatrix, asFloatVector());
00529         _f->_shot.setColorMatrix(cMatrix);
00530 
00531         grabField("frame.platform.minRawValue", _f->dng.minRawValue, asInt());
00532         grabField("frame.platform.maxRawValue", _f->dng.maxRawValue, asInt());
00533 
00534         _f->dng.numIlluminants = 2;
00535         grabField("frame.illuminant1", _f->dng.illuminant1, asInt());
00536         grabField("frame.illuminant2", _f->dng.illuminant2, asInt());
00537 
00538         it = _f->tags.find("frame.colorMatrix1");
00539         if (it != _f->tags.end()) {
00540             for (int i=0; i < 12; i++) {
00541                 _f->dng.colorMatrix1[i] = it->second.asFloatVector()[i];
00542             }
00543             _f->tags.erase(it);
00544         }
00545 
00546         it = _f->tags.find("frame.colorMatrix2");
00547         if (it != _f->tags.end()) {
00548             for (int i=0; i < 12; i++) {
00549                 _f->dng.colorMatrix2[i] = it->second.asFloatVector()[i];
00550             }
00551             _f->tags.erase(it);
00552         }
00553 
00554         // All leftover tags stay in the frame tags
00555     }
00556 
00557 
00558     DNGFrame loadDNG(const std::string &filename) {
00559         // Construct DNG Frame
00560         _DNGFrame *_f = new _DNGFrame;
00561         DNGFrame f(_f);
00562         // We'll mostly manipulate the internal dngFile for now
00563         TiffFile &dng = *(_f->dngFile);
00564 
00565         // Start reading DNG file data
00566         dng.readFrom(filename);
00567 
00568         if (!dng.valid) {
00569             // An error during initial TIFF parsing is recorded in
00570             // dng.lastEvent, forward it to the event system
00571             Event err = dng.lastEvent;
00572             DNGFrame nullF;
00573             err.creator = nullF;
00574             postEvent(err);
00575             return nullF;
00576         }
00577 
00578         // Convenience error macro
00579 #define fatalError(...) do {                                            \
00580             DNGFrame nullF;                                             \
00581             error(Event::FileLoadError, nullF, __VA_ARGS__);            \
00582             return nullF; } while(0)
00583 
00584         //
00585         // Verify DNG version
00586 
00587         const TiffIfdEntry *versionEntry, *backVersionEntry;
00588 
00589         versionEntry = dng.ifds(0)->find(DNG_TAG_DNGVersion);
00590         if (!versionEntry) fatalError("loadDNG: File %s is not a valid DNG file (no DNG version found)", filename.c_str());
00591 
00592         std::string ver(versionEntry->value());
00593         dprintf(4, "loadDNG: DNG file version is %d.%d.%d.%d.\n", ver[0],ver[1],ver[2],ver[3]);
00594 
00595         backVersionEntry = dng.ifds(0)->find(DNG_TAG_DNGBackwardVersion);
00596         if (!backVersionEntry) {
00597             // Default: DNGVersion with last two values empty
00598             ver = (std::string)backVersionEntry->value();
00599             ver[2] = 0;
00600             ver[3] = 0;
00601         } else {
00602             //ver = (std::string)dng.parseEntry(*backVersionEntry);
00603             ver = (std::string)backVersionEntry->value();
00604         }
00605         dprintf(4, "loadDNG: DNG file backward version is %d.%d.%d.%d.\n", ver[0], ver[1], ver[2], ver[3]);
00606 
00607         if ( (understoodDNGVersion[0] < ver[0]) ||
00608              ( (understoodDNGVersion[0] == ver[0]) && (understoodDNGVersion[1] < ver[1])) ||
00609              ( (understoodDNGVersion[1] == ver[1]) && (understoodDNGVersion[2] < ver[2])) ||
00610              ( (understoodDNGVersion[2] == ver[2]) && (understoodDNGVersion[3] < ver[3]) ) ) {
00611             fatalError("loadDNG: File %s is too new, requires understanding at least DNG version %d.%d.%d.%d\n", filename.c_str(), ver[0],ver[1],ver[2],ver[3]);
00612         }
00613 
00614         //
00615         // Let's find the RAW IFD
00616 
00617         const TiffIfdEntry *entry;
00618         entry = dng.ifds(0)->find(TIFF_TAG_NewSubFileType);
00619         int ifdType = TIFF_NewSubfileType_DEFAULT;
00620         if (entry) {
00621             ifdType = entry->value();
00622         }
00623 
00624         TiffIfd *rawIfd = NULL;
00625         if (ifdType == (int)TIFF_NewSubfileType_FullRAW) {
00626             // Main IFD has RAW data
00627             dprintf(4, "loadDNG: RAW data found in IFD0\n");
00628             rawIfd = dng.ifds(0);
00629         } else {
00630             // Search subIFDs for RAW data
00631             for (size_t i=0; i < dng.ifds(0)->subIfds().size(); i++) {
00632                 ifdType = TIFF_NewSubfileType_DEFAULT;
00633                 entry = dng.ifds(0)->subIfds(i)->find(TIFF_TAG_NewSubFileType);
00634                 if (entry) {
00635                     ifdType = entry->value();
00636                 }
00637                 if (ifdType == (int)TIFF_NewSubfileType_FullRAW) {
00638                     dprintf(4, "loadDNG: RAW data found in subIFD %d\n", i);
00639                     rawIfd = dng.ifds(0)->subIfds(i);
00640                     break;
00641                 }
00642             }
00643             if (!rawIfd) fatalError("loadDNG: %s: Can't find RAW data!", filename.c_str());
00644         }
00645 
00646         //
00647         // Read in RAW image data 
00648         _f->image = rawIfd->getImage();
00649         
00650         //
00651         // Ok, now to parse the RAW metadata
00652 
00653         // Read in Bayer mosaic pattern
00654         entry = rawIfd->find(TIFFEP_TAG_CFARepeatPatternDim);
00655         if (!entry) fatalError("loadDNG: %s: No CFA pattern dimensions tag found.");
00656         BayerPattern bayer;
00657         {
00658             std::vector<int> &cfaRepeatPatternDim = entry->value();
00659             if (cfaRepeatPatternDim[0] != 2 ||
00660                 cfaRepeatPatternDim[1] != 2) fatalError("loadDNG: %s: CFA pattern dimensions not 2x2 (%d x %d). Unsupported.\n", filename.c_str());
00661 
00662             entry = rawIfd->find(TIFFEP_TAG_CFAPattern);
00663             if (!entry) fatalError("loadDNG: %s: No CFA pattern tag found.");
00664             std::string cfaPattern = entry->value();
00665             if (cfaPattern.size() != 4) fatalError("loadDNG: %s: CFA pattern entry incorrect\n", filename.c_str());
00666             if (cfaPattern[0] == TIFFEP_CFAPattern_RGGB[0] &&
00667                 cfaPattern[1] == TIFFEP_CFAPattern_RGGB[1] &&
00668                 cfaPattern[2] == TIFFEP_CFAPattern_RGGB[2] &&
00669                 cfaPattern[3] == TIFFEP_CFAPattern_RGGB[3]) {
00670                 bayer = RGGB;
00671             } else if (cfaPattern[0] == TIFFEP_CFAPattern_BGGR[0] &&
00672                        cfaPattern[1] == TIFFEP_CFAPattern_BGGR[1] &&
00673                        cfaPattern[2] == TIFFEP_CFAPattern_BGGR[2] &&
00674                        cfaPattern[3] == TIFFEP_CFAPattern_BGGR[3]) {
00675                 bayer = BGGR;
00676             } else if (cfaPattern[0] == TIFFEP_CFAPattern_GRBG[0] &&
00677                        cfaPattern[1] == TIFFEP_CFAPattern_GRBG[1] &&
00678                        cfaPattern[2] == TIFFEP_CFAPattern_GRBG[2] &&
00679                        cfaPattern[3] == TIFFEP_CFAPattern_GRBG[3]) {
00680                 bayer = GRBG;
00681             } else if (cfaPattern[0] == TIFFEP_CFAPattern_GBRG[0] &&
00682                        cfaPattern[1] == TIFFEP_CFAPattern_GBRG[1] &&
00683                        cfaPattern[2] == TIFFEP_CFAPattern_GBRG[2] &&
00684                        cfaPattern[3] == TIFFEP_CFAPattern_GBRG[3]) {
00685                 bayer = GBRG;
00686             } else {
00687                 fatalError("loadDNG: %s: Unsupported CFA pattern: %d %d %d %d\n", filename.c_str(), cfaPattern[0], cfaPattern[1], cfaPattern[2], cfaPattern[3]);
00688             }
00689             dprintf(4,"loadDNG: %s: CFA pattern is type %d\n", filename.c_str(), bayer);
00690         }
00691 
00692         // Read in black level
00693         entry = rawIfd->find(DNG_TAG_BlackLevelRepeatDim);
00694         uint16_t blackLevelRepeatRows = 1;
00695         uint16_t blackLevelRepeatCols = 1;
00696         if (entry) {
00697             std::vector<int> &blackLevelDims = entry->value();
00698             blackLevelRepeatRows = blackLevelDims[0];
00699             blackLevelRepeatCols = blackLevelDims[1];
00700         }
00701         if (! ((blackLevelRepeatRows == 1 && blackLevelRepeatCols == 1)
00702                || (blackLevelRepeatRows == 2 && blackLevelRepeatCols == 2)) ) {
00703             fatalError("loadDNG: %s: Black level pattern size is unsupported: %d x %d (only support 1x1 or 2x2)",
00704                        filename.c_str(), blackLevelRepeatRows, blackLevelRepeatCols);
00705         }
00706 
00707         entry = rawIfd->find(DNG_TAG_BlackLevel);
00708         uint16_t blackLevel[3] = {0,0,0};
00709         if (entry) {
00710             if (entry->value().type == TagValue::Int) {
00711                 if (blackLevelRepeatRows != 1) {
00712                     fatalError("loadDNG: %s: Mismatched entry count between BlackLevelRepeatDim and BlackLevel",
00713                                filename.c_str());
00714                 }
00715                 blackLevel[0] = (int)entry->value();
00716                 blackLevel[1] = (int)entry->value();
00717                 blackLevel[2] = (int)entry->value();
00718             } else if (entry->value().type == TagValue::IntVector) {
00719                 std::vector<int> &blackLevelTag = entry->value();
00720                 if (blackLevelRepeatRows != 2 ||
00721                     blackLevelTag.size() != 4) {
00722                     fatalError("loadDNG: %s: Mismatched entry count between BlackLevelRepeatDim and BlackLevel",
00723                                filename.c_str());
00724                 }
00725                 switch(bayer) {
00726                     case RGGB:
00727                         blackLevel[0] = (int)blackLevelTag[0];
00728                         blackLevel[1] = (int)(blackLevelTag[1] + blackLevelTag[2])/2;
00729                         blackLevel[2] = (int)blackLevelTag[3];
00730                         break;
00731                     case BGGR:
00732                         blackLevel[0] = blackLevelTag[3];
00733                         blackLevel[1] = (blackLevelTag[1] + blackLevelTag[2])/2;
00734                         blackLevel[2] = blackLevelTag[0];
00735                         break;
00736                     case GRBG:
00737                         blackLevel[0] = blackLevelTag[1];
00738                         blackLevel[1] = (blackLevelTag[0] + blackLevelTag[3])/2;
00739                         blackLevel[2] = blackLevelTag[2];
00740                         break;
00741                     case GBRG:
00742                         blackLevel[0] = blackLevelTag[2];
00743                         blackLevel[1] = (blackLevelTag[0] + blackLevelTag[3])/2;
00744                         blackLevel[2] = blackLevelTag[1];
00745                         break;
00746                     default:
00747                         fatalError("loadDNG: %s: Unexpected Bayer value (should already have been validated)!", filename.c_str());
00748                 };
00749             } else {
00750                 fatalError("loadDNG: %s: Unexpected type of black level tag found", filename.c_str());
00751             }
00752         }
00753         dprintf(4,"loadDNG: %s: Black levels are %d, %d, %d\n", filename.c_str(), blackLevel[0], blackLevel[1], blackLevel[2]);
00754 
00755         // Read in white level
00756         entry = rawIfd->find(DNG_TAG_WhiteLevel);
00757         uint16_t whiteLevel = 65535;
00758         if (entry) {
00759             whiteLevel = (int)entry->value();
00760         }
00761         dprintf(4,"loadDNG: %s: White level is %d\n", filename.c_str(), whiteLevel);
00762 
00763         //
00764         // Let's find the Thumbnail IFD, if any
00765         TiffIfd *thumbIfd = NULL;
00766 
00767         entry = dng.ifds(0)->find(TIFF_TAG_NewSubFileType);
00768         ifdType = TIFF_NewSubfileType_DEFAULT;
00769         if (entry) {
00770             ifdType = entry->value();
00771         }
00772 
00773         if (ifdType == (int)TIFF_NewSubfileType_MainPreview) {
00774             // Main IFD has thumbnail data
00775             dprintf(4, "loadDNG: Thumbnail data found in IFD0\n");
00776             thumbIfd = dng.ifds(0);
00777         } else {
00778             // Search subIFDs for thumbnail data
00779             for (size_t i=0; i < dng.ifds(0)->subIfds().size(); i++) {
00780                 ifdType = TIFF_NewSubfileType_DEFAULT;
00781                 entry = dng.ifds(0)->subIfds(i)->find(TIFF_TAG_NewSubFileType);
00782                 if (entry) {
00783                     ifdType = entry->value();
00784                 }
00785                 if (ifdType == (int)TIFF_NewSubfileType_MainPreview) {
00786                     dprintf(4, "loadDNG: Thumbnail data found in subIFD %d\n", i);
00787                     thumbIfd = dng.ifds(0)->subIfds(i);
00788                     break;
00789                 }
00790             }            
00791         }
00792 
00793         if (thumbIfd) {
00794             _f->thumbnail = thumbIfd->getImage();
00795         }
00796 
00797         //
00798         // Let's grab other useful metadata from the main IFD
00799 
00800         // Verify orientation
00801         entry = dng.ifds(0)->find(TIFF_TAG_Orientation);
00802         if (!entry) fatalError("loadDNG: %s: No orientation entry found", filename.c_str());
00803         int orientation = entry->value();
00804 
00805         if (orientation != TIFF_Orientation_TopLeft) fatalError("loadDNG: %s: Unsupported orientation value %d", filename.c_str(), orientation);
00806 
00807         // Read in color calibration information
00808         entry = dng.ifds(0)->find(DNG_TAG_CalibrationIlluminant1);
00809         unsigned int calibIlluminant1 = 0;
00810         if (entry) calibIlluminant1 = (int)entry->value();
00811         if (calibIlluminant1 >= DNG_CalibrationIlluminant_Values) calibIlluminant1 = DNG_CalibrationIlluminant_Values - 1;
00812 
00813         int calibTemp1 = DNG_CalibrationIlluminant_Temp[calibIlluminant1];
00814         dprintf(4,"loadDNG: %s: Calibration illuminant #1 is type %d (%d K)\n", filename.c_str(), calibIlluminant1, calibTemp1);
00815 
00816         std::vector<float> camToRGBMatrix1(9);
00817         std::vector<float> rgbBlackLevel1(3);
00818         {
00819             entry = dng.ifds(0)->find(DNG_TAG_ColorMatrix1);
00820             if (!entry) fatalError("loadDNG: %s: No color calibration matrix found in IFD0", filename.c_str());
00821 
00822             std::vector<double> &xyzToCamMatrix1 = entry->value();
00823 
00824             std::vector<float> rgbToCamMatrix1(9);
00825 
00826             for (int i=0;i<3;i++) {
00827                 for (int j=0; j<3; j++) {
00828                     for (int k=0; k<3;k++) {
00829                         rgbToCamMatrix1[i*3+j] += RGBtoXYZ[i*3+k]*xyzToCamMatrix1[k*3+j];
00830                     }
00831                 }
00832             }
00833             invert3x3(&rgbToCamMatrix1[0], &camToRGBMatrix1[0]);
00834             for (int i=0;i<3;i++) {
00835                 for (int j=0; j<3; j++) {
00836                     rgbBlackLevel1[i] += camToRGBMatrix1[i*3+j]*(-blackLevel[j]);
00837                 }
00838             }
00839         }
00840 
00841         entry = dng.ifds(0)->find(DNG_TAG_CalibrationIlluminant2);
00842         int numCalibIlluminants = 1;
00843         int calibTemp2 = -1;
00844         std::vector<float> camToRGBMatrix2(9);
00845         std::vector<float> rgbBlackLevel2(3);
00846         if (entry) {
00847             numCalibIlluminants = 2;
00848             unsigned int calibIlluminant2 = (int)entry->value();
00849             if (calibIlluminant2 >= DNG_CalibrationIlluminant_Values) calibIlluminant2 = DNG_CalibrationIlluminant_Values - 1;
00850 
00851             calibTemp2 = DNG_CalibrationIlluminant_Temp[calibIlluminant2];
00852             dprintf(4,"loadDNG: %s: Calibration illuminant #2 is type %d (%d K)\n", filename.c_str(), calibIlluminant2, calibTemp2);
00853 
00854             entry = dng.ifds(0)->find(DNG_TAG_ColorMatrix2);
00855             if (!entry) fatalError("loadDNG: %s: No color matrix found for second calibration illuminant", filename.c_str());
00856 
00857             std::vector<double> &xyzToCamMatrix2 = entry->value();
00858 
00859             std::vector<float> rgbToCamMatrix2(9);
00860             for (int i=0;i<3;i++) {
00861                 for (int j=0; j<3; j++) {
00862                     for (int k=0; k<3;k++) {
00863                         rgbToCamMatrix2[i*3+j] += RGBtoXYZ[i*3+k]*xyzToCamMatrix2[k*3+j];
00864                     }
00865                 }
00866             }
00867             invert3x3(&rgbToCamMatrix2[0], &camToRGBMatrix2[0]);
00868             for (int i=0;i<3;i++) {
00869                 for (int j=0; j<3; j++) {
00870                     rgbBlackLevel2[i] += camToRGBMatrix2[i*3+j]*(-blackLevel[j]);
00871                 }
00872             }
00873 
00874         }
00875 
00876         // Read in camera model
00877         entry = dng.ifds(0)->find(TIFF_TAG_Model);
00878         std::string cameraModel = "Unknown";
00879         if (entry) cameraModel = (std::string)entry->value();
00880         dprintf(4,"loadDNG: %s: Camera model is %s\n", filename.c_str(), cameraModel.c_str());
00881 
00882         // Read in camera manufacturer
00883         entry = dng.ifds(0)->find(TIFF_TAG_Make);
00884         std::string cameraManufacturer = "Unknown";
00885         if (entry) cameraManufacturer = (std::string)entry->value();
00886         dprintf(4,"loadDNG: %s: Camera manufacturer is %s\n", filename.c_str(), cameraManufacturer.c_str());
00887 
00888 #undef fatalError
00889 
00890         // Write values that might be overriden by private data
00891         _f->dng.minRawValue = std::min(blackLevel[0], std::min(blackLevel[1], blackLevel[2]));
00892         _f->dng.maxRawValue = whiteLevel;
00893         _f->dng.numIlluminants = numCalibIlluminants;
00894         _f->dng.illuminant1 = calibTemp1;
00895         _f->dng.illuminant2 = calibTemp2;
00896         for (int i=0; i < 3; i++) {
00897             for (int j=0; j < 3; j++) {
00898                 _f->dng.colorMatrix1[i*4+j] = camToRGBMatrix1[i*3+j];
00899                 _f->dng.colorMatrix2[i*4+j] = camToRGBMatrix2[i*3+j];
00900             }
00901         }
00902         for (int i=0; i < 3; i++) {
00903             _f->dng.colorMatrix1[i*4+3] = rgbBlackLevel1[i];
00904             _f->dng.colorMatrix2[i*4+3] = rgbBlackLevel2[i];
00905         }
00906 
00907         // Grab our private DNG data to supplement/replace the above
00908         entry = dng.ifds(0)->find(DNG_TAG_DNGPrivateData);
00909         if (entry) {
00910             std::string &privateString = entry->value();
00911             // Extract preamble string
00912             int preambleEnd = privateString.find((char)0);
00913             std::string preamble = privateString.substr(0,preambleEnd);
00914             if (preamble == privateDataPreamble) {
00915                 // Extract the private data, starting with version
00916                 std::stringstream privateData(privateString.substr(preambleEnd+1));
00917                 TagValue version;
00918                 privateData >> version;
00919                 
00920                 if (version.asInt() == 1) {
00921                     dprintf(4,"loadDNG: %s: Reading private data, version 1.\n", filename.c_str());
00922                     loadDNGPrivateData_v1(_f, privateData);
00923                 } else {
00924                     TagValue backwardVersion;
00925                     privateData >> backwardVersion;
00926                     switch (backwardVersion.asInt()) {
00927                     case 2:
00928                         dprintf(4,"loadDNG: %s: Reading private data, version 2.\n", filename.c_str());
00929                         loadDNGPrivateData_v2(_f, privateData);
00930                         break;                        
00931                     default:
00932                         warning(Event::FileLoadError,
00933                                 "loadDNG: %s: Private data version too new: %d,%d (can handle X, %d), ignoring it.",
00934                                 filename.c_str(), version.asInt(), backwardVersion.asInt(), privateDataVersion);
00935                     }
00936                 }
00937             } else {
00938                 warning(Event::FileLoadError,
00939                         "loadDNG: %s: Private data preamble doesn't match FCam's: '%s' (expecting '%s'), ignoring it.",
00940                         filename.c_str(), preamble.c_str(), privateDataPreamble);
00941             }
00942         }
00943         // Write remaining frame information
00944 
00945         _f->dng.bayerPattern = bayer;
00946         _f->dng.manufacturer = cameraManufacturer;
00947         _f->dng.model = cameraModel;
00948 
00949         dprintf(4,"loadDNG: %s: Loaded successfully\n", filename.c_str());
00950         return f;
00951     }
00952 
00953 }

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