rawTherapee/rtgui/previewhandler.cc

226 lines
6.2 KiB
C++

/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "previewhandler.h"
#include <gtkmm.h>
#include "../rtengine/rtengine.h"
using namespace rtengine;
using namespace rtengine::procparams;
PreviewHandler::PreviewHandler () : image(NULL), previewScale(1.) {
pih = new PreviewHandlerIdleHelper;
pih->phandler = this;
pih->destroyed = false;
pih->pending = 0;
}
PreviewHandler::~PreviewHandler () {
if (pih->pending)
pih->destroyed = true;
else
delete pih;
}
//----------------previewimagelistener functions--------------------
struct iaimgpar {
IImage8* image;
PreviewHandlerIdleHelper* pih;
double scale;
CropParams cp;
};
int setImageUI (void* data) {
iaimgpar* iap = static_cast<iaimgpar*>(data);
PreviewHandlerIdleHelper* pih = iap->pih;
if (pih->destroyed) {
if (pih->pending == 1)
delete pih;
else
pih->pending--;
delete iap;
return 0;
}
if (pih->phandler->image) {
IImage8* 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 0;
}
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;
g_idle_add (setImageUI, iap);
}
int delImageUI (void* data) {
iaimgpar* iap = static_cast<iaimgpar*>(data);
PreviewHandlerIdleHelper* pih = iap->pih;
if (pih->destroyed) {
if (pih->pending == 1)
delete pih;
else
pih->pending--;
delete iap;
return 0;
}
if (pih->phandler->image) {
IImage8* oldImg = pih->phandler->image;
oldImg->getMutex().lock ();
pih->phandler->image = NULL;
oldImg->getMutex().unlock ();
}
iap->image->free ();
pih->phandler->previewImgMutex.lock ();
pih->phandler->previewImg.clear ();
pih->phandler->previewImgMutex.unlock ();
pih->pending--;
delete iap;
return 0;
}
void PreviewHandler::delImage (IImage8* i) {
pih->pending++;
iaimgpar* iap = new iaimgpar;
iap->image = i;
iap->pih = pih;
g_idle_add (delImageUI, iap);
}
int imageReadyUI (void* data) {
iaimgpar* iap = static_cast<iaimgpar*>(data);
PreviewHandlerIdleHelper* pih = iap->pih;
if (pih->destroyed) {
if (pih->pending == 1)
delete pih;
else
pih->pending--;
delete iap;
return 0;
}
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 0;
}
void PreviewHandler::imageReady (CropParams cp) {
pih->pending++;
iaimgpar* iap = new iaimgpar;
iap->pih = pih;
iap->cp = cp;
g_idle_add (imageReadyUI, iap);
}
Glib::RefPtr<Gdk::Pixbuf> PreviewHandler::getRoughImage (int x, int y, int w, int h, double zoom) {
MyMutex::MyLock lock(previewImgMutex);
Glib::RefPtr<Gdk::Pixbuf> 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;
int ix = x*zoom;
int iy = y*zoom;
if (ix<0)
ix = 0;
if (iy<0)
iy = 0;
if ((ix+w)/totalZoom>previewImg->get_width())
ix = previewImg->get_width()*totalZoom - w;
if ((iy+h)/totalZoom>previewImg->get_height())
iy = previewImg->get_height()*totalZoom - h;
resPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, w, h);
previewImg->scale (resPixbuf, 0, 0, w, h, -ix, -iy, totalZoom, totalZoom, Gdk::INTERP_NEAREST);
}
return resPixbuf;
}
Glib::RefPtr<Gdk::Pixbuf> PreviewHandler::getRoughImage (int desiredW, int desiredH, double& zoom_) {
MyMutex::MyLock lock(previewImgMutex);
Glib::RefPtr<Gdk::Pixbuf> 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<PreviewListener*>::iterator i=listeners.begin(); i!=listeners.end(); i++)
(*i)->previewImageChanged ();
}