diff --git a/rtdata/languages/default b/rtdata/languages/default index f0fb042e5..acd69a349 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -472,6 +472,7 @@ PREFERENCES_INTENT_RELATIVE;Relative Colorimetric PREFERENCES_INTENT_SATURATION;Saturation PREFERENCES_LINEDENOISE;Line noise filter PREFERENCES_LIVETHUMBNAILS;Live Thumbnails (slower) +PREFERENCES_METADATA;Metadata PREFERENCES_MONITORICC;Monitor Profile PREFERENCES_MULTITAB;Multiple tabs mode PREFERENCES_MULTITABDUALMON;Multiple tabs mode, if available on second monitor @@ -490,10 +491,10 @@ PREFERENCES_PARSEDEXTDELHINT;Delete selected extension from the list PREFERENCES_PRESER;Exposure before interpolation\n :preserve highlights (EV) PREFERENCES_PROFILEHANDLING;Processing Profile Handling PREFERENCES_PROFILELOADPR;Profile Loading Priority -PREFERENCES_PROFILEPRCACHE;Profile in Cache -PREFERENCES_PROFILEPRFILE;Profile Next to the Input File -PREFERENCES_PROFILESAVECACHE;Save Processing Parameters to the Cache -PREFERENCES_PROFILESAVEINPUT;Save Processing Parameters Next to the Input File +PREFERENCES_PROFILEPRCACHE;Profile in cache +PREFERENCES_PROFILEPRFILE;Profile next to the input file +PREFERENCES_PROFILESAVECACHE;Save processing parameters to the cache +PREFERENCES_PROFILESAVEINPUT;Save processing parameters next to the input file PREFERENCES_PROPERTY;Property PREFERENCES_PSPATH;Adobe Photoshop installation directory PREFERENCES_SELECTFONT;Select font @@ -520,6 +521,7 @@ PREFERENCES_TAB_IMPROC;Image Processing PREFERENCES_TAB_OUTPUT;Output Options PREFERENCES_TAB_SOUND;Sounds PREFERENCES_THUMBSIZE;Thumbnail Size +PREFERENCES_TUNNELMETADATA;Tunnel IPTC/XMP unchanged to output file PREFERENCES_USESYSTEMTHEME; Use System Theme PREFERENCES_WORKFLOW;Workflow PROFILEPANEL_FILEDLGFILTERANY;Any files diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 216831c52..41ab400c8 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -45,6 +45,22 @@ using namespace rtengine::procparams; Glib::ustring ImageIO::errorMsg[6] = {"Success", "Cannot read file.", "Invalid header.","Error while reading header.","File reading error", "Image format not supported."}; +// For only copying the raw input data +void ImageIO::setMetadata (const rtexif::TagDirectory* eroot) { + if (exifRoot!=NULL) { delete exifRoot; exifRoot = NULL; } + + if (eroot) { + rtexif::TagDirectory* td = ((rtexif::TagDirectory*)eroot)->clone (NULL); + + // make IPTC and XMP pass through + td->keepTag(0x83bb); // IPTC + td->keepTag(0x02bc); // XMP + + exifRoot=td; + } +} + +// For merging with RT specific data void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const std::vector& exif, const std::vector& iptcc) { // store exif info @@ -53,15 +69,13 @@ void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const std::vector< exifChange[i].first = exif[i].field; exifChange[i].second = exif[i].value; } - delete exifRoot; - exifRoot = NULL; + if (exifRoot!=NULL) { delete exifRoot; exifRoot = NULL; } + if (eroot) exifRoot = ((rtexif::TagDirectory*)eroot)->clone (NULL); - if (iptc) - iptc_data_free (iptc); - iptc = NULL; + if (iptc!=NULL) { iptc_data_free (iptc); iptc = NULL; } // build iptc structures for libiptcdata if (iptcc.size()==0) diff --git a/rtengine/imageio.h b/rtengine/imageio.h index df0414165..ee4241bf2 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -82,6 +82,7 @@ class ImageIO { cmsHPROFILE getEmbeddedProfile () { return embProfile; } void getEmbeddedProfileData (int& length, unsigned char*& pdata) { length = loadedProfileLength; pdata = (unsigned char*)loadedProfileData; } + void setMetadata (const rtexif::TagDirectory* eroot); void setMetadata (const rtexif::TagDirectory* eroot, const std::vector& exif, const std::vector& iptcc); void setOutputProfile (char* pdata, int plen); Glib::Mutex& mutex () { return imutex; } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 17b7a5537..11488562f 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -348,8 +348,9 @@ namespace rtengine { * @param job the ProcessingJob to cancel. * @param errorCode is the error code if an error occured (e.g. the input image could not be loaded etc.) * @param pl is an optional ProgressListener if you want to keep track of the progress + * @param tunnelMetaData tunnels IPTC and XMP to output without change * @return the resulting image, with the output profile applied, exif and iptc data set. You have to save it or you can access the pixel data directly. */ - IImage16* processImage (ProcessingJob* job, int& errorCode, ProgressListener* pl = NULL); + IImage16* processImage (ProcessingJob* job, int& errorCode, ProgressListener* pl = NULL, bool tunnelMetaData=false); /** This class is used to control the batch processing. The class implementing this interface will be called when the full processing of an * image is ready and the next job to process is needed. */ @@ -366,8 +367,9 @@ namespace rtengine { * with processing. If no new job is given, it finishes. * The ProcessingJob passed becomes invalid, you can not use it any more. * @param job the ProcessingJob to cancel. - * @param bpl is the BatchProcessingListener that is called when the image is ready or the next job is needed. It also acts as a ProgressListener. */ - void startBatchProcessing (ProcessingJob* job, BatchProcessingListener* bpl); + * @param bpl is the BatchProcessingListener that is called when the image is ready or the next job is needed. It also acts as a ProgressListener. + * @param tunnelMetaData tunnels IPTC and XMP to output without change */ + void startBatchProcessing (ProcessingJob* job, BatchProcessingListener* bpl, bool tunnelMetaData); extern Glib::Mutex* lcmsMutex; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 3428acc9f..23580eaea 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -2,6 +2,7 @@ * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath + * Copyright (c) 2010 Oliver Duis * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,7 +32,8 @@ namespace rtengine { -IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* pl) { +// tunnelMetaData copies IPTC and XMP untouched to output +IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* pl, bool tunnelMetaData) { errorCode = 0; @@ -275,12 +277,14 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p } } + if (tunnelMetaData) + readyImg->setMetadata (ii->getMetaData()->getExifData ()); + else + readyImg->setMetadata (ii->getMetaData()->getExifData (), params.exif, params.iptc); if (pl) pl->setProgress (1.0); - readyImg->setMetadata (ii->getMetaData()->getExifData (), params.exif, params.iptc); - ProfileContent pc; if (params.icm.output.compare (0, 6, "No ICM") && params.icm.output!="") pc = iccStore->getContent (params.icm.output); @@ -302,23 +306,23 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p return readyImg; } -void batchProcessingThread (ProcessingJob* job, BatchProcessingListener* bpl) { +void batchProcessingThread (ProcessingJob* job, BatchProcessingListener* bpl, bool tunnelMetaData) { ProcessingJob* currentJob = job; while (currentJob) { int errorCode; - IImage16* img = processImage (currentJob, errorCode, bpl); + IImage16* img = processImage (currentJob, errorCode, bpl, tunnelMetaData); if (errorCode) bpl->error ("Can not load input image."); currentJob = bpl->imageReady (img); } } -void startBatchProcessing (ProcessingJob* job, BatchProcessingListener* bpl) { +void startBatchProcessing (ProcessingJob* job, BatchProcessingListener* bpl, bool tunnelMetaData) { if (bpl) - Glib::Thread::create(sigc::bind(sigc::ptr_fun(batchProcessingThread), job, bpl), 0, true, true, Glib::THREAD_PRIORITY_LOW); + Glib::Thread::create(sigc::bind(sigc::ptr_fun(batchProcessingThread), job, bpl, tunnelMetaData), 0, true, true, Glib::THREAD_PRIORITY_LOW); } diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc index be8c03026..2935a7589 100644 --- a/rtexif/rtexif.cc +++ b/rtexif/rtexif.cc @@ -208,6 +208,11 @@ Tag* TagDirectory::findTag (const char* name) const { return NULL; } +void TagDirectory::keepTag (int ID) { + for (int i=0; igetID()==ID) tags[i]->setKeep(true); +} + int TagDirectory::calculateSize () { int size = 2; // space to store the number of tags diff --git a/rtexif/rtexif.h b/rtexif/rtexif.h index fc231b021..b898ac975 100644 --- a/rtexif/rtexif.h +++ b/rtexif/rtexif.h @@ -80,6 +80,8 @@ class TagDirectory { virtual Tag* getTag (const char* name) const; virtual Tag* getTag (int ID) const; virtual Tag* findTag (const char* name) const; + + void keepTag (int ID); virtual void addTag (Tag* a); virtual void addTagFront (Tag* a); virtual void replaceTag (Tag* a); diff --git a/rtexif/stdattribs.cc b/rtexif/stdattribs.cc index 053991c5a..fa97aa0bc 100644 --- a/rtexif/stdattribs.cc +++ b/rtexif/stdattribs.cc @@ -2,6 +2,7 @@ * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath + * Copyright (c) 2010 Oliver Duis * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -374,6 +375,12 @@ public: }; UnitsInterpreter unitsInterpreter; +class UTF8BinInterpreter : public Interpreter { + public: + UTF8BinInterpreter () {} +}; +UTF8BinInterpreter utf8BinInterpreter; + const TagAttrib exifAttribs[] = { {0, 2, 0, 0, 0x0100, "ImageWidth", &stdInterpreter}, {0, 2, 0, 0, 0x0101, "ImageHeight", &stdInterpreter}, @@ -442,7 +449,6 @@ const TagAttrib exifAttribs[] = { {0, 1, 0, 0, 0xA420, "ImageUniqueID", &stdInterpreter}, {0, 1, 0, 0, 0xa432, "LensInfo", &stdInterpreter}, {0, 1, 0, 0, 0xa434, "LensModel", &stdInterpreter}, - {0, 1, 0, 0, 0xc630, "DNGLensInfo", &stdInterpreter}, {-1, 0, 0, 0, 0, "", NULL }}; @@ -517,6 +523,7 @@ const TagAttrib iopAttribs[] = { {0, 2, 0, 0, 0x0212, "YCbCrSubSampling", &stdInterpreter}, {0, 2, 0, 0, 0x0213, "YCbCrPositioning", &stdInterpreter}, {0, 2, 0, 0, 0x0214, "ReferenceBlackWhite", &stdInterpreter}, + {0, 2, 0, 0, 0x02bc, "ApplicationNotes", &utf8BinInterpreter}, // XMP {0, 1, 0, 0, 0x4746, "Rating",&stdInterpreter}, {0, 1, 0, 0, 0x4749, "RatingPercent",&stdInterpreter}, {0, 1, 0, 0, 0x828d, "CFAPatternDim", &stdInterpreter}, @@ -528,8 +535,13 @@ const TagAttrib iopAttribs[] = { {0, 1, 0, gpsAttribs, 0x8825, "GPSInfo", &stdInterpreter}, {0, 1, 0, 0, 0x9003, "DateTimeOriginal", &stdInterpreter}, {0, 1, 0, 0, 0x9004, "DateTimeDigitized", &stdInterpreter}, + {0, 1, 0, 0, 0x9211, "ImageNumber", &stdInterpreter}, {0, 1, 0, iopAttribs, 0xA005, "Interoperability", &stdInterpreter}, {0, 0, 0, 0, 0xC4A5, "PrintIMInformation", &stdInterpreter}, + {0, 1, 0, 0, 0xc62f, "CameraSerialNumber", &stdInterpreter}, + {0, 2, 0, 0, 0xc630, "DNGLensInfo", &stdInterpreter}, + {0, 1, 0, 0, 0xc65d, "RawDataUniqueID", &stdInterpreter}, + {0, 0, 0, 0, 0xc761, "NoiseProfile", &stdInterpreter}, {0, 2, 0, 0, 0x00fe, "NewSubFileType", &stdInterpreter}, {-1, 0, 0, 0, 0, "", NULL}}; diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index f70f9e0f7..f9be902a9 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -281,7 +281,7 @@ void BatchQueue::startProcessing () { // remove button set next->removeButtonSet (); // start batch processing - rtengine::startBatchProcessing (next->job, this); + rtengine::startBatchProcessing (next->job, this, options.tunnelMetaData); queue_draw (); } } diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index bf3f4d91b..1bc71833f 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -900,7 +900,7 @@ void EditorPanel::saveAsPressed () { rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); fname = removeExtension (fname); ProgressConnector *ld = new ProgressConnector(); - ld->startFunc(sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, parent->getProgressListener() ), + ld->startFunc(sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, parent->getProgressListener(), options.tunnelMetaData ), sigc::bind(sigc::mem_fun( *this,&EditorPanel::idle_saveImage ),ld,fname,sf,false )); saveimgas->set_sensitive(false); sendtogimp->set_sensitive(false); @@ -929,7 +929,7 @@ void EditorPanel::sendToGimpPressed () { ipc->getParams (&pparams); rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); ProgressConnector *ld = new ProgressConnector(); - ld->startFunc(sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, parent->getProgressListener() ), + ld->startFunc(sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, parent->getProgressListener(), options.tunnelMetaData ), sigc::bind(sigc::mem_fun( *this,&EditorPanel::idle_sendToGimp ),ld )); saveimgas->set_sensitive(false); sendtogimp->set_sensitive(false); diff --git a/rtgui/main.cc b/rtgui/main.cc index af7acb8ad..3176a9c83 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -349,7 +349,7 @@ int processLineParams( int argc, char **argv ) } // Process image - rtengine::IImage16* resultImage = rtengine::processImage (job, errorCode, NULL); + rtengine::IImage16* resultImage = rtengine::processImage (job, errorCode, NULL, options.tunnelMetaData); if( !resultImage ){ errors++; std::cerr << "Error processing:"<< inputFile << std::endl; diff --git a/rtgui/options.cc b/rtgui/options.cc index afb6a3796..6f2d390d7 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -123,6 +123,7 @@ void Options::setDefaults () { showFileNames = true; tabbedUI = false; multiDisplayMode = 0; + tunnelMetaData = false; cutOverlayBrush = std::vector (4); cutOverlayBrush[3] = 0.667; @@ -214,6 +215,7 @@ if (keyFile.has_group ("Output")) { if (keyFile.has_key ("Output", "UsePathTemplate")) saveUsePathTemplate = keyFile.get_boolean("Output", "UsePathTemplate"); if (keyFile.has_key ("Output", "LastSaveAsPath")) lastSaveAsPath = keyFile.get_string ("Output", "LastSaveAsPath"); if (keyFile.has_key ("Output", "OverwriteOutputFile")) overwriteOutputFile = keyFile.get_boolean("Output", "OverwriteOutputFile"); + if (keyFile.has_key ("Output", "TunnelMetaData")) tunnelMetaData = keyFile.get_boolean("Output", "TunnelMetaData"); } if (keyFile.has_group ("Profiles")) { @@ -387,6 +389,7 @@ int Options::saveToFile (Glib::ustring fname) { keyFile.set_boolean ("Output", "UsePathTemplate", saveUsePathTemplate); keyFile.set_string ("Output", "LastSaveAsPath", lastSaveAsPath); keyFile.set_boolean ("Output", "OverwriteOutputFile", overwriteOutputFile); + keyFile.set_boolean ("Output", "TunnelMetaData", tunnelMetaData); keyFile.set_string ("Profiles", "Directory", profilePath); keyFile.set_string ("Profiles", "RawDefault", defProfRaw); diff --git a/rtgui/options.h b/rtgui/options.h index d2fadbbec..f24cd6894 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -139,7 +139,7 @@ class Options { Glib::ustring sndBatchQueueDone; Glib::ustring sndLngEditProcDone; double sndLngEditProcDoneSecs; // Minimum processing time seconds till the sound is played - + bool tunnelMetaData; // Pass through IPTC and XMP unchanged Options (); diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 760fd266f..ad90d866e 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -286,6 +286,13 @@ Gtk::Widget* Preferences::getProcParamsPanel () { dfconn = darkFrameDir->signal_file_set().connect ( sigc::mem_fun(*this, &Preferences::darkFrameChanged), true); + Gtk::Frame* fmd = Gtk::manage (new Gtk::Frame (M("PREFERENCES_METADATA"))); + Gtk::VBox* vbmd = Gtk::manage (new Gtk::VBox ()); + ckbTunnelMetaData = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_TUNNELMETADATA"))); + vbmd->pack_start (*ckbTunnelMetaData, Gtk::PACK_SHRINK, 4); + fmd->add (*vbmd); + mvbpp->pack_start (*fmd, Gtk::PACK_SHRINK, 4); + return mvbpp; } @@ -816,6 +823,8 @@ void Preferences::storePreferences () { moptions.saveParamsCache = saveParamsCache->get_active (); moptions.paramsLoadLocation = (PPLoadLocation)loadParamsPreference->get_active_row_number (); + moptions.tunnelMetaData = ckbTunnelMetaData->get_active (); + moptions.rtSettings.darkFramesPath = darkFrameDir->get_filename(); int i = 0; @@ -914,6 +923,8 @@ void Preferences::fillPreferences () { saveParamsCache->set_active (moptions.saveParamsCache); loadParamsPreference->set_active (moptions.paramsLoadLocation); + ckbTunnelMetaData->set_active (moptions.tunnelMetaData); + if (!moptions.tabbedUI) editorLayout->set_active(moptions.mainNBVertical ? 1 : 0); else diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 9068d53c6..2c6eead28 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -111,6 +111,8 @@ class Preferences : public Gtk::Dialog { Gtk::Entry* txtSndLngEditProcDone; Gtk::SpinButton* spbSndLngEditProcDoneSecs; + Gtk::CheckButton* ckbTunnelMetaData; + Options moptions; sigc::connection tconn, fconn, usethcon, addc, setc, dfconn; Glib::ustring initialTheme;