From d1ad6a85df549bbe962c038f64f9a1d16560f383 Mon Sep 17 00:00:00 2001 From: Oliver Duis Date: Thu, 7 Apr 2011 17:04:24 +0200 Subject: [PATCH] Merged RTEngine enhancements from DEFAULT --- rtengine/dcrop.cc | 42 ++++++---------- rtengine/dcrop.h | 2 +- rtengine/imageio.cc | 81 +++++++++++++++-------------- rtengine/improccoordinator.cc | 74 +++++---------------------- rtengine/improccoordinator.h | 7 +-- rtengine/rtengine.h | 9 ++-- rtengine/safegtk.cc | 95 +++++++++++++++++++++++------------ rtengine/safegtk.h | 3 ++ rtengine/simpleprocess.cc | 6 +-- 9 files changed, 148 insertions(+), 171 deletions(-) diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 0dd93ea65..0bf949553 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -51,22 +51,22 @@ Crop::~Crop () { } void Crop::setListener (DetailedCropListener* il) { + // We can make reads in the IF, because the mProcessing lock is only needed for change + if (cropImageListener!=il) { - parent->mProcessing.lock(); + Glib::Mutex::Lock lock(cropMutex); cropImageListener = il; - parent->mProcessing.unlock(); +} } -void Crop::update (int todo, bool internal) { - +void Crop::update (int todo) { + Glib::Mutex::Lock lock(cropMutex); + //flag for testing color accuracy bool colortest = false; - if (!internal) - parent->mProcessing.lock (); - ProcParams& params = parent->params; - cropMutex.lock (); + parent->ipf.setScale (skip); @@ -91,9 +91,10 @@ void Crop::update (int todo, bool internal) { if (needsinitupdate) todo = ALL; + /* Seems to be taken care of by calling improccoordinator::updatePreviewImage if( regenHighDetail ) parent->updatePreviewImage (ALL,this); // We have just set skip to 1 - + */ baseCrop = origCrop; bool needstransform = parent->ipf.needsTransform(); @@ -243,11 +244,6 @@ void Crop::update (int todo, bool internal) { delete final; delete finaltrue; } - - cropMutex.unlock (); - - if (!internal) - parent->mProcessing.unlock (); } void Crop::freeAll () { @@ -392,15 +388,9 @@ bool Crop::tryUpdate() { return needsFullUpdate; } +// Full update, should be called via thread void Crop::fullUpdate () { - if (updating) { - needsNext = true; - return; - } - - updating = true; - parent->updaterThreadStart.lock (); if (parent->updaterRunning && parent->thread) { // Do NOT reset changes here, since in a long chain of events it will lead to chroma_scale not being updated, @@ -410,19 +400,19 @@ void Crop::fullUpdate () { } if (parent->plistener) - parent->plistener->setProgressState (1); + parent->plistener->setProgressState (true); needsNext = true; while (needsNext) { needsNext = false; - update (ALL, true); + update (ALL); } updating = false; - if (parent->plistener) - parent->plistener->setProgressState (0); - parent->updaterThreadStart.unlock (); + + if (parent->plistener) + parent->plistener->setProgressState (false); } } diff --git a/rtengine/dcrop.h b/rtengine/dcrop.h index c36a6097c..3e811113e 100644 --- a/rtengine/dcrop.h +++ b/rtengine/dcrop.h @@ -68,7 +68,7 @@ class Crop : public DetailedCrop { ~Crop (); bool hasListener () { return cropImageListener; } - void update (int todo, bool internal=false); + void update (int todo); void setWindow (int cx, int cy, int cw, int ch, int skip) { setCropSizes (cx, cy, cw, ch, skip, false); } bool tryUpdate (); // First try, only make fullUpdate if this returns false diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 0c383d0c7..8eae7ff74 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.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 @@ -45,6 +46,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 +70,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) @@ -136,7 +151,7 @@ int ImageIO::loadPNG (Glib::ustring fname) { return IMIO_CANNOTREADFILE; if (pl) { - pl->setProgressStr ("Loading PNG file..."); + pl->setProgressStr ("PROGRESSBAR_LOADPNG"); pl->setProgress (0.0); } @@ -252,7 +267,7 @@ int ImageIO::loadPNG (Glib::ustring fname) { delete [] row; fclose(file); if (pl) { - pl->setProgressStr ("Ready."); + pl->setProgressStr ("PROGRESSBAR_READY"); pl->setProgress (1.0); } return IMIO_SUCCESS; @@ -269,7 +284,7 @@ int ImageIO::loadJPEGFromMemory (const char* buffer, int bufsize) if ( setjmp(((rt_jpeg_error_mgr*)cinfo.src)->error_jmp_buf) == 0 ) { if (pl) { - pl->setProgressStr ("Loading JPEG file..."); + pl->setProgressStr ("PROGRESSBAR_LOADJPEG"); pl->setProgress (0.0); } @@ -313,7 +328,7 @@ int ImageIO::loadJPEGFromMemory (const char* buffer, int bufsize) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); if (pl) { - pl->setProgressStr ("Ready."); + pl->setProgressStr ("PROGRESSBAR_READY"); pl->setProgress (1.0); } return IMIO_SUCCESS; @@ -340,7 +355,7 @@ int ImageIO::loadJPEG (Glib::ustring fname) { if ( setjmp(((rt_jpeg_error_mgr*)cinfo.src)->error_jmp_buf) == 0 ) { if (pl) { - pl->setProgressStr ("Loading JPEG file..."); + pl->setProgressStr ("PROGRESSBAR_LOADJPEG"); pl->setProgress (0.0); } @@ -385,7 +400,7 @@ int ImageIO::loadJPEG (Glib::ustring fname) { jpeg_destroy_decompress(&cinfo); fclose(file); if (pl) { - pl->setProgressStr ("Ready."); + pl->setProgressStr ("PROGRESSBAR_READY"); pl->setProgress (1.0); } return IMIO_SUCCESS; @@ -409,7 +424,7 @@ int ImageIO::loadTIFF (Glib::ustring fname) { return IMIO_CANNOTREADFILE; if (pl) { - pl->setProgressStr ("Loading TIFF file..."); + pl->setProgressStr ("PROGRESSBAR_LOADTIFF"); pl->setProgress (0.0); } @@ -467,7 +482,7 @@ int ImageIO::loadTIFF (Glib::ustring fname) { delete [] linebuffer; if (pl) { - pl->setProgressStr ("Ready."); + pl->setProgressStr ("PROGRESSBAR_READY"); pl->setProgress (1.0); } @@ -502,17 +517,13 @@ int ImageIO::loadPPMFromMemory(const char* buffer, int width, int height, bool s int ImageIO::savePNG (Glib::ustring fname, int compression, int bps) { - // create a temporary file name that is opened in parallel by e.g. image viewers whilte RT is still writing - Glib::ustring tmpFname=fname; - tmpFname.append(".tmp"); - - FILE *file = safe_g_fopen (tmpFname, "wb"); + FILE *file = safe_g_fopen_WriteBinLock (fname); if (!file) return IMIO_CANNOTREADFILE; if (pl) { - pl->setProgressStr ("Saving PNG file..."); + pl->setProgressStr ("PROGRESSBAR_SAVEPNG"); pl->setProgress (0.0); } @@ -573,11 +584,8 @@ int ImageIO::savePNG (Glib::ustring fname, int compression, int bps) { delete [] row; fclose (file); - // Rename temporary filename, practically atomic - safe_g_rename(tmpFname,fname); - if (pl) { - pl->setProgressStr ("Ready."); + pl->setProgressStr ("PROGRESSBAR_READY"); pl->setProgress (1.0); } @@ -593,17 +601,13 @@ int ImageIO::saveJPEG (Glib::ustring fname, int quality) { cinfo.err = jpeg_std_error (&jerr); jpeg_create_compress (&cinfo); - // create a temporary file name that is opened in parallel by e.g. image viewers whilte RT is still writing - Glib::ustring tmpFname=fname; - tmpFname.append(".tmp"); - - FILE *file = safe_g_fopen (tmpFname, "wb"); + FILE *file = safe_g_fopen_WriteBinLock (fname); if (!file) return IMIO_CANNOTREADFILE; if (pl) { - pl->setProgressStr ("Saving JPEG file..."); + pl->setProgressStr ("PROGRESSBAR_SAVEJPEG"); pl->setProgress (0.0); } @@ -689,11 +693,8 @@ int ImageIO::saveJPEG (Glib::ustring fname, int quality) { fclose (file); - // Rename temporary filename, practically atomic - safe_g_rename(tmpFname,fname); - if (pl) { - pl->setProgressStr ("Ready."); + pl->setProgressStr ("PROGRESSBAR_READY"); pl->setProgress (1.0); } @@ -712,13 +713,13 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) { unsigned char* linebuffer = new unsigned char[lineWidth]; // TODO the following needs to be looked into - do we really need two ways to write a Tiff file ? if (exifRoot && uncompressed) { - FILE *file = safe_g_fopen (fname, "wb"); + FILE *file = safe_g_fopen_WriteBinLock (fname); if (!file) return IMIO_CANNOTREADFILE; if (pl) { - pl->setProgressStr ("Saving TIFF file ..."); + pl->setProgressStr ("PROGRESSBAR_SAVETIFF"); pl->setProgress (0.0); } @@ -771,7 +772,7 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) { return IMIO_CANNOTREADFILE; if (pl) { - pl->setProgressStr ("Saving TIFF file ..."); + pl->setProgressStr ("PROGRESSBAR_SAVETIFF"); pl->setProgress (0.0); } @@ -842,7 +843,7 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) { delete [] linebuffer; if (pl) { - pl->setProgressStr ("Ready."); + pl->setProgressStr ("PROGRESSBAR_READY"); pl->setProgress (1.0); } @@ -885,7 +886,8 @@ void png_flush(png_structp png_ptr) { int ImageIO::load (Glib::ustring fname) { int lastdot = fname.find_last_of ('.'); - + if( Glib::ustring::npos == lastdot ) + return IMIO_FILETYPENOTSUPPORTED; if (!fname.casefold().compare (lastdot, 4, ".png")) return loadPNG (fname); else if (!fname.casefold().compare (lastdot, 4, ".jpg")) @@ -898,7 +900,8 @@ int ImageIO::load (Glib::ustring fname) { int ImageIO::save (Glib::ustring fname) { int lastdot = fname.find_last_of ('.'); - + if( Glib::ustring::npos == lastdot ) + return IMIO_FILETYPENOTSUPPORTED; if (!fname.casefold().compare (lastdot, 4, ".png")) return savePNG (fname); else if (!fname.casefold().compare (lastdot, 4, ".jpg")) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index e2dad292e..aa8529fff 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -83,6 +83,8 @@ DetailedCrop* ImProcCoordinator::createCrop () { return new Crop (this); } +// todo: bitmask containing desired actions, taken from changesSinceLast +// cropCall: calling crop, used to prevent self-updates void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { mProcessing.lock (); @@ -92,6 +94,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { ipf.setScale (scale); + // Check if any detail crops need high detail. If not, take a fast path short cut bool highDetailNeeded=false; for (int i=0; iget_skip() == 1 ){ @@ -109,14 +112,12 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { if ( todo & M_PREPROC) imgsrc->preprocess( rp ); if( todo & M_RAW){ - if( !highDetailNeeded ){ - fineDetailsProcessed = false; - }else - fineDetailsProcessed = true; + fineDetailsProcessed = highDetailNeeded; imgsrc->demosaic( rp ); } if (todo & M_INIT) { - minit.lock (); + Glib::Mutex::Lock lock(minit); + if (settings->verbose) printf ("Applying white balance, color correction & sRBG conversion...\n"); currWB = ColorTemp (params.wb.temperature, params.wb.green); if (params.wb.method=="Camera") @@ -140,15 +141,15 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { imgsrc->getFullSize (fw, fh, tr); PreviewProps pp (0, 0, fw, fh, scale); - setScale (scale, true); + setScale (scale); imgsrc->getImage (currWB, tr, orig_prev, pp, params.hlrecovery, params.icm, params.raw); ipf.firstAnalysis (orig_prev, ¶ms, vhist16, imgsrc->getGamma()); - minit.unlock (); } readyphase++; progress ("Rotate / Distortion...",100*readyphase/numofphases); bool needstransform = ipf.needsTransform(); + // Remove transformation if unneeded if (!needstransform && orig_prev!=oprevi) { delete oprevi; oprevi = orig_prev; @@ -237,7 +238,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { // process crop, if needed for (int i=0; ihasListener () && cropCall != crops[i] ) - crops[i]->update (todo, true); + crops[i]->update (todo); // may call outselves progress ("Conversion to RGB...",100*readyphase/numofphases); if (todo!=CROP) { @@ -249,6 +250,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { catch(char * str) { progress ("Error converting file...",0); + previmg->getMutex().unlock(); mProcessing.unlock (); return; } @@ -304,13 +306,10 @@ void ImProcCoordinator::freeAll () { allocated = false; } -void ImProcCoordinator::setScale (int prevscale, bool internal) { +void ImProcCoordinator::setScale (int prevscale) { if (settings->verbose) printf ("setscale before lock\n"); - if (!internal) - mProcessing.lock (); - tr = TR_NONE; if (params.coarse.rotate==90) tr |= TR_R90; if (params.coarse.rotate==180) tr |= TR_R180; @@ -356,8 +355,6 @@ if (settings->verbose) printf ("setscale before lock\n"); sizeListeners[i]->sizeChanged (fullw, fullh, fw, fh); if (settings->verbose) printf ("setscale ends2\n"); - if (!internal) - mProcessing.unlock (); } @@ -479,51 +476,6 @@ void ImProcCoordinator::getAutoCrop (double ratio, int &x, int &y, int &w, int & mProcessing.unlock (); } -void ImProcCoordinator::fullUpdatePreviewImage () { - - if (destroying) - return; - - updaterThreadStart.lock (); - if (updaterRunning && thread) { - changeSinceLast = 0; - thread->join (); - } - - if (plistener) - plistener->setProgressState (1); - - updatePreviewImage (ALL); - - if (plistener) - plistener->setProgressState (0); - - updaterThreadStart.unlock (); -} - -void ImProcCoordinator::fullUpdateDetailedCrops () { - - if (destroying) - return; - - updaterThreadStart.lock (); - if (updaterRunning && thread) { - changeSinceLast = 0; - thread->join (); - } - - if (plistener) - plistener->setProgressState (1); - - for (int i=0; iupdate (ALL, true); - - if (plistener) - plistener->setProgressState (0); - - updaterThreadStart.unlock (); -} - void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname) { @@ -593,7 +545,7 @@ void ImProcCoordinator::startProcessing () { void ImProcCoordinator::process () { if (plistener) - plistener->setProgressState (1); + plistener->setProgressState (true); paramsUpdateMutex.lock (); while (changeSinceLast) { @@ -609,7 +561,7 @@ void ImProcCoordinator::process () { updaterRunning = false; if (plistener) - plistener->setProgressState (0); + plistener->setProgressState (false); } ProcParams* ImProcCoordinator::getParamsForUpdate (ProcEvent change) { diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 91f49444e..77a7efab4 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -34,6 +34,8 @@ using namespace procparams; class Crop; +// Manages the image processing, espc. of the preview windows +// There is one ImProcCoordinator per edit panel class ImProcCoordinator : public StagedImageProcessor { friend class Crop; @@ -95,7 +97,7 @@ class ImProcCoordinator : public StagedImageProcessor { void progress (Glib::ustring str, int pr); void reallocAll (); void updateHistograms (int x1, int y1, int x2, int y2); - void setScale (int prevscale, bool internal=false); + void setScale (int prevscale); void updatePreviewImage (int todo, Crop* cropCall= NULL); Glib::Mutex mProcessing; @@ -129,8 +131,7 @@ class ImProcCoordinator : public StagedImageProcessor { void setPreviewScale (int scale) { setScale (scale); } int getPreviewScale () { return scale; } - void fullUpdatePreviewImage (); - void fullUpdateDetailedCrops (); + //void fullUpdatePreviewImage (); int getFullWidth () { return fullw; } int getFullHeight () { return fullh; } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 531acfaef..6725109b4 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -105,8 +105,8 @@ namespace rtengine { * @param str is the textual information corresponding to the progress */ virtual void setProgressStr (Glib::ustring str) {} /** This member function is called when the state of the processing has been changed. - * @param state =1 if the processing has been started, =0 if it has been stopped */ - virtual void setProgressState (int state) {} + * @param inProcessing =true if the processing has been started, =false if it has been stopped */ + virtual void setProgressState (bool inProcessing) {} /** This member function is called when an error occurs during the operation. * @param descr is the error message */ virtual void error (Glib::ustring descr) {} @@ -261,10 +261,6 @@ namespace rtengine { /** Returns the scale of the preview image. * @return the current scale of the preview image */ virtual int getPreviewScale () =0; - /** Performs a full update on the preview image. The resulting image is passed to the listener. */ - virtual void fullUpdatePreviewImage () =0; - /** Performs a full update on the detailed crops corresponding to the image. The resulting images are passed to the listeners of the crops. */ - virtual void fullUpdateDetailedCrops () =0; /** Returns the full width of the resulting image (in 1:1 scale). * @return the width of the final image */ virtual int getFullWidth () =0; @@ -354,6 +350,7 @@ 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, bool tunnelMetaData=false); diff --git a/rtengine/safegtk.cc b/rtengine/safegtk.cc index 5cf396ddf..6ba18662e 100644 --- a/rtengine/safegtk.cc +++ b/rtengine/safegtk.cc @@ -22,6 +22,12 @@ #include #include #include +#include +#ifdef WIN32 +#include +#else +#include +#endif Glib::RefPtr safe_create_from_file(const std::string& filename) @@ -113,6 +119,9 @@ void safe_build_subdir_list (Glib::RefPtr &dir, std::vector dirList; if (dir) { + // CD-ROMs with no drive inserted are reported, but do not exist, causing RT to crash + if (!safe_file_test(dir->get_path(),Glib::FILE_TEST_EXISTS)) return; + SAFE_ENUMERATOR_CODE_START if (info->get_file_type() == Gio::FILE_TYPE_DIRECTORY && (!info->is_hidden() || add_hidden)) subDirs.push_back (info->get_name()); @@ -162,27 +171,6 @@ std::string safe_locale_from_utf8 (const Glib::ustring& utf8_str) return str; } -std::string safe_filename_from_utf8 (const Glib::ustring& utf8_str) -{ - std::string str; -#ifdef GLIBMM_EXCEPTIONS_ENABLED - try { - str = Glib::filename_from_utf8 (utf8_str); - } - catch (const Glib::ConvertError& e) { - //str = Glib::convert_with_fallback(utf8_str, "LATIN1", "UTF8", "?"); - } -#else - { - std::auto_ptr error; - str = Glib::filename_from_utf8 (utf8_str, error); - /*if (error.get()) - {str = Glib::convert_with_fallback(utf8_str, "LATIN1", "UTF8", "?", error);}*/ - } -#endif //GLIBMM_EXCEPTIONS_ENABLED - return str; -} - bool safe_spawn_command_line_async (const Glib::ustring& cmd_utf8) { std::string cmd; @@ -190,8 +178,8 @@ bool safe_spawn_command_line_async (const Glib::ustring& cmd_utf8) #ifdef GLIBMM_EXCEPTIONS_ENABLED try { cmd = Glib::filename_from_utf8(cmd_utf8); - printf ("command line: |%s|\n", cmd.c_str()); - Glib::spawn_command_line_async (cmd); + printf ("command line: %s\n", cmd.c_str()); + Glib::spawn_command_line_async (cmd.c_str()); success = true; } catch (Glib::Exception& ex) { printf ("%s\n", ex.what().c_str()); @@ -200,7 +188,7 @@ bool safe_spawn_command_line_async (const Glib::ustring& cmd_utf8) std::auto_ptr error; cmd = Glib::filename_from_utf8(cmd_utf8, error); if (!error.get()) { - printf ("command line: |%s|\n", cmd.c_str()); + printf ("command line: %s\n", cmd.c_str()); Glib::spawn_command_line_async (cmd, error); } if (error.get()) @@ -221,38 +209,81 @@ bool safe_spawn_command_line_sync (const Glib::ustring& cmd_utf8) int exitStatus=-1; try { - cmd = Glib::filename_from_utf8(cmd_utf8); - printf ("command line: |%s|\n", cmd.c_str()); + //cmd = Glib::filename_from_utf8(cmd_utf8); + printf ("command line: %s\n", cmd_utf8.c_str()); // if it crashes here on windows, make sure you have the GTK runtime files gspawn-win32-helper*.exe files in RT directory - Glib::spawn_command_line_sync (cmd,NULL,NULL, &exitStatus); + Glib::spawn_command_line_sync (cmd_utf8, NULL, NULL, &exitStatus); } catch (Glib::Exception& ex) { printf ("%s\n", ex.what().c_str()); } return (exitStatus==0); } +// Opens a file for binary writing and request exclusive lock (cases were you need "wb" mode plus locking) +// (Important on Windows to prevent Explorer to crash RT when parallel scanning e.g. a currently written image file) +FILE * safe_g_fopen_WriteBinLock(const Glib::ustring& fname) { + FILE* f=NULL; + +#ifdef WIN32 + // g_fopen just uses _wfopen internally on Windows, does not lock access and has no options to set this + // so use a native function to work around this problem + wchar_t *wFname = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL); + HANDLE hFile = CreateFileW(wFname, GENERIC_READ | GENERIC_WRITE, 0 /* no sharing allowed */, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + g_free(wFname); + + if (hFile==INVALID_HANDLE_VALUE) + f=NULL; + else + f=_fdopen( _open_osfhandle((intptr_t)hFile, 0) , "wb"); +#else + f = safe_g_fopen(fname, "wb"); +#endif + + return f; +} + +// Covers old UNIX ::open, which expects ANSI instead of UTF8 on Windows +int safe_open_ReadOnly(const char *fname) { + int fd=-1; + +#ifdef WIN32 + // First convert UTF8 to UTF16, then use Windows function to open + wchar_t *wFname = (wchar_t*)g_utf8_to_utf16 (fname, -1, NULL, NULL, NULL); + HANDLE hFile = CreateFileW(wFname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + g_free(wFname); + + // convert back to old file descriptor format + if (hFile!=INVALID_HANDLE_VALUE) fd = _open_osfhandle((intptr_t)hFile, 0); +#else + fd = ::open(fname, O_RDONLY); +#endif + + return fd; +} + + FILE * safe_g_fopen(const Glib::ustring& src,const gchar *mode) { - return g_fopen(safe_filename_from_utf8(src).c_str(),mode); + return g_fopen(src.c_str(),mode); } bool safe_file_test (const Glib::ustring& filename, Glib::FileTest test) { - return Glib::file_test (safe_filename_from_utf8(filename), test); + return Glib::file_test (filename, test); } int safe_g_remove(const Glib::ustring& filename) { - return ::g_remove(safe_filename_from_utf8(filename).c_str()); + return ::g_remove(filename.c_str()); } int safe_g_rename(const Glib::ustring& oldFilename, const Glib::ustring& newFilename) { - return ::g_rename(safe_filename_from_utf8(oldFilename).c_str(), safe_filename_from_utf8(newFilename).c_str()); + return ::g_rename(oldFilename.c_str(), newFilename.c_str()); } int safe_g_mkdir_with_parents(const Glib::ustring& dirName, int mode) { - return ::g_mkdir_with_parents(safe_filename_from_utf8(dirName).c_str(), mode); + return ::g_mkdir_with_parents(dirName.c_str(), mode); } \ No newline at end of file diff --git a/rtengine/safegtk.h b/rtengine/safegtk.h index 73f8dfbad..ae8c597f4 100644 --- a/rtengine/safegtk.h +++ b/rtengine/safegtk.h @@ -31,6 +31,9 @@ std::string safe_locale_from_utf8 (const Glib::ustring& utf8_str); std::string safe_filename_from_utf8 (const Glib::ustring& utf8_str); FILE * safe_g_fopen(const Glib::ustring& src,const gchar *mode); +FILE * safe_g_fopen_WriteBinLock(const Glib::ustring& fname); +int safe_open_ReadOnly(const char *fname); + bool safe_file_test (const Glib::ustring& filename, Glib::FileTest test); int safe_g_remove(const Glib::ustring& filename); int safe_g_rename(const Glib::ustring& oldFilename, const Glib::ustring& newFilename); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index ef7444968..d305b9428 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -275,9 +275,9 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p } - //if (tunnelMetaData) - // readyImg->setMetadata (ii->getMetaData()->getExifData ()); - //else + if (tunnelMetaData) + readyImg->setMetadata (ii->getMetaData()->getExifData ()); + else readyImg->setMetadata (ii->getMetaData()->getExifData (), params.exif, params.iptc);