From b25d03e6eafd5902452ace99336db5e6e4620abc Mon Sep 17 00:00:00 2001 From: Steve Herrell Date: Fri, 29 Oct 2010 12:06:17 +0200 Subject: [PATCH] speed up un-cached directories embedded thumbnails will be used for the first pass when cached thumbnails are not found. --- rtengine/CMakeLists.txt | 1 + rtengine/dcraw.cc | 63 +++++++++++++++ rtengine/image16.cc | 17 ++++ rtengine/image16.h | 4 + rtengine/imageio.cc | 69 ++++++++++++++++ rtengine/imageio.h | 2 + rtengine/rtthumbnail.cc | 89 +++++++++++++++++++++ rtengine/rtthumbnail.h | 3 + rtgui/filebrowserentry.cc | 11 ++- rtgui/filebrowserentry.h | 1 + rtgui/filecatalog.cc | 4 + rtgui/thumbbrowserbase.cc | 6 ++ rtgui/thumbbrowserbase.h | 1 + rtgui/thumbbrowserentrybase.h | 1 + rtgui/thumbimageupdater.cc | 32 ++++++-- rtgui/thumbimageupdater.h | 2 +- rtgui/thumbnail.cc | 144 ++++++++++++++++++++++------------ rtgui/thumbnail.h | 6 +- 18 files changed, 397 insertions(+), 59 deletions(-) diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 688c7455e..d8ce097bd 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -13,6 +13,7 @@ set (RTENGINESOURCEFILES colortemp.cc curves.cc dcraw.cc iccstore.cc stdimagesource.cc myfile.cc iccjpeg.c hlmultipliers.cc improccoordinator.cc processingjob.cc rtthumbnail.cc utils.cc labimage.cc iplab2rgb.cc ipsharpen.cc iptransform.cc ipresize.cc + jpeg_memsrc.c wavelet_dec.cc ipequalizer.cc dirpyrLab_denoise.cc dirpyrLab_equalizer.cc dirpyr_equalizer.cc) add_library (rtengine ${RTENGINESOURCEFILES}) diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 2d00ef936..5ddd16e27 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -9144,6 +9144,69 @@ int getRawFileBasicInfo (const Glib::ustring& fname, rtengine::RawMetaDataLocati #include +rtengine::Thumbnail* rtengine::Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh) { + + THREAD_LOCK + + image = NULL; + ifname = fname.c_str(); + exif_base = -1; + ciff_base = -1; + ciff_len = -1; + verbose = settings->verbose; + oprof = NULL; + ifp = gfopen (fname.c_str()); + if (!ifp) { + printf("DCRAW: failed0\n"); + return NULL; + } + + if (setjmp (failure)) { + printf("DCRAW: failed1\n"); + fclose (ifp); + return NULL; + } + + identify (); + if (!is_raw || colors>3) { + printf("DCRAW: failed2\n"); + fclose(ifp); + return NULL; + } + + rml.exifBase = exif_base; + rml.ciffBase = ciff_base; + rml.ciffLength = ciff_len; + + char thumb_buffer[thumb_length]; + fseek(ifp,thumb_offset,SEEK_SET); + fread(thumb_buffer,1,thumb_length,ifp); + fclose(ifp); + + rtengine::Thumbnail* tpp = rtengine::Thumbnail::loadFromMemory(thumb_buffer,thumb_length,w,h,fixwh); + if ( tpp == 0 ) + { + printf("DCRAW: failed3\n"); + return NULL; + } + + int deg = 0; + if (flip==5) + deg = 270; + else if (flip==3) + deg = 180; + else if (flip==6) + deg = 90; + + if (deg>0) { + Image16* rot = tpp->thumbImg->rotate (deg); + delete tpp->thumbImg; + tpp->thumbImg = rot; + } + + return tpp; +} + rtengine::Thumbnail* rtengine::Thumbnail::loadFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh) { THREAD_LOCK diff --git a/rtengine/image16.cc b/rtengine/image16.cc index 1afe0e258..1f6227f98 100644 --- a/rtengine/image16.cc +++ b/rtengine/image16.cc @@ -17,6 +17,7 @@ * along with RawTherapee. If not, see . */ #include +#include #include #include @@ -239,3 +240,19 @@ Image16* Image16::resize (int nw, int nh, TypeInterpolation interp) { } return NULL; } + +Image8* +Image16::to8() const +{ + Image8* img8 = new Image8(width,height); + for ( int h = 0; h < height; ++h ) + { + for ( int w = 0; w < width; ++w ) + { + img8->r(h,w,r[h][w] >> 8); + img8->g(h,w,g[h][w] >> 8); + img8->b(h,w,b[h][w] >> 8); + } + } + return img8; +} diff --git a/rtengine/image16.h b/rtengine/image16.h index 8a778215b..ba719535b 100644 --- a/rtengine/image16.h +++ b/rtengine/image16.h @@ -29,6 +29,8 @@ namespace rtengine { enum TypeInterpolation { TI_Nearest, TI_Bilinear }; +class Image8; + class Image16 : public ImageIO, public IImage16 { private: @@ -54,6 +56,8 @@ class Image16 : public ImageIO, public IImage16 { Image16* copy (); + Image8* to8() const; + Image16* rotate (int deg); Image16* hflip (); Image16* vflip (); diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 59c32ebc5..432fafae2 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -259,6 +259,75 @@ int ImageIO::loadPNG (Glib::ustring fname) { extern jmp_buf jpeg_jmp_buf; +extern "C" { +void jpeg_memory_src (jpeg_decompress_struct* cinfo, const char* buffer, int bufsize); +} + +int ImageIO::loadJPEGFromMemory (const char* buffer, int bufsize) +{ + jpeg_decompress_struct cinfo; + jpeg_error_mgr jerr; + cinfo.err = my_jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + jpeg_memory_src (&cinfo,buffer,bufsize); + + if (pl) { + pl->setProgressStr ("Loading JPEG file..."); + pl->setProgress (0.0); + + } + + setup_read_icc_profile (&cinfo); + + if (!setjmp(jpeg_jmp_buf)) { + jpeg_memory_src (&cinfo,buffer,bufsize); + jpeg_read_header(&cinfo, TRUE); + + unsigned int proflen; + delete loadedProfileData; + loadedProfileData = NULL; + bool hasprofile = read_icc_profile (&cinfo, (JOCTET**)&loadedProfileData, (unsigned int*)&loadedProfileLength); + if (hasprofile) + embProfile = cmsOpenProfileFromMem (loadedProfileData, loadedProfileLength); + else + embProfile = NULL; + + jpeg_start_decompress(&cinfo); + + int width = cinfo.output_width; + int height = cinfo.output_height; + + allocate (width, height); + + unsigned char *row=new unsigned char[width*3]; + while (cinfo.output_scanline < height) { + if (jpeg_read_scanlines(&cinfo,&row,1) < 1) { + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + delete [] row; + return IMIO_READERROR; + } + setScanline (cinfo.output_scanline-1, row, 8); + + if (pl && !(cinfo.output_scanline%100)) + pl->setProgress ((double)(cinfo.output_scanline)/cinfo.output_height); + } + delete [] row; + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + if (pl) { + pl->setProgressStr ("Ready."); + pl->setProgress (1.0); + } + return IMIO_SUCCESS; + } + else { + jpeg_destroy_decompress(&cinfo); + return IMIO_READERROR; + } +} + int ImageIO::loadJPEG (Glib::ustring fname) { FILE *file=g_fopen(fname.c_str(),"rb"); diff --git a/rtengine/imageio.h b/rtengine/imageio.h index 5c7a2a033..a036060b0 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -72,6 +72,8 @@ class ImageIO { int loadJPEG (Glib::ustring fname); int loadTIFF (Glib::ustring fname); + int loadJPEGFromMemory (const char* buffer, int bufsize); + int savePNG (Glib::ustring fname, int compression = -1, int bps = -1); int saveJPEG (Glib::ustring fname, int quality = 100); int saveTIFF (Glib::ustring fname, int bps = -1, bool uncompressed = false); diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 39a6c46ec..43f64539c 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -48,6 +48,62 @@ my_jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile); namespace rtengine { +Thumbnail* Thumbnail::loadFromMemory (const char* image, int length, int &w, int &h, int fixwh) { + Image16* img = new Image16 (); + int err = img->loadJPEGFromMemory(image,length); + if (err) { + printf("loadfromMemory: error\n"); + delete img; + return NULL; + } + + Thumbnail* tpp = new Thumbnail (); + + tpp->camwbRed = 1.0; + tpp->camwbGreen = 1.0; + tpp->camwbBlue = 1.0; + + tpp->embProfileLength = 0; + unsigned char* data; + img->getEmbeddedProfileData (tpp->embProfileLength, data); + if (data && tpp->embProfileLength) { + tpp->embProfileData = new unsigned char [tpp->embProfileLength]; + memcpy (tpp->embProfileData, data, tpp->embProfileLength); + } + else { + tpp->embProfileLength = 0; + tpp->embProfileData = NULL; + } + + tpp->redMultiplier = 1.0; + tpp->greenMultiplier = 1.0; + tpp->blueMultiplier = 1.0; + + tpp->scaleForSave = 8192; + tpp->defGain = 1.0; + tpp->gammaCorrected = false; + tpp->isRaw = 1; + memset (tpp->colorMatrix, 0, sizeof(tpp->colorMatrix)); + tpp->colorMatrix[0][0] = 1.0; + tpp->colorMatrix[1][1] = 1.0; + tpp->colorMatrix[2][2] = 1.0; + + if (fixwh==1) { + w = h * img->width / img->height; + tpp->scale = (double)img->height / h; + } + else { + h = w * img->height / img->width; + tpp->scale = (double)img->width / w; + } + + tpp->thumbImg = img->resize (w, h, TI_Nearest); + delete img; + + tpp->init (); + return tpp; +} + Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh) { Image16* img = new Image16 (); @@ -173,6 +229,39 @@ Thumbnail::~Thumbnail () { cmsCloseProfile(camProfile); } +IImage8* Thumbnail::quickProcessImage (const procparams::ProcParams& params, int rheight, TypeInterpolation interp, double& myscale) { + + int rwidth; + if (params.coarse.rotate==90 || params.coarse.rotate==270) { + rwidth = rheight; + rheight = thumbImg->height * rwidth / thumbImg->width; + } + else + rwidth = thumbImg->width * rheight / thumbImg->height; + Image16* baseImg = thumbImg->resize (rwidth, rheight, interp); + + if (params.coarse.rotate) { + Image16* tmp = baseImg->rotate (params.coarse.rotate); + rwidth = tmp->width; + rheight = tmp->height; + delete baseImg; + baseImg = tmp; + } + if (params.coarse.hflip) { + Image16* tmp = baseImg->hflip (); + delete baseImg; + baseImg = tmp; + } + if (params.coarse.vflip) { + Image16* tmp = baseImg->vflip (); + delete baseImg; + baseImg = tmp; + } + Image8* img8 = baseImg->to8(); + delete baseImg; + return img8; +} + IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rheight, TypeInterpolation interp, double& myscale) { // compute WB multipliers diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index f9b1c9914..438fe2e04 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -70,9 +70,12 @@ namespace rtengine { void init (); IImage8* processImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, double& scale); + IImage8* quickProcessImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, double& scale); int getImageWidth (const procparams::ProcParams& pparams, int rheight); void getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h); + static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh); + static Thumbnail* loadFromMemory (const char* image, int length, int &w, int &h, int fixwh); static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh); static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh); diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc index 50b7a91b9..bbef581b6 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -77,7 +77,16 @@ void FileBrowserEntry::refreshThumbnailImage () { if (!thumbnail) return; - thumbImageUpdater->add (thumbnail, thumbnail->getProcParams(), preh, &updatepriority, this); + thumbImageUpdater->add (thumbnail, thumbnail->getProcParams(), preh, &updatepriority, false, this); +} + +void FileBrowserEntry::refreshQuickThumbnailImage () { + + if ( thumbnail && + thumbnail->isQuick() ) + { + thumbImageUpdater->add(thumbnail, thumbnail->getProcParams(), preh, &updatepriority, true, this); + } } void FileBrowserEntry::calcThumbnailSize () { diff --git a/rtgui/filebrowserentry.h b/rtgui/filebrowserentry.h index 53a1fcf16..490e0d100 100644 --- a/rtgui/filebrowserentry.h +++ b/rtgui/filebrowserentry.h @@ -76,6 +76,7 @@ public: FileThumbnailButtonSet* getThumbButtonSet (); void refreshThumbnailImage (); + void refreshQuickThumbnailImage (); void calcThumbnailSize (); std::vector > getIconsOnImageArea (); diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index ce5f0786e..4d15839f6 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -374,10 +374,14 @@ void FileCatalog::_previewsFinished () { filterPanel->setFilter ( currentEFS,false ); } } + // restart anything that might have been loaded low quality + fileBrowser->refreshQuickThumbImages(); } void FileCatalog::previewsFinished (int dir_id) { + GThreadLock lock; + if ( dir_id != selectedDirectoryId ) { return; diff --git a/rtgui/thumbbrowserbase.cc b/rtgui/thumbbrowserbase.cc index ad464c3a7..cea0bbc83 100644 --- a/rtgui/thumbbrowserbase.cc +++ b/rtgui/thumbbrowserbase.cc @@ -498,6 +498,12 @@ void ThumbBrowserBase::refreshThumbImages () { redraw (); } +void ThumbBrowserBase::refreshQuickThumbImages () { + for (int i=0; irefreshQuickThumbnailImage (); + } +} + void ThumbBrowserBase::refreshEditedState (const std::set& efiles) { editedFiles = efiles; diff --git a/rtgui/thumbbrowserbase.h b/rtgui/thumbbrowserbase.h index e8ffe4b53..801a96756 100644 --- a/rtgui/thumbbrowserbase.h +++ b/rtgui/thumbbrowserbase.h @@ -95,6 +95,7 @@ class ThumbBrowserBase : public Gtk::VBox { void styleChanged (const Glib::RefPtr& style); void redraw (); // arrange files and draw area void refreshThumbImages (); // refresh thumbnail sizes, re-generate thumbnail images, arrange and draw + void refreshQuickThumbImages (); // refresh thumbnail sizes, re-generate thumbnail images, arrange and draw void refreshEditedState (const std::set& efiles); void initEntry (ThumbBrowserEntryBase* entry); diff --git a/rtgui/thumbbrowserentrybase.h b/rtgui/thumbbrowserentrybase.h index 20f8dda77..6562633d0 100644 --- a/rtgui/thumbbrowserentrybase.h +++ b/rtgui/thumbbrowserentrybase.h @@ -109,6 +109,7 @@ protected: bool operator< (ThumbBrowserEntryBase& other) { return shortname.casefold()>other.shortname.casefold(); } virtual void refreshThumbnailImage () {} + virtual void refreshQuickThumbnailImage () {} virtual void calcThumbnailSize () {} virtual void drawProgressBar (Glib::RefPtr win, Glib::RefPtr gc, const Gdk::Color& foregr, const Gdk::Color& backgr, int x, int w, int y, int h) {} diff --git a/rtgui/thumbimageupdater.cc b/rtgui/thumbimageupdater.cc index bb6e95028..2b83a7157 100644 --- a/rtgui/thumbimageupdater.cc +++ b/rtgui/thumbimageupdater.cc @@ -22,7 +22,7 @@ #include #include -#define THREAD_NUM 4 +#define THREAD_NUM 2 #define DEBUG(format,args...) //#define DEBUG(format,args...) printf("ThumbImageUpdate::%s: " format "\n", __FUNCTION__, ## args) @@ -35,12 +35,13 @@ public: struct Job { Job(Thumbnail* thumbnail, const rtengine::procparams::ProcParams& pparams, - int height, bool* priority, + int height, bool* priority, bool upgrade, ThumbImageUpdateListener* listener): thumbnail_(thumbnail), pparams_(pparams), height_(height), priority_(priority), + upgrade_(upgrade), listener_(listener) {} @@ -53,6 +54,7 @@ public: rtengine::procparams::ProcParams pparams_; int height_; bool* priority_; + bool upgrade_; ThumbImageUpdateListener* listener_; }; @@ -103,6 +105,16 @@ public: } } + // see if any none upgrade jobs exist + for ( i = jobs_.begin(); i != jobs_.end(); ++i) + { + if ( !i->upgrade_ ) + { + DEBUG("processing(not-upgrade) %s",i->thumbnail_->getFileName().c_str()); + break; + } + } + // if none, then use first if ( i == jobs_.end() ) { @@ -123,6 +135,15 @@ public: // unlock and do processing; will relock on block exit, then call listener double scale = 1.0; rtengine::IImage8* img = 0; + + if ( j.upgrade_ ) + { + if ( j.thumbnail_->isQuick() ) + { + img = j.thumbnail_->upgradeThumbImage(j.pparams_, j.height_, scale); + } + } + else { img = j.thumbnail_->processThumbImage(j.pparams_, j.height_, scale); } @@ -165,7 +186,7 @@ ThumbImageUpdater::ThumbImageUpdater(): void ThumbImageUpdater::add(Thumbnail* t, const rtengine::procparams::ProcParams& params, - int height, bool* priority, ThumbImageUpdateListener* l) + int height, bool* priority, bool upgrade, ThumbImageUpdateListener* l) { // nobody listening? if ( l == 0 ) @@ -180,7 +201,8 @@ ThumbImageUpdater::add(Thumbnail* t, const rtengine::procparams::ProcParams& par for ( ; i != impl_->jobs_.end(); ++i ) { if ( i->thumbnail_ == t && - i->listener_ == l ) + i->listener_ == l && + i->upgrade_ == upgrade ) { DEBUG("updating job %s",t->getFileName().c_str()); // we have one, update queue entry, will be picked up by thread when processed @@ -193,7 +215,7 @@ ThumbImageUpdater::add(Thumbnail* t, const rtengine::procparams::ProcParams& par // create a new job and append to queue DEBUG("queing job %s",t->getFileName().c_str()); - impl_->jobs_.push_back(Impl::Job(t,params,height,priority,l)); + impl_->jobs_.push_back(Impl::Job(t,params,height,priority,upgrade,l)); DEBUG("adding run request %s",t->getFileName().c_str()); impl_->threadPool_->push(sigc::mem_fun(*impl_, &ThumbImageUpdater::Impl::processNextJob)); diff --git a/rtgui/thumbimageupdater.h b/rtgui/thumbimageupdater.h index 08caf3eda..6fdce5bc1 100644 --- a/rtgui/thumbimageupdater.h +++ b/rtgui/thumbimageupdater.h @@ -64,7 +64,7 @@ class ThumbImageUpdater { * @param l listener waiting on update */ void add(Thumbnail* t, const rtengine::procparams::ProcParams& params, - int height, bool* priority, ThumbImageUpdateListener* l); + int height, bool* priority, bool upgrade, ThumbImageUpdateListener* l); /** * @brief Remove jobs associated with listener \c l. diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index c8318f53d..0ffe641de 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -34,7 +34,8 @@ using namespace rtengine::procparams; Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf) : fname(fname), cfs(*cf), cachemgr(cm), ref(1), enqueueNumber(0), tpp(NULL), - pparamsValid(false), needsReProcessing(true), lastImg(NULL) { + pparamsValid(false), needsReProcessing(true), lastImg(NULL), + quick_(false), initial_(false) { cfs.load (getCacheFileName ("data")+".txt"); loadProcParams (); @@ -44,68 +45,90 @@ Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageDa Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5) : fname(fname), cachemgr(cm), ref(1), enqueueNumber(0), tpp(NULL), pparamsValid(false), - needsReProcessing(true), lastImg(NULL) { + needsReProcessing(true), lastImg(NULL), + quick_(false), initial_(true) { cfs.md5 = md5; _generateThumbnailImage (); loadProcParams (); cfs.recentlySaved = false; + + initial_ = false; } void Thumbnail::_generateThumbnailImage () { -// delete everything loaded into memory - delete tpp; - tpp = NULL; - delete [] lastImg; - lastImg = NULL; - tw = -1; - th = options.maxThumbnailHeight; + // delete everything loaded into memory + delete tpp; + tpp = NULL; + delete [] lastImg; + lastImg = NULL; + tw = -1; + th = options.maxThumbnailHeight; -// generate thumbnail image + // generate thumbnail image - Glib::ustring ext = getExtension (fname); - if (ext=="") - return; - cfs.supported = false; - cfs.exifValid = false; - cfs.timeValid = false; - - delete tpp; - tpp = NULL; - if (ext.lowercase()=="jpg" || ext.lowercase()=="png" || ext.lowercase()=="tif" || ext.lowercase()=="tiff") - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1); - if (tpp) { - if (ext.lowercase()=="jpg") { - cfs.format = FT_Jpeg; - infoFromImage (fname); - } - else if (ext.lowercase()=="png") - cfs.format = FT_Png; - else if (ext.lowercase()=="tif" || ext.lowercase()=="tiff") { - cfs.format = FT_Tiff; - infoFromImage (fname); - } - } - else { - rtengine::RawMetaDataLocation ri; - tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, tw, th, 1); - if (tpp) { - cfs.format = FT_Raw; - infoFromImage (fname, &ri); - } - } - if (tpp) { - // save thumbnail image to cache - _saveThumbnail (); - cfs.supported = true; - } - needsReProcessing = true; + Glib::ustring ext = getExtension (fname); + if (ext=="") + return; + cfs.supported = false; + cfs.exifValid = false; + cfs.timeValid = false; - cfs.save (getCacheFileName ("data")+".txt"); + delete tpp; + tpp = NULL; + if (ext.lowercase()=="jpg" || ext.lowercase()=="png" || ext.lowercase()=="tif" || ext.lowercase()=="tiff") + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1); + if (tpp) { + if (ext.lowercase()=="jpg") { + cfs.format = FT_Jpeg; + infoFromImage (fname); + } + else if (ext.lowercase()=="png") + cfs.format = FT_Png; + else if (ext.lowercase()=="tif" || ext.lowercase()=="tiff") { + cfs.format = FT_Tiff; + infoFromImage (fname); + } + } + else { + // RAW works like this: + // 1. if we are here it's because we aren't in the cache so load the JPG + // image out of the RAW. Mark as "quick". + // 2. if we don't find that then just grab the real image. + rtengine::RawMetaDataLocation ri; + if ( initial_ ) + { + quick_ = true; + tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, tw, th, 1); + } + if ( tpp == 0 ) + { + quick_ = false; + tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, tw, th, 1); + } + if (tpp) { + cfs.format = FT_Raw; + infoFromImage (fname, &ri); + } + } + if (tpp ) + { + if ( !quick_ ) + { + _saveThumbnail (); + } + cfs.supported = true; + } + needsReProcessing = true; - generateExifDateTimeStrings (); + if ( !quick_ ) + { + cfs.save (getCacheFileName ("data")+".txt"); + } + + generateExifDateTimeStrings (); } void Thumbnail::generateThumbnailImage () { @@ -262,9 +285,28 @@ rtengine::IImage8* Thumbnail::processThumbImage (const rtengine::procparams::Pro if (!tpp) return NULL; - rtengine::IImage8* res = tpp->processImage (pparams, h, rtengine::TI_Bilinear, scale); + if ( quick_ ) + { + return tpp->quickProcessImage (pparams, h, rtengine::TI_Nearest, scale); + } + else + { + return tpp->processImage (pparams, h, rtengine::TI_Bilinear, scale); + } +} - return res; +rtengine::IImage8* Thumbnail::upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale) { + + Glib::Mutex::Lock lock(mutex); + + if ( !quick_ ) + { + return 0; + } + + quick_ = false; + _generateThumbnailImage(); + return tpp->processImage (pparams, h, rtengine::TI_Bilinear, scale); } void Thumbnail::generateExifDateTimeStrings () { diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index 19e388812..32da160e9 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -58,6 +58,9 @@ class Thumbnail { Glib::ustring exifString; Glib::ustring dateTimeString; + bool initial_; + bool quick_; + // vector of listeners std::vector listeners; @@ -81,6 +84,7 @@ class Thumbnail { void clearProcParams (int whoClearedIt=-1); void loadProcParams (); + bool isQuick() { return quick_; } bool isRecentlySaved (); void imageDeveloped (); void imageEnqueued (); @@ -89,7 +93,7 @@ class Thumbnail { // unsigned char* getThumbnailImage (int &w, int &h, int fixwh=1); // fixwh = 0: fix w and calculate h, =1: fix h and calculate w rtengine::IImage8* processThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale); - void processThumbImage2 (const rtengine::procparams::ProcParams& pparams, int h, rtengine::IImage8*& img, double& scale) { img = processThumbImage(pparams, h, scale); } + rtengine::IImage8* upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale); void getThumbnailSize (int &w, int &h); void getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h) { if (tpp) tpp->getFinalSize (pparams, w, h); }