/* * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RawTherapee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ #include #include #include #include #ifdef RAWZOR_SUPPORT #include #endif #ifndef GLIBMM_EXCEPTIONS_ENABLED #include #endif using namespace rtengine; extern "C" IptcData *iptc_data_new_from_jpeg_file (FILE* infile); ImageMetaData* ImageMetaData::fromFile (const Glib::ustring& fname, RawMetaDataLocation* rml) { return new ImageData (fname, rml); } ImageData::ImageData (Glib::ustring fname, RawMetaDataLocation* ri) { int dotpos = fname.find_last_of ('.'); root = NULL; iptc = NULL; #ifdef RAWZOR_SUPPORT // RAWZOR support begin if (dotposexifBase>=0 || ri->ciffBase>=0)) { FILE* f = g_fopen (fname.c_str (), "rb"); if (f) { fseek (f, 0, SEEK_END); int rzwSize = ftell (f); char* rzwData = new char [rzwSize]; fseek (f, 0, SEEK_SET); fread (rzwData, 1, rzwSize, f); fclose(f); int rawSize; if (!m_rwz_check (rzwData, rzwSize, &rawSize)) { char* rawData = new char [rawSize]; if (!m_rwz_get_meta_only (rzwData, rzwSize, rawData, rawSize)) { std::string tfname; int fd = Glib::file_open_tmp (tfname, ""); FILE* tf = fdopen (fd, "w+b"); fwrite (rawData, 1, rawSize, tf); if (ri->exifBase>=0) root = rtexif::ExifManager::parse (tf, ri->exifBase); else if (ri->ciffBase>=0) root = rtexif::ExifManager::parseCIFF (tf, ri->ciffBase, ri->ciffLength); fclose (tf); ::g_remove (tfname.c_str()); extractInfo (); } delete [] rawData; } delete [] rzwData; } } // RAWZOR support end else #endif if (ri && (ri->exifBase>=0 || ri->ciffBase>=0)) { FILE* f = g_fopen (fname.c_str(), "rb"); if (f) { if (ri->exifBase>=0) { root = rtexif::ExifManager::parse (f, ri->exifBase); if (root) { rtexif::Tag* t = root->getTag (0x83BB); if (t) iptc = iptc_data_new_from_data ((unsigned char*)t->getValue (), (unsigned)t->getValueSize ()); } } else if (ri->ciffBase>=0) root = rtexif::ExifManager::parseCIFF (f, ri->ciffBase, ri->ciffLength); fclose (f); extractInfo (); } } else if (dotpos<(int)fname.size()-3 && !fname.casefold().compare (dotpos, 4, ".jpg")) { FILE* f = g_fopen (fname.c_str (), "rb"); if (f) { root = rtexif::ExifManager::parseJPEG (f); extractInfo (); fclose (f); FILE* ff = g_fopen (fname.c_str (), "rb"); iptc = iptc_data_new_from_jpeg_file (ff); fclose (ff); } } else if ((dotpos<(int)fname.size()-3 && !fname.casefold().compare (dotpos, 4, ".tif")) || (dotposgetTag (0x83BB); if (t) iptc = iptc_data_new_from_data ((unsigned char*)t->getValue (), (unsigned)t->getValueSize ()); } } } else { root = new rtexif::TagDirectory (); shutter = 0; aperture = 0; iso_speed = 0; lens = "Unknown"; make = "Unknown"; model = "Unknown"; focal_len = 0; memset (&time, 0, sizeof(time)); } } void ImageData::extractInfo () { if (!root) return; char buffer[256]; make = ""; model = ""; shutter = 0; aperture = 0; focal_len = 0; iso_speed = 0; memset (&time, 0, sizeof(time)); if (root->getTag ("Make")) make = root->getTag ("Make")->valueToString (); if (root->getTag ("Model")) model = root->getTag ("Model")->valueToString (); rtexif::TagDirectory* exif = NULL; if (root->getTag ("Exif")) exif = root->getTag ("Exif")->getDirectory (); if (exif) { // standard exif tags if (exif->getTag ("ShutterSpeedValue")) shutter = exif->getTag ("ShutterSpeedValue")->toDouble (); if (exif->getTag ("ExposureTime")) shutter = exif->getTag ("ExposureTime")->toDouble (); if (exif->getTag ("ApertureValue")) aperture = exif->getTag ("ApertureValue")->toDouble (); if (exif->getTag ("FNumber")) aperture = exif->getTag ("FNumber")->toDouble (); if (exif->getTag ("FocalLength")) focal_len = exif->getTag ("FocalLength")->toDouble (); if (exif->getTag ("ISOSpeedRatings")) iso_speed = exif->getTag ("ISOSpeedRatings")->toDouble (); if (exif->getTag ("DateTimeOriginal")) { if (sscanf ((const char*)exif->getTag("DateTimeOriginal")->getValue(), "%d:%d:%d %d:%d:%d", &time.tm_year, &time.tm_mon, &time.tm_mday, &time.tm_hour, &time.tm_min, &time.tm_sec) == 6) { time.tm_year -= 1900; time.tm_mon -= 1; } } // guess lens... lens = "Unknown"; // Sometimes (e.g. DNG) EXIF already contains lens data if (exif->getTag ("MakerNote")) { rtexif::TagDirectory* mnote = exif->getTag ("MakerNote")->getDirectory(); if (mnote && !make.compare (0, 5, "NIKON")) { bool lensOk = false; if (mnote->getTag ("LensData")) { std::string ldata = mnote->getTag ("LensData")->valueToString (); int pos; if (ldata.size()>10 && (pos=ldata.find ("Lens = "))!=Glib::ustring::npos) { lens = ldata.substr (pos + 7); if (lens.compare (0, 7, "Unknown")) lensOk = true; } } if (!lensOk && mnote->getTag ("Lens")) { std::string ldata = mnote->getTag ("Lens")->valueToString (); int i=0, j=0; double n[4]; for (int m=0; m<4; m++) { while (igetTag ("LensType")) { std::string ldata = mnote->getTag ("LensType")->valueToString (); if (ldata.size()>1) { lens = ldata; lensOk = true; } } if (!lensOk && mnote->getTag ("CanonCameraSettings")) { std::string ccs = mnote->getTag ("CanonCameraSettings")->valueToString (); int i = ccs.find ("LongFocal = "); double a = 0; if (i!=ccs.npos) { i += 12; int j = i; while (j!=ccs.npos && ccs[j]!='\n' && ccs[j]!=' ') j++; a = atof (ccs.substr (i, j-i).c_str()); } i = ccs.find ("ShortFocal = "); double b = 0; if (i!=ccs.npos) { i += 13; int j = i; while (j!=ccs.npos && ccs[j]!='\n' && ccs[j]!=' ') j++; b = atof (ccs.substr (i, j-i).c_str()); } if (a>0 && b>0) { std::ostringstream str; if (a==b) str << "Unknown " << a << "mm"; else str << "Unknown " << b << "-" << a << "mm"; lens = str.str(); } } } else if (mnote && !make.compare (0, 6, "PENTAX")) { if (mnote->getTag ("LensType")) lens = mnote->getTag ("LensType")->valueToString (); } else if (mnote && (!make.compare (0, 4, "SONY") || !make.compare (0, 6, "KONICA"))) { if (mnote->getTag ("LensID")) lens = mnote->getTag ("LensID")->valueToString (); } else if (mnote && !make.compare (0, 7, "OLYMPUS")) { if (mnote->getTag ("Equipment")) { rtexif::TagDirectory* eq = mnote->getTag ("Equipment")->getDirectory (); if (eq->getTag ("LensType")) lens = eq->getTag ("LensType")->valueToString (); } } } else if (exif->getTag ("DNGLensInfo")) { lens = exif->getTag ("DNGLensInfo")->valueToString (); } if (exif->getTag ("LensModel")) { lens = exif->getTag ("LensModel")->valueToString (); } else if (exif->getTag ("LensInfo")) { lens = exif->getTag ("LensInfo")->valueToString (); } } } ImageData::~ImageData () { delete root; if (iptc) iptc_data_free (iptc); } const std::vector ImageData::getIPTCData () const { std::vector iptcc; if (!iptc) return iptcc; unsigned char buffer[2100]; for (int i=0; i<16; i++) { IptcDataSet* ds = iptc_data_get_next_dataset (iptc, NULL, IPTC_RECORD_APP_2, strTags[i].tag); if (ds) { iptc_dataset_get_data (ds, buffer, 2100); procparams::IPTCPair ic; ic.field = strTags[i].field; ic.values.push_back (safe_locale_to_utf8((char*)buffer)); iptcc.push_back (ic); iptc_dataset_unref (ds); } } IptcDataSet* ds = NULL; procparams::IPTCPair ickw; ickw.field = "Keywords"; while ((ds=iptc_data_get_next_dataset (iptc, ds, IPTC_RECORD_APP_2, IPTC_TAG_KEYWORDS))) { iptc_dataset_get_data (ds, buffer, 2100); ickw.values.push_back (safe_locale_to_utf8((char*)buffer)); } iptcc.push_back (ickw); ds = NULL; procparams::IPTCPair icsc; icsc.field = "SupplementalCategories"; while ((ds=iptc_data_get_next_dataset (iptc, ds, IPTC_RECORD_APP_2, IPTC_TAG_SUPPL_CATEGORY))) { iptc_dataset_get_data (ds, buffer, 2100); icsc.values.push_back (safe_locale_to_utf8((char*)buffer)); iptc_dataset_unref (ds); } iptcc.push_back (icsc); return iptcc; } //------inherited functions--------------// std::string ImageMetaData::apertureToString (double aperture) { char buffer[256]; sprintf (buffer, "%0.1f", aperture); return buffer; } std::string ImageMetaData::shutterToString (double shutter) { char buffer[256]; if (shutter > 0.0 && shutter < 0.9) sprintf (buffer, "1/%0.0f", 1.0 / shutter); else sprintf (buffer, "%0.1f", shutter); return buffer; } double ImageMetaData::shutterFromString (std::string s) { int i = s.find_first_of ('/'); if (i==std::string::npos) return atof (s.c_str()); else return atof (s.substr(0,i).c_str()) / atof (s.substr(i+1).c_str()); } double ImageMetaData::apertureFromString (std::string s) { return atof (s.c_str()); } extern "C" { #include #include struct _IptcDataPrivate { unsigned int ref_count; IptcLog *log; IptcMem *mem; }; IptcData * iptc_data_new_from_jpeg_file (FILE *infile) { IptcData *d; unsigned char * buf; int buf_len = 256*256; int len, offset; unsigned int iptc_len; if (!infile) return NULL; d = iptc_data_new (); if (!d) return NULL; buf = (unsigned char*)iptc_mem_alloc (d->priv->mem, buf_len); if (!buf) { iptc_data_unref (d); return NULL; } len = iptc_jpeg_read_ps3 (infile, buf, buf_len); if (len <= 0) { goto failure; } offset = iptc_jpeg_ps3_find_iptc (buf, len, &iptc_len); if (offset <= 0) { goto failure; } iptc_data_load (d, buf + offset, iptc_len); iptc_mem_free (d->priv->mem, buf); return d; failure: iptc_mem_free (d->priv->mem, buf); iptc_data_unref (d); return NULL; } }