/* * 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 "previewhandler.h" #include #include "../rtengine/rtengine.h" using namespace rtengine; using namespace rtengine::procparams; namespace { struct iaimgpar { IImage8* image; PreviewHandlerIdleHelper* pih; double scale; CropParams cp; }; } PreviewHandler::PreviewHandler () : image(nullptr), previewScale(1.) { pih = new PreviewHandlerIdleHelper; pih->phandler = this; pih->destroyed = false; pih->pending = 0; } PreviewHandler::~PreviewHandler () { idle_register.destroy(); if (pih->pending) { pih->destroyed = true; } else { delete pih; } } //----------------previewimagelistener functions-------------------- void PreviewHandler::setImage (rtengine::IImage8* i, double scale, rtengine::procparams::CropParams cp) { pih->pending++; iaimgpar* iap = new iaimgpar; iap->image = i; iap->pih = pih; iap->scale = scale; iap->cp = cp; const auto func = [](gpointer data) -> gboolean { iaimgpar* const iap = static_cast(data); PreviewHandlerIdleHelper* const pih = iap->pih; if (pih->destroyed) { if (pih->pending == 1) { delete pih; } else { pih->pending--; } delete iap; return FALSE; } if (pih->phandler->image) { IImage8* const oldImg = pih->phandler->image; oldImg->getMutex().lock (); pih->phandler->image = iap->image; oldImg->getMutex().unlock (); } else { pih->phandler->image = iap->image; } pih->phandler->cropParams = iap->cp; pih->phandler->previewScale = iap->scale; pih->pending--; delete iap; return FALSE; }; idle_register.add(func, iap); } void PreviewHandler::delImage (IImage8* i) { pih->pending++; iaimgpar* iap = new iaimgpar; iap->image = i; iap->pih = pih; const auto func = [](gpointer data) -> gboolean { iaimgpar* iap = static_cast(data); PreviewHandlerIdleHelper* pih = iap->pih; if (pih->destroyed) { if (pih->pending == 1) { delete pih; } else { pih->pending--; } delete iap; return FALSE; } if (pih->phandler->image) { IImage8* oldImg = pih->phandler->image; oldImg->getMutex().lock (); pih->phandler->image = nullptr; oldImg->getMutex().unlock (); } iap->image->free (); pih->phandler->previewImgMutex.lock (); pih->phandler->previewImg.clear (); pih->phandler->previewImgMutex.unlock (); pih->pending--; delete iap; return FALSE; }; idle_register.add(func, iap); } void PreviewHandler::imageReady (CropParams cp) { pih->pending++; iaimgpar* iap = new iaimgpar; iap->pih = pih; iap->cp = cp; const auto func = [](gpointer data) -> gboolean { iaimgpar* const iap = static_cast(data); PreviewHandlerIdleHelper* pih = iap->pih; if (pih->destroyed) { if (pih->pending == 1) { delete pih; } else { pih->pending--; } delete iap; return FALSE; } pih->phandler->previewImgMutex.lock (); pih->phandler->previewImg = Gdk::Pixbuf::create_from_data (pih->phandler->image->getData(), Gdk::COLORSPACE_RGB, false, 8, pih->phandler->image->getWidth(), pih->phandler->image->getHeight(), 3 * pih->phandler->image->getWidth()); pih->phandler->previewImgMutex.unlock (); pih->phandler->cropParams = iap->cp; pih->phandler->previewImageChanged (); pih->pending--; delete iap; return FALSE; }; idle_register.add(func, iap); } Glib::RefPtr PreviewHandler::getRoughImage (int x, int y, int w, int h, double zoom) { MyMutex::MyLock lock(previewImgMutex); Glib::RefPtr resPixbuf; if (previewImg) { double totalZoom = zoom * previewScale; if (w > previewImg->get_width()*totalZoom) { w = image->getWidth() * totalZoom; } if (h > previewImg->get_height()*totalZoom) { h = image->getHeight() * totalZoom; } x *= zoom; y *= zoom; w = rtengine::LIM(w, 0, int(previewImg->get_width() * totalZoom) - x); h = rtengine::LIM(h, 0, int(previewImg->get_height() * totalZoom) - y); resPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, w, h); previewImg->scale (resPixbuf, 0, 0, w, h, -x, -y, totalZoom, totalZoom, Gdk::INTERP_NEAREST); } return resPixbuf; } Glib::RefPtr PreviewHandler::getRoughImage (int desiredW, int desiredH, double& zoom_) { MyMutex::MyLock lock(previewImgMutex); Glib::RefPtr resPixbuf; if (previewImg) { double zoom1 = (double)max(desiredW, 20) / previewImg->get_width(); // too small values lead to extremely increased processing time in scale function, Issue 2783 double zoom2 = (double)max(desiredH, 20) / previewImg->get_height(); // "" double zoom = zoom1 < zoom2 ? zoom1 : zoom2; resPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, image->getWidth() * zoom, image->getHeight() * zoom); previewImg->scale (resPixbuf, 0, 0, previewImg->get_width()*zoom, previewImg->get_height()*zoom, 0, 0, zoom, zoom, Gdk::INTERP_BILINEAR); zoom_ = zoom / previewScale; } return resPixbuf; } void PreviewHandler::previewImageChanged () { for (std::list::iterator i = listeners.begin(); i != listeners.end(); ++i) { (*i)->previewImageChanged (); } }