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
00476 privateData >> val;
00477 _f->dng.illuminant2 = val;
00478 privateData >> val;
00479 for (int i=0; i < 12 ; i++) {
00480 _f->dng.colorMatrix2[i] = val.asFloatVector()[i];
00481 }
00482
00483
00484 TagValue key;
00485 while ((privateData >> key).good()) {
00486 privateData >> val;
00487 _f->tags[key] = val;
00488 }
00489 }
00490
00491 void loadDNGPrivateData_v2(_DNGFrame *_f, std::stringstream &privateData) {
00492
00493
00494 TagValue key, val;
00495 while ((privateData >> key).good()) {
00496 privateData >> val;
00497 _f->tags[key] = val;
00498 }
00499
00500
00501
00502 TagMap::iterator it;
00503
00504 #define grabField(fieldName, fieldDest, asType) \
00505 do { \
00506 it = _f->tags.find(fieldName); \
00507 if ( it != _f->tags.end()) { \
00508 fieldDest = it->second.asType; \
00509 _f->tags.erase(it); \
00510 } \
00511 } while(0)
00512
00513 grabField("frame.exposureStartTime", _f->exposureStartTime, asTime());
00514 grabField("frame.exposureEndTime", _f->exposureEndTime, asTime());
00515
00516 grabField("frame.processingDoneTime", _f->processingDoneTime, asTime());
00517 grabField("frame.exposure", _f->exposure, asInt());
00518 grabField("frame.frameTime", _f->frameTime, asInt());
00519 grabField("frame.gain", _f->gain, asFloat());
00520
00521 grabField("frame.whiteBalance", _f->whiteBalance, asInt());
00522
00523 grabField("frame.shot.exposure", _f->_shot.exposure, asInt());
00524 grabField("frame.shot.frameTime", _f->_shot.frameTime, asInt());
00525 grabField("frame.shot.gain", _f->_shot.gain, asFloat());
00526
00527 grabField("frame.shot.whiteBalance", _f->_shot.whiteBalance, asInt());
00528
00529 std::vector<float> cMatrix;
00530 grabField("frame.shot.colorMatrix", cMatrix, asFloatVector());
00531 _f->_shot.setColorMatrix(cMatrix);
00532
00533 grabField("frame.platform.minRawValue", _f->dng.minRawValue, asInt());
00534 grabField("frame.platform.maxRawValue", _f->dng.maxRawValue, asInt());
00535
00536 _f->dng.numIlluminants = 2;
00537 grabField("frame.illuminant1", _f->dng.illuminant1, asInt());
00538 grabField("frame.illuminant2", _f->dng.illuminant2, asInt());
00539
00540 it = _f->tags.find("frame.colorMatrix1");
00541 if (it != _f->tags.end()) {
00542 for (int i=0; i < 12; i++) {
00543 _f->dng.colorMatrix1[i] = it->second.asFloatVector()[i];
00544 }
00545 _f->tags.erase(it);
00546 }
00547
00548 it = _f->tags.find("frame.colorMatrix2");
00549 if (it != _f->tags.end()) {
00550 for (int i=0; i < 12; i++) {
00551 _f->dng.colorMatrix2[i] = it->second.asFloatVector()[i];
00552 }
00553 _f->tags.erase(it);
00554 }
00555
00556
00557 }
00558
00559
00560 DNGFrame loadDNG(const std::string &filename) {
00561
00562 _DNGFrame *_f = new _DNGFrame;
00563 DNGFrame f(_f);
00564
00565 TiffFile &dng = *(_f->dngFile);
00566
00567
00568 dng.readFrom(filename);
00569
00570 if (!dng.valid) {
00571
00572
00573 Event err = dng.lastEvent;
00574 DNGFrame nullF;
00575 err.creator = nullF;
00576 postEvent(err);
00577 return nullF;
00578 }
00579
00580
00581 #define fatalError(...) do { \
00582 DNGFrame nullF; \
00583 error(Event::FileLoadError, nullF, __VA_ARGS__); \
00584 return nullF; } while(0)
00585
00586
00587
00588
00589 const TiffIfdEntry *versionEntry, *backVersionEntry;
00590
00591 versionEntry = dng.ifds(0)->find(DNG_TAG_DNGVersion);
00592 if (!versionEntry) { fatalError("loadDNG: File %s is not a valid DNG file (no DNG version found)", filename.c_str()); }
00593
00594 std::string ver(versionEntry->value());
00595 dprintf(4, "loadDNG: DNG file version is %d.%d.%d.%d.\n", ver[0],ver[1],ver[2],ver[3]);
00596
00597 backVersionEntry = dng.ifds(0)->find(DNG_TAG_DNGBackwardVersion);
00598 if (!backVersionEntry) {
00599
00600 ver = (std::string)backVersionEntry->value();
00601 ver[2] = 0;
00602 ver[3] = 0;
00603 } else {
00604
00605 ver = (std::string)backVersionEntry->value();
00606 }
00607 dprintf(4, "loadDNG: DNG file backward version is %d.%d.%d.%d.\n", ver[0], ver[1], ver[2], ver[3]);
00608
00609 if ((understoodDNGVersion[0] < ver[0]) ||
00610 ((understoodDNGVersion[0] == ver[0]) && (understoodDNGVersion[1] < ver[1])) ||
00611 ((understoodDNGVersion[1] == ver[1]) && (understoodDNGVersion[2] < ver[2])) ||
00612 ((understoodDNGVersion[2] == ver[2]) && (understoodDNGVersion[3] < ver[3]))) {
00613 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]);
00614 }
00615
00616
00617
00618
00619 const TiffIfdEntry *entry;
00620 entry = dng.ifds(0)->find(TIFF_TAG_NewSubFileType);
00621 int ifdType = TIFF_NewSubfileType_DEFAULT;
00622 if (entry) {
00623 ifdType = entry->value();
00624 }
00625
00626 TiffIfd *rawIfd = NULL;
00627 if (ifdType == (int)TIFF_NewSubfileType_FullRAW) {
00628
00629 dprintf(4, "loadDNG: RAW data found in IFD0\n");
00630 rawIfd = dng.ifds(0);
00631 } else {
00632
00633 for (size_t i=0; i < dng.ifds(0)->subIfds().size(); i++) {
00634 ifdType = TIFF_NewSubfileType_DEFAULT;
00635 entry = dng.ifds(0)->subIfds(i)->find(TIFF_TAG_NewSubFileType);
00636 if (entry) {
00637 ifdType = entry->value();
00638 }
00639 if (ifdType == (int)TIFF_NewSubfileType_FullRAW) {
00640 dprintf(4, "loadDNG: RAW data found in subIFD %d\n", i);
00641 rawIfd = dng.ifds(0)->subIfds(i);
00642 break;
00643 }
00644 }
00645 if (!rawIfd) { fatalError("loadDNG: %s: Can't find RAW data!", filename.c_str()); }
00646 }
00647
00648
00649
00650 _f->image = rawIfd->getImage();
00651
00652
00653
00654
00655
00656 entry = rawIfd->find(TIFFEP_TAG_CFARepeatPatternDim);
00657 if (!entry) { fatalError("loadDNG: %s: No CFA pattern dimensions tag found."); }
00658 BayerPattern bayer;
00659 {
00660 std::vector<int> &cfaRepeatPatternDim = entry->value();
00661 if (cfaRepeatPatternDim[0] != 2 ||
00662 cfaRepeatPatternDim[1] != 2) { fatalError("loadDNG: %s: CFA pattern dimensions not 2x2 (%d x %d). Unsupported.\n", filename.c_str()); }
00663
00664 entry = rawIfd->find(TIFFEP_TAG_CFAPattern);
00665 if (!entry) { fatalError("loadDNG: %s: No CFA pattern tag found."); }
00666 std::string cfaPattern = entry->value();
00667 if (cfaPattern.size() != 4) { fatalError("loadDNG: %s: CFA pattern entry incorrect\n", filename.c_str()); }
00668 if (cfaPattern[0] == TIFFEP_CFAPattern_RGGB[0] &&
00669 cfaPattern[1] == TIFFEP_CFAPattern_RGGB[1] &&
00670 cfaPattern[2] == TIFFEP_CFAPattern_RGGB[2] &&
00671 cfaPattern[3] == TIFFEP_CFAPattern_RGGB[3]) {
00672 bayer = RGGB;
00673 } else if (cfaPattern[0] == TIFFEP_CFAPattern_BGGR[0] &&
00674 cfaPattern[1] == TIFFEP_CFAPattern_BGGR[1] &&
00675 cfaPattern[2] == TIFFEP_CFAPattern_BGGR[2] &&
00676 cfaPattern[3] == TIFFEP_CFAPattern_BGGR[3]) {
00677 bayer = BGGR;
00678 } else if (cfaPattern[0] == TIFFEP_CFAPattern_GRBG[0] &&
00679 cfaPattern[1] == TIFFEP_CFAPattern_GRBG[1] &&
00680 cfaPattern[2] == TIFFEP_CFAPattern_GRBG[2] &&
00681 cfaPattern[3] == TIFFEP_CFAPattern_GRBG[3]) {
00682 bayer = GRBG;
00683 } else if (cfaPattern[0] == TIFFEP_CFAPattern_GBRG[0] &&
00684 cfaPattern[1] == TIFFEP_CFAPattern_GBRG[1] &&
00685 cfaPattern[2] == TIFFEP_CFAPattern_GBRG[2] &&
00686 cfaPattern[3] == TIFFEP_CFAPattern_GBRG[3]) {
00687 bayer = GBRG;
00688 } else {
00689 fatalError("loadDNG: %s: Unsupported CFA pattern: %d %d %d %d\n", filename.c_str(), cfaPattern[0], cfaPattern[1], cfaPattern[2], cfaPattern[3]);
00690 }
00691 dprintf(4,"loadDNG: %s: CFA pattern is type %d\n", filename.c_str(), bayer);
00692 }
00693
00694
00695 entry = rawIfd->find(DNG_TAG_BlackLevelRepeatDim);
00696 uint16_t blackLevelRepeatRows = 1;
00697 uint16_t blackLevelRepeatCols = 1;
00698 if (entry) {
00699 std::vector<int> &blackLevelDims = entry->value();
00700 blackLevelRepeatRows = blackLevelDims[0];
00701 blackLevelRepeatCols = blackLevelDims[1];
00702 }
00703 if (!((blackLevelRepeatRows == 1 && blackLevelRepeatCols == 1)
00704 || (blackLevelRepeatRows == 2 && blackLevelRepeatCols == 2))) {
00705 fatalError("loadDNG: %s: Black level pattern size is unsupported: %d x %d (only support 1x1 or 2x2)",
00706 filename.c_str(), blackLevelRepeatRows, blackLevelRepeatCols);
00707 }
00708
00709 entry = rawIfd->find(DNG_TAG_BlackLevel);
00710 uint16_t blackLevel[3] = {0,0,0};
00711 if (entry) {
00712 if (entry->value().type == TagValue::Int) {
00713 if (blackLevelRepeatRows != 1) {
00714 fatalError("loadDNG: %s: Mismatched entry count between BlackLevelRepeatDim and BlackLevel",
00715 filename.c_str());
00716 }
00717 blackLevel[0] = (int)entry->value();
00718 blackLevel[1] = (int)entry->value();
00719 blackLevel[2] = (int)entry->value();
00720 } else if (entry->value().type == TagValue::IntVector) {
00721 std::vector<int> &blackLevelTag = entry->value();
00722 if (blackLevelRepeatRows != 2 ||
00723 blackLevelTag.size() != 4) {
00724 fatalError("loadDNG: %s: Mismatched entry count between BlackLevelRepeatDim and BlackLevel",
00725 filename.c_str());
00726 }
00727 switch (bayer) {
00728 case RGGB:
00729 blackLevel[0] = (int)blackLevelTag[0];
00730 blackLevel[1] = (int)(blackLevelTag[1] + blackLevelTag[2])/2;
00731 blackLevel[2] = (int)blackLevelTag[3];
00732 break;
00733 case BGGR:
00734 blackLevel[0] = blackLevelTag[3];
00735 blackLevel[1] = (blackLevelTag[1] + blackLevelTag[2])/2;
00736 blackLevel[2] = blackLevelTag[0];
00737 break;
00738 case GRBG:
00739 blackLevel[0] = blackLevelTag[1];
00740 blackLevel[1] = (blackLevelTag[0] + blackLevelTag[3])/2;
00741 blackLevel[2] = blackLevelTag[2];
00742 break;
00743 case GBRG:
00744 blackLevel[0] = blackLevelTag[2];
00745 blackLevel[1] = (blackLevelTag[0] + blackLevelTag[3])/2;
00746 blackLevel[2] = blackLevelTag[1];
00747 break;
00748 default:
00749 fatalError("loadDNG: %s: Unexpected Bayer value (should already have been validated)!", filename.c_str());
00750 };
00751 } else {
00752 fatalError("loadDNG: %s: Unexpected type of black level tag found", filename.c_str());
00753 }
00754 }
00755 dprintf(4,"loadDNG: %s: Black levels are %d, %d, %d\n", filename.c_str(), blackLevel[0], blackLevel[1], blackLevel[2]);
00756
00757
00758 entry = rawIfd->find(DNG_TAG_WhiteLevel);
00759 uint16_t whiteLevel = 65535;
00760 if (entry) {
00761 whiteLevel = (int)entry->value();
00762 }
00763 dprintf(4,"loadDNG: %s: White level is %d\n", filename.c_str(), whiteLevel);
00764
00765
00766
00767 TiffIfd *thumbIfd = NULL;
00768
00769 entry = dng.ifds(0)->find(TIFF_TAG_NewSubFileType);
00770 ifdType = TIFF_NewSubfileType_DEFAULT;
00771 if (entry) {
00772 ifdType = entry->value();
00773 }
00774
00775 if (ifdType == (int)TIFF_NewSubfileType_MainPreview) {
00776
00777 dprintf(4, "loadDNG: Thumbnail data found in IFD0\n");
00778 thumbIfd = dng.ifds(0);
00779 } else {
00780
00781 for (size_t i=0; i < dng.ifds(0)->subIfds().size(); i++) {
00782 ifdType = TIFF_NewSubfileType_DEFAULT;
00783 entry = dng.ifds(0)->subIfds(i)->find(TIFF_TAG_NewSubFileType);
00784 if (entry) {
00785 ifdType = entry->value();
00786 }
00787 if (ifdType == (int)TIFF_NewSubfileType_MainPreview) {
00788 dprintf(4, "loadDNG: Thumbnail data found in subIFD %d\n", i);
00789 thumbIfd = dng.ifds(0)->subIfds(i);
00790 break;
00791 }
00792 }
00793 }
00794
00795 if (thumbIfd) {
00796 _f->thumbnail = thumbIfd->getImage();
00797 }
00798
00799
00800
00801
00802
00803 entry = dng.ifds(0)->find(TIFF_TAG_Orientation);
00804 if (!entry) { fatalError("loadDNG: %s: No orientation entry found", filename.c_str()); }
00805 int orientation = entry->value();
00806
00807 if (orientation != TIFF_Orientation_TopLeft) { fatalError("loadDNG: %s: Unsupported orientation value %d", filename.c_str(), orientation); }
00808
00809
00810 entry = dng.ifds(0)->find(DNG_TAG_CalibrationIlluminant1);
00811 unsigned int calibIlluminant1 = 0;
00812 if (entry) { calibIlluminant1 = (int)entry->value(); }
00813 if (calibIlluminant1 >= DNG_CalibrationIlluminant_Values) { calibIlluminant1 = DNG_CalibrationIlluminant_Values - 1; }
00814
00815 int calibTemp1 = DNG_CalibrationIlluminant_Temp[calibIlluminant1];
00816 dprintf(4,"loadDNG: %s: Calibration illuminant #1 is type %d (%d K)\n", filename.c_str(), calibIlluminant1, calibTemp1);
00817
00818 std::vector<float> camToRGBMatrix1(9);
00819 std::vector<float> rgbBlackLevel1(3);
00820 {
00821 entry = dng.ifds(0)->find(DNG_TAG_ColorMatrix1);
00822 if (!entry) { fatalError("loadDNG: %s: No color calibration matrix found in IFD0", filename.c_str()); }
00823
00824 std::vector<double> &xyzToCamMatrix1 = entry->value();
00825
00826 std::vector<float> rgbToCamMatrix1(9);
00827
00828 for (int i=0; i<3; i++) {
00829 for (int j=0; j<3; j++) {
00830 for (int k=0; k<3; k++) {
00831 rgbToCamMatrix1[i*3+j] += RGBtoXYZ[i*3+k]*xyzToCamMatrix1[k*3+j];
00832 }
00833 }
00834 }
00835 invert3x3(&rgbToCamMatrix1[0], &camToRGBMatrix1[0]);
00836 for (int i=0; i<3; i++) {
00837 for (int j=0; j<3; j++) {
00838 rgbBlackLevel1[i] += camToRGBMatrix1[i*3+j]*(-blackLevel[j]);
00839 }
00840 }
00841 }
00842
00843 entry = dng.ifds(0)->find(DNG_TAG_CalibrationIlluminant2);
00844 int numCalibIlluminants = 1;
00845 int calibTemp2 = -1;
00846 std::vector<float> camToRGBMatrix2(9);
00847 std::vector<float> rgbBlackLevel2(3);
00848 if (entry) {
00849 numCalibIlluminants = 2;
00850 unsigned int calibIlluminant2 = (int)entry->value();
00851 if (calibIlluminant2 >= DNG_CalibrationIlluminant_Values) { calibIlluminant2 = DNG_CalibrationIlluminant_Values - 1; }
00852
00853 calibTemp2 = DNG_CalibrationIlluminant_Temp[calibIlluminant2];
00854 dprintf(4,"loadDNG: %s: Calibration illuminant #2 is type %d (%d K)\n", filename.c_str(), calibIlluminant2, calibTemp2);
00855
00856 entry = dng.ifds(0)->find(DNG_TAG_ColorMatrix2);
00857 if (!entry) { fatalError("loadDNG: %s: No color matrix found for second calibration illuminant", filename.c_str()); }
00858
00859 std::vector<double> &xyzToCamMatrix2 = entry->value();
00860
00861 std::vector<float> rgbToCamMatrix2(9);
00862 for (int i=0; i<3; i++) {
00863 for (int j=0; j<3; j++) {
00864 for (int k=0; k<3; k++) {
00865 rgbToCamMatrix2[i*3+j] += RGBtoXYZ[i*3+k]*xyzToCamMatrix2[k*3+j];
00866 }
00867 }
00868 }
00869 invert3x3(&rgbToCamMatrix2[0], &camToRGBMatrix2[0]);
00870 for (int i=0; i<3; i++) {
00871 for (int j=0; j<3; j++) {
00872 rgbBlackLevel2[i] += camToRGBMatrix2[i*3+j]*(-blackLevel[j]);
00873 }
00874 }
00875
00876 }
00877
00878
00879 entry = dng.ifds(0)->find(TIFF_TAG_Model);
00880 std::string cameraModel = "Unknown";
00881 if (entry) { cameraModel = (std::string)entry->value(); }
00882 dprintf(4,"loadDNG: %s: Camera model is %s\n", filename.c_str(), cameraModel.c_str());
00883
00884
00885 entry = dng.ifds(0)->find(TIFF_TAG_Make);
00886 std::string cameraManufacturer = "Unknown";
00887 if (entry) { cameraManufacturer = (std::string)entry->value(); }
00888 dprintf(4,"loadDNG: %s: Camera manufacturer is %s\n", filename.c_str(), cameraManufacturer.c_str());
00889
00890 #undef fatalError
00891
00892
00893 _f->dng.minRawValue = std::min(blackLevel[0], std::min(blackLevel[1], blackLevel[2]));
00894 _f->dng.maxRawValue = whiteLevel;
00895 _f->dng.numIlluminants = numCalibIlluminants;
00896 _f->dng.illuminant1 = calibTemp1;
00897 _f->dng.illuminant2 = calibTemp2;
00898 for (int i=0; i < 3; i++) {
00899 for (int j=0; j < 3; j++) {
00900 _f->dng.colorMatrix1[i*4+j] = camToRGBMatrix1[i*3+j];
00901 _f->dng.colorMatrix2[i*4+j] = camToRGBMatrix2[i*3+j];
00902 }
00903 }
00904 for (int i=0; i < 3; i++) {
00905 _f->dng.colorMatrix1[i*4+3] = rgbBlackLevel1[i];
00906 _f->dng.colorMatrix2[i*4+3] = rgbBlackLevel2[i];
00907 }
00908
00909
00910 entry = dng.ifds(0)->find(DNG_TAG_DNGPrivateData);
00911 if (entry) {
00912 std::string &privateString = entry->value();
00913
00914 int preambleEnd = privateString.find((char)0);
00915 std::string preamble = privateString.substr(0,preambleEnd);
00916 if (preamble == privateDataPreamble) {
00917
00918 std::stringstream privateData(privateString.substr(preambleEnd+1));
00919 TagValue version;
00920 privateData >> version;
00921
00922 if (version.asInt() == 1) {
00923 dprintf(4,"loadDNG: %s: Reading private data, version 1.\n", filename.c_str());
00924 loadDNGPrivateData_v1(_f, privateData);
00925 } else {
00926 TagValue backwardVersion;
00927 privateData >> backwardVersion;
00928 switch (backwardVersion.asInt()) {
00929 case 2:
00930 dprintf(4,"loadDNG: %s: Reading private data, version 2.\n", filename.c_str());
00931 loadDNGPrivateData_v2(_f, privateData);
00932 break;
00933 default:
00934 warning(Event::FileLoadError,
00935 "loadDNG: %s: Private data version too new: %d,%d (can handle X, %d), ignoring it.",
00936 filename.c_str(), version.asInt(), backwardVersion.asInt(), privateDataVersion);
00937 }
00938 }
00939 } else {
00940 warning(Event::FileLoadError,
00941 "loadDNG: %s: Private data preamble doesn't match FCam's: '%s' (expecting '%s'), ignoring it.",
00942 filename.c_str(), preamble.c_str(), privateDataPreamble);
00943 }
00944 }
00945
00946
00947 _f->dng.bayerPattern = bayer;
00948 _f->dng.manufacturer = cameraManufacturer;
00949 _f->dng.model = cameraModel;
00950
00951 dprintf(4,"loadDNG: %s: Loaded successfully\n", filename.c_str());
00952 return f;
00953 }
00954
00955 }