• 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 <math.h>
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 
00016 #include "TIFF.h"
00017 #include "../Debug.h"
00018 
00019 namespace FCam {
00020 
00021     void _DNGFrame::rawToRGBColorMatrix(int kelvin, float *matrix) const {
00022         if (dng.numIlluminants == 1) {
00023             for (int i=0;i < 12; i++) matrix[i] = dng.colorMatrix1[i];
00024             return;
00025         }
00026         float alpha =
00027             ((float)kelvin-dng.illuminant1)
00028             /(dng.illuminant2 - dng.illuminant1);
00029         colorMatrixInterpolate(dng.colorMatrix1,
00030                                dng.colorMatrix2,
00031                                alpha, matrix);
00032     }
00033 
00034     void _DNGFrame::debug(const char *name) const {
00035         printf("\tDump of FCam::DNGFrame %s at %llx:\n", name, (long long unsigned)this);
00036         printf("\t  Number of calibration illuminants: %d\n", dng.numIlluminants);
00037         printf("\t  Illuminant 1: %d K, conversion matrix:\n", dng.illuminant1);
00038         const float *matrix = dng.colorMatrix1;
00039         printf("\t\t[ [ %5.3f %5.3f %5.3f %5.3f ]\n", matrix[0], matrix[1], matrix[2], matrix[3]);
00040         printf("\t\t  [ %5.3f %5.3f %5.3f %5.3f ]\n", matrix[4], matrix[5], matrix[6], matrix[7]);
00041         printf("\t\t  [ %5.3f %5.3f %5.3f %5.3f ]\n", matrix[8], matrix[9], matrix[10], matrix[11]);
00042         printf("\t\t  [ %5.3f %5.3f %5.3f %5.3f ] ]\n", matrix[12], matrix[13], matrix[14], matrix[15]);
00043         if (dng.numIlluminants == 2) {
00044             printf("\t Illuminant 2: %d K, conversion matrix:\n", dng.illuminant2);
00045             matrix = dng.colorMatrix2;
00046             printf("\t\t[ [ %5.3f %5.3f %5.3f %5.3f ]\n", matrix[0], matrix[1], matrix[2], matrix[3]);
00047             printf("\t\t  [ %5.3f %5.3f %5.3f %5.3f ]\n", matrix[4], matrix[5], matrix[6], matrix[7]);
00048             printf("\t\t  [ %5.3f %5.3f %5.3f %5.3f ]\n", matrix[8], matrix[9], matrix[10], matrix[11]);
00049             printf("\t\t  [ %5.3f %5.3f %5.3f %5.3f ] ]\n", matrix[12], matrix[13], matrix[14], matrix[15]);
00050         }
00051         printf("\t** Dump of DNGFrame thumbnail image data follows\n");
00052         thumbnail.debug("DNGFrame::thumbnail");
00053         printf("\t** Dump of base Frame fields follows\n");
00054         FCam::_Frame::debug("base frame");
00055     }
00056 
00057     DNGFrame::DNGFrame(_DNGFrame *f): FCam::Frame(f) {}
00058 
00059     const char understoodDNGVersion[4] = {1,3,0,0};
00060     const char oldestSupportedDNGVersion[4] = {1,2,0,0};
00061     const char privateDataPreamble[] = "stanford.fcam.privatedata";
00062     const int privateDataVersion = 1;
00063 
00064     void saveDNG(Frame frame, const std::string &filename) {
00065         dprintf(DBG_MINOR, "saveDNG: Starting to write %s\n", filename.c_str());
00066 
00067         // Initial error checking
00068 
00069         if (!frame.valid()) {
00070             error(Event::FileSaveError, frame,
00071                   "saveDNG: Cannot save invalid frame as %s.", filename.c_str());
00072             return;
00073         }
00074         if (!frame.image().valid()) {
00075             error(Event::FileSaveError, frame,
00076                   "saveDNG: Cannot save frame with no valid image as %s.", filename.c_str());
00077             return;
00078         }
00079         if (frame.image().type() != RAW) {
00080             error(Event::FileSaveError, frame,
00081                   "saveDNG: Cannot save a non-RAW frame as a DNG %s", filename.c_str());
00082             return;
00083         }
00084         if (frame.bayerPattern() == NotBayer) {
00085             error(Event::FileSaveError, frame,
00086                   "saveDNG: Cannot save non-Bayer pattern RAW data as %s", filename.c_str());
00087             return;
00088         }
00089 
00090         // Figure out the color matrices for this sensor
00091         std::vector<float> rawToRGB3000(12);
00092         std::vector<float> rawToRGB6500(12);
00093         frame.rawToRGBColorMatrix(3000, &rawToRGB3000[0]);
00094         frame.rawToRGBColorMatrix(6500, &rawToRGB6500[0]);
00095 
00096         // First map from raw to XYZ
00097         double rawToXYZ3000[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
00098         double rawToXYZ6500[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
00099         for (int i = 0; i < 3; i++) {
00100             for (int j = 0; j < 3; j++) {
00101                 for (int k = 0; k < 3; k++) {
00102                     rawToXYZ3000[i*3+j] += FCam::RGBtoXYZ[i*3+k]*rawToRGB3000[k*4+j];
00103                     rawToXYZ6500[i*3+j] += FCam::RGBtoXYZ[i*3+k]*rawToRGB6500[k*4+j];
00104                 }
00105             }
00106         }
00107 
00108         std::vector<double> xyzToRaw3000(9);
00109         std::vector<double> xyzToRaw6500(9);
00110         // Then invert
00111         invert3x3(rawToXYZ3000, &xyzToRaw3000.front());
00112         invert3x3(rawToXYZ6500, &xyzToRaw6500.front());
00113 
00114         // Start constructing DNG fields
00115 
00116         //bool success;
00117 
00118         TIFFFile dng;
00119 
00120         TIFFFile::Ifd *ifd0 = dng.addIfd();
00121 
00122         // Add IFD0 entries
00123 
00124         std::string dngVersion(understoodDNGVersion,4);
00125         ifd0->add(DNG_TAG_DNGVersion, dngVersion);
00126 
00127         std::string dngBackVersion(oldestSupportedDNGVersion,4);
00128         ifd0->add(DNG_TAG_DNGBackwardVersion, dngBackVersion);
00129 
00130         ifd0->add(TIFF_TAG_Make, frame.manufacturer());
00131         ifd0->add(TIFF_TAG_Model, frame.model());
00132         ifd0->add(DNG_TAG_UniqueCameraModel, frame.model());
00133 
00134         if (frame.tags().find("flash.brightness") != frame.tags().end()) {
00135             // \todo Find actual spec on this, implement better
00136             // bit
00137             //       0  : 0 = flash didn't fire, 1 = flash fired
00138             //     21   : 00 = no strobe return detect, 01 = reserved, 10 = strobe return not detected, 11 = strobe return detected
00139             //   43     : 00 = unknown, 01 = compulsory flash, 10 = compulsory flash supress, 11 = auto mode
00140             //  5       : 0 = flash function present, 1 = no flash function
00141             // 6        : 0 = no red-eye reduction, 1 = red-eye reduction supported
00142             ifd0->add(TIFFEP_TAG_Flash, 1);
00143         }
00144 
00145         // \todo Find specs on this one
00146         ifd0->add(TIFFEP_TAG_TIFFEPStandardID, 1);
00147 
00148         time_t tim = frame.exposureStartTime().s();
00149         struct tm *local = localtime(&tim);
00150         char buf[20];
00151         snprintf(buf, 20, "%04d:%02d:%02d %02d:%02d:%02d",
00152                  local->tm_year + 1900,
00153                  local->tm_mon,
00154                  local->tm_mday,
00155                  local->tm_hour,
00156                  local->tm_min,
00157                  local->tm_sec);
00158         ifd0->add(TIFF_TAG_DateTime, std::string(buf));
00159 
00160         ifd0->add(DNG_TAG_CalibrationIlluminant1, DNG_TAG_CalibrationIlluminant_StdA);
00161         ifd0->add(DNG_TAG_ColorMatrix1, xyzToRaw3000);
00162 
00163         ifd0->add(DNG_TAG_CalibrationIlluminant2, DNG_TAG_CalibrationIlluminant_D65);
00164         ifd0->add(DNG_TAG_ColorMatrix2, xyzToRaw6500);
00165 
00166         std::vector<double> whiteXY(2);
00167         float x,y;
00168         kelvinToXY(frame.whiteBalance(), &x, &y);
00169         whiteXY[0] = x; whiteXY[1] = y;
00170         ifd0->add(DNG_TAG_AsShotWhiteXY, whiteXY);
00171 
00172         std::vector<double> lensInfo(4);
00173         if (frame.tags().find("lens.minZoom") != frame.tags().end()) {
00174             lensInfo[0] = frame["lens.minZoom"].asFloat();
00175             lensInfo[1] = frame["lens.maxZoom"].asFloat();
00176             lensInfo[2] = frame["lens.wideApertureMin"].asFloat();
00177             lensInfo[3] = frame["lens.wideApertureMax"].asFloat();
00178             ifd0->add(DNG_TAG_LensInfo, lensInfo);
00179         }
00180         
00181         // Add some EXIF tags
00182         ifd0->add(EXIF_TAG_ExposureTime, double(frame.exposure())/1e6);
00183         if (frame.tags().find("lens.aperture") != frame.tags().end()) {
00184             double fNumber = frame["lens.aperture"].asFloat();
00185             ifd0->add(EXIF_TAG_FNumber, fNumber);
00186         }
00187 
00188         // Create our very own DNG private data!
00189         {
00190             std::stringstream privateData;
00191             // must start with manufacturer and identification string, terminated by null character. No whitespace!
00192             privateData << privateDataPreamble << std::ends;
00193             // never remove this
00194             privateData << TagValue(privateDataVersion).toBlob();
00195             // if you change the order/count of the below, make sure to update the loading side as well, and up the version number.
00196             privateData << TagValue(frame.exposureStartTime()).toBlob();
00197             privateData << TagValue(frame.exposureEndTime()).toBlob();
00198             privateData << TagValue(frame.processingDoneTime()).toBlob();
00199             privateData << TagValue(frame.exposure()).toBlob();
00200             privateData << TagValue(frame.frameTime()).toBlob();
00201             privateData << TagValue(frame.gain()).toBlob();
00202             privateData << TagValue(frame.whiteBalance()).toBlob();
00203 
00204             privateData << TagValue(frame.shot().exposure).toBlob();
00205             privateData << TagValue(frame.shot().frameTime).toBlob();
00206             privateData << TagValue(frame.shot().gain).toBlob();
00207             privateData << TagValue(frame.shot().whiteBalance).toBlob();
00208 
00209             privateData << TagValue(frame.minRawValue()).toBlob();
00210             privateData << TagValue(frame.maxRawValue()).toBlob();
00211 
00212             privateData << TagValue(3000).toBlob();
00213             privateData << TagValue(rawToRGB3000).toBlob();
00214             privateData << TagValue(6500).toBlob();
00215             privateData << TagValue(rawToRGB6500).toBlob();
00216 
00217             // (not writing histogram/sharpness map)
00218 
00219 
00220             // Write tags
00221             for (TagMap::const_iterator it = frame.tags().begin(); it != frame.tags().end(); it++) {
00222                 privateData << TagValue(it->first) << TagValue(it->second);
00223             }
00224             ifd0->add(DNG_TAG_DNGPrivateData, privateData.str());
00225         }
00226         // Add thumbnail into thumbnail IFD
00227 
00228         TIFFFile::Ifd *thumbIfd = ifd0;
00229         Image thumbnail = makeThumbnail(frame);
00230 
00231         thumbIfd->add(TIFF_TAG_NewSubFileType, (int)TIFF_NewSubfileType_MainPreview);
00232         thumbIfd->setImage(thumbnail);
00233 
00234         // Add RAW Ifd and entries
00235 
00236         TIFFFile::Ifd *rawIfd = ifd0->addSubIfd();
00237 
00238         rawIfd->add(TIFF_TAG_NewSubFileType, (int)TIFF_NewSubfileType_FullRAW);
00239 
00240         std::vector<int> CFARepeatPatternDim(2,2);
00241         rawIfd->add(TIFFEP_TAG_CFARepeatPatternDim, CFARepeatPatternDim);
00242 
00243         std::string CFAPattern;
00244         std::vector<int> blackLevel;
00245         switch(frame.bayerPattern()) {
00246         case RGGB:
00247             CFAPattern = std::string(TIFFEP_CFAPattern_RGGB,4);
00248             blackLevel.push_back(-rawToRGB3000[3]);
00249             blackLevel.push_back(-rawToRGB3000[7]);
00250             blackLevel.push_back(-rawToRGB3000[7]);
00251             blackLevel.push_back(-rawToRGB3000[11]);
00252             break;
00253         case BGGR:
00254             CFAPattern = std::string(TIFFEP_CFAPattern_BGGR,4);
00255             blackLevel.push_back(-rawToRGB3000[11]);
00256             blackLevel.push_back(-rawToRGB3000[7]);
00257             blackLevel.push_back(-rawToRGB3000[7]);
00258             blackLevel.push_back(-rawToRGB3000[3]);
00259             break;
00260         case GRBG:
00261             CFAPattern = std::string(TIFFEP_CFAPattern_GRBG,4);
00262             blackLevel.push_back(-rawToRGB3000[7]);
00263             blackLevel.push_back(-rawToRGB3000[3]);
00264             blackLevel.push_back(-rawToRGB3000[11]);
00265             blackLevel.push_back(-rawToRGB3000[7]);
00266             break;
00267         case GBRG:
00268             CFAPattern = std::string(TIFFEP_CFAPattern_GBRG,4);
00269             blackLevel.push_back(-rawToRGB3000[7]);
00270             blackLevel.push_back(-rawToRGB3000[11]);
00271             blackLevel.push_back(-rawToRGB3000[3]);
00272             blackLevel.push_back(-rawToRGB3000[7]);
00273         default:
00274             error(Event::FileSaveError, "saveDNG: %s: Can't handle non-bayer RAW images", filename.c_str());
00275             return;
00276             break;
00277         }
00278         rawIfd->add(TIFFEP_TAG_CFAPattern, CFAPattern);
00279         rawIfd->add(DNG_TAG_BlackLevel, blackLevel);
00280 
00281         std::vector<int> blackLevelRepeatDim(2,2);
00282         rawIfd->add(DNG_TAG_BlackLevelRepeatDim, blackLevelRepeatDim);
00283 
00284         rawIfd->add(DNG_TAG_WhiteLevel, frame.maxRawValue());
00285 
00286         rawIfd->setImage(frame.image());
00287 
00288         // Constructed all DNG fields, write it to disk
00289         dng.writeTo(filename);
00290 
00291         dprintf(DBG_MINOR, "saveDNG: Done writing %s\n", filename.c_str());
00292     }
00293 
00294 
00295     DNGFrame loadDNG(const std::string &filename) {
00296         TIFFFile dng(filename);
00297         if (!dng.valid) {
00298             // An error during initial TIFF parsing is recorded in
00299             // dng.lastEvent, forward it to the event system
00300             Event err = dng.lastEvent;
00301             DNGFrame nullF;
00302             err.creator = nullF;
00303             postEvent(err);
00304             return nullF;
00305         }
00306 
00307         // Convenience macro, used a lot below.
00308 #define fatalError(...) do {                                            \
00309             DNGFrame nullF;                                             \
00310             error(Event::FileLoadError, nullF, __VA_ARGS__);            \
00311             return nullF; } while(0)
00312 
00313         //
00314         // Verify DNG version
00315 
00316         const TIFFFile::IfdEntry *versionEntry, *backVersionEntry;
00317 
00318         versionEntry = dng.ifds(0)->find(DNG_TAG_DNGVersion);
00319         if (!versionEntry) fatalError("loadDNG: File %s is not a valid DNG file (no DNG version found)", filename.c_str());
00320 
00321         std::string ver(versionEntry->value());
00322         dprintf(4, "loadDNG: DNG file version is %d.%d.%d.%d.\n", ver[0],ver[1],ver[2],ver[3]);
00323 
00324         backVersionEntry = dng.ifds(0)->find(DNG_TAG_DNGBackwardVersion);
00325         if (!backVersionEntry) {
00326             // Default: DNGVersion with last two values empty
00327             ver = (std::string)backVersionEntry->value();
00328             ver[2] = 0;
00329             ver[3] = 0;
00330         } else {
00331             //ver = (std::string)dng.parseEntry(*backVersionEntry);
00332             ver = (std::string)backVersionEntry->value();
00333         }
00334         dprintf(4, "loadDNG: DNG file backward version is %d.%d.%d.%d.\n", ver[0], ver[1], ver[2], ver[3]);
00335 
00336         if ( (understoodDNGVersion[0] < ver[0]) ||
00337              ( (understoodDNGVersion[0] == ver[0]) && (understoodDNGVersion[1] < ver[1])) ||
00338              ( (understoodDNGVersion[1] == ver[1]) && (understoodDNGVersion[2] < ver[2])) ||
00339              ( (understoodDNGVersion[2] == ver[2]) && (understoodDNGVersion[3] < ver[3]) ) ) {
00340             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]);
00341         }
00342 
00343         //
00344         // Let's find the RAW IFD
00345 
00346         const TIFFFile::IfdEntry *entry;
00347         entry = dng.ifds(0)->find(TIFF_TAG_NewSubFileType);
00348         int ifdType = TIFF_NewSubfileType_DEFAULT;
00349         if (entry) {
00350             ifdType = entry->value();
00351         }
00352 
00353         TIFFFile::Ifd *rawIfd=NULL;
00354         if (ifdType == (int)TIFF_NewSubfileType_FullRAW) {
00355             // Main IFD has RAW data
00356             dprintf(4, "loadDNG: RAW data found in IFD0\n");
00357             rawIfd = dng.ifds(0);
00358         } else {
00359             // Search subIFDs for RAW data
00360             for (size_t i=0; i < dng.ifds(0)->subIfds().size(); i++) {
00361                 ifdType = TIFF_NewSubfileType_DEFAULT;
00362                 entry = dng.ifds(0)->subIfds(i)->find(TIFF_TAG_NewSubFileType);
00363                 if (entry) {
00364                     ifdType = entry->value();
00365                 }
00366                 if (ifdType == (int)TIFF_NewSubfileType_FullRAW) {
00367                     dprintf(4, "loadDNG: RAW data found in subIFD %d\n", i);
00368                     rawIfd = dng.ifds(0)->subIfds(i);
00369                     break;
00370                 }
00371             }
00372             if (!rawIfd) fatalError("loadDNG: %s: Can't find RAW data!", filename.c_str());
00373         }
00374 
00375         //
00376         // Ok, now to parse the RAW data
00377 
00378         // Get the bare image data pointed to by the RAW ifd
00379         Image img = rawIfd->getImage();
00380         if (!img.valid()) {
00381             fatalError("loadDNG: %s: Cannot load RAW image data", filename.c_str());
00382         }
00383 
00384         // Need a bunch of other metadata
00385 
00386         // Read in Bayer mosaic pattern
00387         entry = rawIfd->find(TIFFEP_TAG_CFARepeatPatternDim);
00388         if (!entry) fatalError("loadDNG: %s: No CFA pattern dimensions tag found.");
00389         BayerPattern bayer;
00390         {
00391             std::vector<int> &cfaRepeatPatternDim = entry->value();
00392             if (cfaRepeatPatternDim[0] != 2 ||
00393                 cfaRepeatPatternDim[1] != 2) fatalError("loadDNG: %s: CFA pattern dimensions not 2x2 (%d x %d). Unsupported.\n", filename.c_str());
00394 
00395             entry = rawIfd->find(TIFFEP_TAG_CFAPattern);
00396             if (!entry) fatalError("loadDNG: %s: No CFA pattern tag found.");
00397             std::string cfaPattern = entry->value();
00398             if (cfaPattern.size() != 4) fatalError("loadDNG: %s: CFA pattern entry incorrect\n", filename.c_str());
00399             if (cfaPattern[0] == TIFFEP_CFAPattern_RGGB[0] &&
00400                 cfaPattern[1] == TIFFEP_CFAPattern_RGGB[1] &&
00401                 cfaPattern[2] == TIFFEP_CFAPattern_RGGB[2] &&
00402                 cfaPattern[3] == TIFFEP_CFAPattern_RGGB[3]) {
00403                 bayer = RGGB;
00404             } else if (cfaPattern[0] == TIFFEP_CFAPattern_BGGR[0] &&
00405                        cfaPattern[1] == TIFFEP_CFAPattern_BGGR[1] &&
00406                        cfaPattern[2] == TIFFEP_CFAPattern_BGGR[2] &&
00407                        cfaPattern[3] == TIFFEP_CFAPattern_BGGR[3]) {
00408                 bayer = BGGR;
00409             } else if (cfaPattern[0] == TIFFEP_CFAPattern_GRBG[0] &&
00410                        cfaPattern[1] == TIFFEP_CFAPattern_GRBG[1] &&
00411                        cfaPattern[2] == TIFFEP_CFAPattern_GRBG[2] &&
00412                        cfaPattern[3] == TIFFEP_CFAPattern_GRBG[3]) {
00413                 bayer = GRBG;
00414             } else if (cfaPattern[0] == TIFFEP_CFAPattern_GBRG[0] &&
00415                        cfaPattern[1] == TIFFEP_CFAPattern_GBRG[1] &&
00416                        cfaPattern[2] == TIFFEP_CFAPattern_GBRG[2] &&
00417                        cfaPattern[3] == TIFFEP_CFAPattern_GBRG[3]) {
00418                 bayer = GBRG;
00419             } else {
00420                 fatalError("loadDNG: %s: Unsupported CFA pattern: %d %d %d %d\n", filename.c_str(), cfaPattern[0], cfaPattern[1], cfaPattern[2], cfaPattern[3]);
00421             }
00422             dprintf(4,"loadDNG: %s: CFA pattern is type %d\n", filename.c_str(), bayer);
00423         }
00424 
00425         // Read in black level
00426         entry = rawIfd->find(DNG_TAG_BlackLevelRepeatDim);
00427         uint16_t blackLevelRepeatRows = 1;
00428         uint16_t blackLevelRepeatCols = 1;
00429         if (entry) {
00430             std::vector<int> &blackLevelDims = entry->value();
00431             blackLevelRepeatRows = blackLevelDims[0];
00432             blackLevelRepeatCols = blackLevelDims[1];
00433         }
00434         if (! ((blackLevelRepeatRows == 1 && blackLevelRepeatCols == 1)
00435                || (blackLevelRepeatRows == 2 && blackLevelRepeatCols == 2)) ) {
00436             fatalError("loadDNG: %s: Black level pattern size is unsupported: %d x %d (only support 1x1 or 2x2)",
00437                        filename.c_str(), blackLevelRepeatRows, blackLevelRepeatCols);
00438         }
00439 
00440         entry = rawIfd->find(DNG_TAG_BlackLevel);
00441         uint16_t blackLevel[3] = {0,0,0};
00442         if (entry) {
00443             if (entry->value().type == TagValue::Int) {
00444                 if (blackLevelRepeatRows != 1) {
00445                     fatalError("loadDNG: %s: Mismatched entry count between BlackLevelRepeatDim and BlackLevel",
00446                                filename.c_str());
00447                 }
00448                 blackLevel[0] = (int)entry->value();
00449                 blackLevel[1] = (int)entry->value();
00450                 blackLevel[2] = (int)entry->value();
00451             } else if (entry->value().type == TagValue::IntVector) {
00452                 std::vector<int> &blackLevelTag = entry->value();
00453                 if (blackLevelRepeatRows != 2 ||
00454                     blackLevelTag.size() != 4) {
00455                     fatalError("loadDNG: %s: Mismatched entry count between BlackLevelRepeatDim and BlackLevel",
00456                                filename.c_str());
00457                 }
00458                 switch(bayer) {
00459                     case RGGB:
00460                         blackLevel[0] = (int)blackLevelTag[0];
00461                         blackLevel[1] = (int)(blackLevelTag[1] + blackLevelTag[2])/2;
00462                         blackLevel[2] = (int)blackLevelTag[3];
00463                         break;
00464                     case BGGR:
00465                         blackLevel[0] = blackLevelTag[3];
00466                         blackLevel[1] = (blackLevelTag[1] + blackLevelTag[2])/2;
00467                         blackLevel[2] = blackLevelTag[0];
00468                         break;
00469                     case GRBG:
00470                         blackLevel[0] = blackLevelTag[1];
00471                         blackLevel[1] = (blackLevelTag[0] + blackLevelTag[3])/2;
00472                         blackLevel[2] = blackLevelTag[2];
00473                         break;
00474                     case GBRG:
00475                         blackLevel[0] = blackLevelTag[2];
00476                         blackLevel[1] = (blackLevelTag[0] + blackLevelTag[3])/2;
00477                         blackLevel[2] = blackLevelTag[1];
00478                         break;
00479                     default:
00480                         fatalError("loadDNG: %s: Unexpected Bayer value (should already have been validated)!", filename.c_str());
00481                 };
00482             } else {
00483                 fatalError("loadDNG: %s: Unexpected type of black level tag found", filename.c_str());
00484             }
00485         }
00486         dprintf(4,"loadDNG: %s: Black levels are %d, %d, %d\n", filename.c_str(), blackLevel[0], blackLevel[1], blackLevel[2]);
00487 
00488         // Read in white level
00489         entry = rawIfd->find(DNG_TAG_WhiteLevel);
00490         uint16_t whiteLevel = 65535;
00491         if (entry) {
00492             whiteLevel = (int)entry->value();
00493         }
00494         dprintf(4,"loadDNG: %s: White level is %d\n", filename.c_str(), whiteLevel);
00495 
00496         //
00497         // Let's find the Thumbnail IFD, if any
00498 
00499         entry = dng.ifds(0)->find(TIFF_TAG_NewSubFileType);
00500         ifdType = TIFF_NewSubfileType_DEFAULT;
00501         if (entry) {
00502             ifdType = entry->value();
00503         }
00504 
00505         TIFFFile::Ifd *thumbIfd=NULL;
00506         if (ifdType == (int)TIFF_NewSubfileType_MainPreview) {
00507             // Main IFD has thumbnail data
00508             dprintf(4, "loadDNG: Thumbnail data found in IFD0\n");
00509             thumbIfd = dng.ifds(0);
00510         } else {
00511             // Search subIFDs for thumbnail data
00512             for (size_t i=0; i < dng.ifds(0)->subIfds().size(); i++) {
00513                 ifdType = TIFF_NewSubfileType_DEFAULT;
00514                 entry = dng.ifds(0)->subIfds(i)->find(TIFF_TAG_NewSubFileType);
00515                 if (entry) {
00516                     ifdType = entry->value();
00517                 }
00518                 if (ifdType == (int)TIFF_NewSubfileType_MainPreview) {
00519                     dprintf(4, "loadDNG: Thumbnail data found in subIFD %d\n", i);
00520                     thumbIfd = dng.ifds(0)->subIfds(i);
00521                     break;
00522                 }
00523             }            
00524         }
00525         Image thumbnail;
00526         if (thumbIfd) {
00527             dprintf(4, "loadDNG: %s: Loading thumbnail\n", filename.c_str());
00528             thumbnail = thumbIfd->getImage();
00529         }
00530 
00531         //
00532         // Let's grab other useful metadata from the main IFD
00533 
00534         // Read in color calibration information
00535         entry = dng.ifds(0)->find(DNG_TAG_CalibrationIlluminant1);
00536         unsigned int calibIlluminant1 = 0;
00537         if (entry) calibIlluminant1 = (int)entry->value();
00538         if (calibIlluminant1 >= DNG_CalibrationIlluminant_Values) calibIlluminant1 = DNG_CalibrationIlluminant_Values - 1;
00539 
00540         int calibTemp1 = DNG_CalibrationIlluminant_Temp[calibIlluminant1];
00541         dprintf(4,"loadDNG: %s: Calibration illuminant #1 is type %d (%d K)\n", filename.c_str(), calibIlluminant1, calibTemp1);
00542 
00543         std::vector<float> camToRGBMatrix1(9);
00544         {
00545             entry = dng.ifds(0)->find(DNG_TAG_ColorMatrix1);
00546             if (!entry) fatalError("loadDNG: %s: No color calibration matrix found in IFD0", filename.c_str());
00547 
00548             std::vector<double> &xyzToCamMatrix1 = entry->value();
00549 
00550             std::vector<float> rgbToCamMatrix1(9);
00551 
00552             for (int i=0;i<3;i++) {
00553                 for (int j=0; j<3; j++) {
00554                     for (int k=0; k<3;k++) {
00555                         rgbToCamMatrix1[i*3+j] += RGBtoXYZ[i*3+k]*xyzToCamMatrix1[k*3+j];
00556                     }
00557                 }
00558             }
00559             invert3x3(&rgbToCamMatrix1[0], &camToRGBMatrix1[0]);
00560         }
00561 
00562         entry = dng.ifds(0)->find(DNG_TAG_CalibrationIlluminant2);
00563         int numCalibIlluminants = 1;
00564         int calibTemp2 = -1;
00565         std::vector<float> camToRGBMatrix2(9);
00566         if (entry) {
00567             numCalibIlluminants = 2;
00568             unsigned int calibIlluminant2 = (int)entry->value();
00569             if (calibIlluminant2 >= DNG_CalibrationIlluminant_Values) calibIlluminant2 = DNG_CalibrationIlluminant_Values - 1;
00570 
00571             calibTemp2 = DNG_CalibrationIlluminant_Temp[calibIlluminant2];
00572             dprintf(4,"loadDNG: %s: Calibration illuminant #2 is type %d (%d K)\n", filename.c_str(), calibIlluminant2, calibTemp2);
00573 
00574             entry = dng.ifds(0)->find(DNG_TAG_ColorMatrix2);
00575             if (!entry) fatalError("loadDNG: %s: No color matrix found for second calibration illuminant", filename.c_str());
00576 
00577             std::vector<double> &xyzToCamMatrix2 = entry->value();
00578 
00579             std::vector<float> rgbToCamMatrix2(9);
00580 
00581             for (int i=0;i<3;i++) {
00582                 for (int j=0; j<3; j++) {
00583                     for (int k=0; k<3;k++) {
00584                         rgbToCamMatrix2[i*3+j] += RGBtoXYZ[i*3+k]*xyzToCamMatrix2[k*3+j];
00585                     }
00586                 }
00587             }
00588             invert3x3(&rgbToCamMatrix2[0], &camToRGBMatrix2[0]);
00589         }
00590 
00591         // Read in camera model
00592         entry = dng.ifds(0)->find(TIFF_TAG_Model);
00593         std::string cameraModel = "Unknown";
00594         if (entry) cameraModel = (std::string)entry->value();
00595         dprintf(4,"loadDNG: %s: Camera model is %s\n", filename.c_str(), cameraModel.c_str());
00596 
00597         // Read in camera manufacturer
00598         entry = dng.ifds(0)->find(TIFF_TAG_Make);
00599         std::string cameraManufacturer = "Unknown";
00600         if (entry) cameraManufacturer = (std::string)entry->value();
00601         dprintf(4,"loadDNG: %s: Camera manufacturer is %s\n", filename.c_str(), cameraManufacturer.c_str());
00602 
00603 #undef fatalError
00604 
00605         // Create the frame in case we're sticking private data into it
00606         _DNGFrame *_f = new _DNGFrame;
00607         DNGFrame DNGFrame(_f);
00608 
00609         // Write values that might be overriden by private data
00610         _f->dng.minRawValue = std::min(blackLevel[0], std::min(blackLevel[1], blackLevel[2]));
00611         _f->dng.maxRawValue = whiteLevel;
00612         _f->dng.numIlluminants = numCalibIlluminants;
00613         _f->dng.illuminant1 = calibTemp1;
00614         _f->dng.illuminant2 = calibTemp2;
00615         for (int i=0; i < 3; i++) {
00616             for (int j=0; j < 3; j++) {
00617                 _f->dng.colorMatrix1[i*4+j] = camToRGBMatrix1[i*3+j];
00618                 _f->dng.colorMatrix2[i*4+j] = camToRGBMatrix2[i*3+j];
00619             }
00620         }
00621         for (int i=0; i < 3; i++) {
00622             _f->dng.colorMatrix1[i*4+3] = -blackLevel[i];
00623             _f->dng.colorMatrix2[i*4+3] = -blackLevel[i];
00624         }
00625 
00626         // Grab our private DNG data to supplement/replace the above
00627         entry = dng.ifds(0)->find(DNG_TAG_DNGPrivateData);
00628         if (entry) {
00629             std::string &privateString = entry->value();
00630             // Extract preamble string
00631             int preambleEnd = privateString.find((char)0);
00632             std::string preamble = privateString.substr(0,preambleEnd);
00633             if (preamble == privateDataPreamble) {
00634                 // Extract the private data, starting with version
00635                 std::stringstream privateData(privateString.substr(preambleEnd+1));
00636                 TagValue version;
00637                 privateData >> version;
00638                 if (version.asInt() == privateDataVersion) {
00639                     dprintf(4,"loadDNG: %s: Reading private data: %s version %d.\n", filename.c_str(), preamble.c_str(), version.asInt());
00640                     // Deserialize our fields now
00641                     // Order below must match DNG save order
00642                     TagValue val;
00643                     privateData >> val;
00644                     _f->exposureStartTime = val;
00645                     privateData >> val;
00646                     _f->exposureEndTime = val;
00647                     privateData >> val;
00648                     _f->processingDoneTime = val;
00649                     privateData >> val;
00650                     _f->exposure = val;
00651                     privateData >> val;
00652                     _f->frameTime = val;
00653                     privateData >> val;
00654                     _f->gain = val;
00655                     privateData >> val;
00656                     _f->whiteBalance = val;
00657 
00658                     privateData >> val;
00659                     _f->_shot.exposure = val;
00660                     privateData >> val;
00661                     _f->_shot.frameTime = val;
00662                     privateData >> val;
00663                     _f->_shot.gain = val;
00664                     privateData >> val;
00665                     _f->_shot.whiteBalance = val;
00666 
00667                     privateData >> val;
00668                     _f->dng.minRawValue = val.asInt();
00669                     privateData >> val;
00670                     _f->dng.maxRawValue = val.asInt();
00671 
00672                     _f->dng.numIlluminants = 2;
00673 
00674                     privateData >> val;
00675                     _f->dng.illuminant1 = val;
00676                     privateData >> val;
00677                     for (int i=0; i < 12 ; i++)
00678                         _f->dng.colorMatrix1[i] = val.asFloatVector()[i];
00679 
00680                     privateData >> val;
00681                     _f->dng.illuminant2 = val;
00682                     privateData >> val;
00683                     for (int i=0; i < 12 ; i++)
00684                         _f->dng.colorMatrix2[i] = val.asFloatVector()[i];
00685 
00686                     // And the tags
00687                     TagValue key;
00688                     while ((privateData >> key).good()) {
00689                         privateData >> val;
00690                         _f->tags[key] = val;
00691                     }
00692                 } else {
00693                     warning(Event::FileLoadError,
00694                             "loadDNG: %s: Private data version too new: %d (can handle %d), ignoring it.",
00695                             filename.c_str(), version.asInt(), privateDataVersion);
00696                 }
00697             } else {
00698                 warning(Event::FileLoadError,
00699                         "loadDNG: %s: Private data preamble doesn't match FCam's: '%s' (expecting '%s'), ignoring it.",
00700                         filename.c_str(), preamble.c_str(), privateDataPreamble);
00701             }
00702         }
00703         // Write remaining frame information
00704 
00705         _f->image = img;
00706         _f->thumbnail = thumbnail;
00707         _f->dng.bayerPattern = bayer;
00708         _f->dng.manufacturer = cameraManufacturer;
00709         _f->dng.model = cameraModel;
00710 
00711         dprintf(4,"loadDNG: %s: Loaded successfully\n", filename.c_str());
00712         return DNGFrame;
00713     }
00714 
00715 }

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