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
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
00080
00081
00082
00083
00084
00085
00086
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
00112
00113
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
00124 privateData << TagValue(backwardPrivateDataVersion).toBlob();
00125
00126
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
00152 for (TagMap::const_iterator it = frameFields.begin(); it != frameFields.end(); it++) {
00153 privateData << TagValue(it->first).toBlob() << it->second.toBlob();
00154 }
00155
00156
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
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
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
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
00213 invert3x3(&rawToXYZ3000.front(), &xyzToRaw3000.front());
00214 invert3x3(&rawToXYZ6500.front(), &xyzToRaw6500.front());
00215
00216
00217
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
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
00247
00248 TiffFile dng;
00249
00250 TiffIfd *ifd0 = dng.addIfd();
00251
00252
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
00266
00267
00268
00269
00270
00271
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
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
00335 {
00336 std::stringstream privateData;
00337
00338 privateData << privateDataPreamble << std::ends;
00339
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
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
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
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
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
00436
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
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
00492 TagValue key, val;
00493 while ((privateData >> key).good()) {
00494 privateData >> val;
00495 _f->tags[key] = val;
00496 }
00497
00498
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
00555 }
00556
00557
00558 DNGFrame loadDNG(const std::string &filename) {
00559
00560 _DNGFrame *_f = new _DNGFrame;
00561 DNGFrame f(_f);
00562
00563 TiffFile &dng = *(_f->dngFile);
00564
00565
00566 dng.readFrom(filename);
00567
00568 if (!dng.valid) {
00569
00570
00571 Event err = dng.lastEvent;
00572 DNGFrame nullF;
00573 err.creator = nullF;
00574 postEvent(err);
00575 return nullF;
00576 }
00577
00578
00579 #define fatalError(...) do { \
00580 DNGFrame nullF; \
00581 error(Event::FileLoadError, nullF, __VA_ARGS__); \
00582 return nullF; } while(0)
00583
00584
00585
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
00598 ver = (std::string)backVersionEntry->value();
00599 ver[2] = 0;
00600 ver[3] = 0;
00601 } else {
00602
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
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
00627 dprintf(4, "loadDNG: RAW data found in IFD0\n");
00628 rawIfd = dng.ifds(0);
00629 } else {
00630
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
00648 _f->image = rawIfd->getImage();
00649
00650
00651
00652
00653
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
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
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
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
00775 dprintf(4, "loadDNG: Thumbnail data found in IFD0\n");
00776 thumbIfd = dng.ifds(0);
00777 } else {
00778
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
00799
00800
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
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
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
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
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
00908 entry = dng.ifds(0)->find(DNG_TAG_DNGPrivateData);
00909 if (entry) {
00910 std::string &privateString = entry->value();
00911
00912 int preambleEnd = privateString.find((char)0);
00913 std::string preamble = privateString.substr(0,preambleEnd);
00914 if (preamble == privateDataPreamble) {
00915
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
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 }