Clean up clutstore.* and add LRU cache
This commit adds a true LRU cache to `rtengine` which is used in the new `CLUTStore` class. The code in `clutstore.*` was cleaned up with C++11 features and small optimizations taken from my `clutbench` project. The `CLUTStore` class was converted to a true singleton.
This commit is contained in:
parent
e61e488346
commit
e495093b18
236
rtengine/cache.h
Normal file
236
rtengine/cache.h
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RawTherapee.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 Flössie <floessie.mail@gmail.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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <list>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "../rtgui/threadutils.h"
|
||||||
|
|
||||||
|
namespace rtengine
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace cache_helper
|
||||||
|
{
|
||||||
|
|
||||||
|
// See http://stackoverflow.com/a/20790050
|
||||||
|
template<typename, typename = void>
|
||||||
|
struct has_hash
|
||||||
|
: std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct has_hash<T, decltype(std::hash<T>()(std::declval<T>()), void())>
|
||||||
|
: std::true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class K, class V>
|
||||||
|
class Cache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class Hook
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Hook()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual void onDiscard(const K& key, const V& value) = 0;
|
||||||
|
virtual void onDisplace(const K& key, const V& value) = 0;
|
||||||
|
virtual void onRemove(const K& key, const V& value) = 0;
|
||||||
|
virtual void onDestroy() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Cache(unsigned long _size, Hook* _hook = 0) :
|
||||||
|
store_size(_size),
|
||||||
|
hook(_hook)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Cache()
|
||||||
|
{
|
||||||
|
if (hook) {
|
||||||
|
resize(0);
|
||||||
|
hook->onDestroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get(const K& key, V& value) const
|
||||||
|
{
|
||||||
|
mutex.lock();
|
||||||
|
const StoreConstIterator store_it = store.find(key);
|
||||||
|
const bool present = store_it != store.end();
|
||||||
|
if (present) {
|
||||||
|
lru_list.splice(
|
||||||
|
lru_list.begin(),
|
||||||
|
lru_list,
|
||||||
|
store_it->second.lru_list_it
|
||||||
|
);
|
||||||
|
value = store_it->second.value;
|
||||||
|
}
|
||||||
|
mutex.unlock();
|
||||||
|
|
||||||
|
return present;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set(const K& key, const V& value)
|
||||||
|
{
|
||||||
|
return set(key, value, Mode::UNCOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool replace(const K& key, const V& value)
|
||||||
|
{
|
||||||
|
return set(key, value, Mode::KNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool insert(const K& key, const V& value)
|
||||||
|
{
|
||||||
|
return set(key, value, Mode::UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove(const K& key)
|
||||||
|
{
|
||||||
|
mutex.lock();
|
||||||
|
const StoreIterator store_it = store.find(key);
|
||||||
|
const bool present = store_it != store.end();
|
||||||
|
if (present) {
|
||||||
|
remove(store_it);
|
||||||
|
}
|
||||||
|
mutex.unlock();
|
||||||
|
|
||||||
|
return present;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(unsigned long size)
|
||||||
|
{
|
||||||
|
mutex.lock();
|
||||||
|
while (lru_list.size() > size) {
|
||||||
|
discard();
|
||||||
|
}
|
||||||
|
store_size = size;
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
mutex.lock();
|
||||||
|
if (hook) {
|
||||||
|
for (const auto& entry : store) {
|
||||||
|
hook->onRemove(entry.first, entry.second.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lru_list.clear();
|
||||||
|
store.clear();
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Value;
|
||||||
|
|
||||||
|
using Store = typename std::conditional<
|
||||||
|
cache_helper::has_hash<K>::value,
|
||||||
|
std::unordered_map<K, Value>,
|
||||||
|
std::map<K, Value>
|
||||||
|
>::type;
|
||||||
|
using StoreIterator = typename Store::iterator;
|
||||||
|
using StoreConstIterator = typename Store::const_iterator;
|
||||||
|
|
||||||
|
typedef std::list<StoreIterator> LruList;
|
||||||
|
using LruListIterator = typename LruList::iterator;
|
||||||
|
|
||||||
|
struct Value {
|
||||||
|
V value;
|
||||||
|
LruListIterator lru_list_it;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Mode {
|
||||||
|
UNCOND,
|
||||||
|
KNOWN,
|
||||||
|
UNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
void discard()
|
||||||
|
{
|
||||||
|
const StoreIterator store_it = lru_list.back();
|
||||||
|
if (hook) {
|
||||||
|
hook->onDiscard(store_it->first, store_it->second.value);
|
||||||
|
}
|
||||||
|
store.erase(store_it);
|
||||||
|
lru_list.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set(const K& key, const V& value, Mode mode)
|
||||||
|
{
|
||||||
|
mutex.lock();
|
||||||
|
const StoreIterator store_it = store.find(key);
|
||||||
|
const bool is_new_key = store_it == store.end();
|
||||||
|
if (is_new_key) {
|
||||||
|
if (mode == Mode::UNCOND || mode == Mode::UNKNOWN) {
|
||||||
|
if (lru_list.size() >= store_size) {
|
||||||
|
discard();
|
||||||
|
}
|
||||||
|
lru_list.push_front(store.end());
|
||||||
|
const Value v = {
|
||||||
|
value,
|
||||||
|
lru_list.begin()
|
||||||
|
};
|
||||||
|
lru_list.front() = store.emplace(key, v).first;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mode == Mode::UNCOND || mode == Mode::KNOWN) {
|
||||||
|
if (hook) {
|
||||||
|
hook->onDisplace(key, store_it->second.value);
|
||||||
|
}
|
||||||
|
lru_list.splice(
|
||||||
|
lru_list.begin(),
|
||||||
|
lru_list,
|
||||||
|
store_it->second.lru_list_it
|
||||||
|
);
|
||||||
|
store_it->second.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex.unlock();
|
||||||
|
|
||||||
|
return is_new_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(const StoreIterator& store_it)
|
||||||
|
{
|
||||||
|
if (hook) {
|
||||||
|
hook->onRemove(store_it->first, store_it->second.value);
|
||||||
|
}
|
||||||
|
lru_list.erase(store_it->second.lru_list_it);
|
||||||
|
store.erase(store_it);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long store_size;
|
||||||
|
Hook* const hook;
|
||||||
|
mutable MyMutex mutex;
|
||||||
|
Store store;
|
||||||
|
mutable LruList lru_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -3,440 +3,233 @@
|
|||||||
#include "stdimagesource.h"
|
#include "stdimagesource.h"
|
||||||
#include "../rtgui/options.h"
|
#include "../rtgui/options.h"
|
||||||
|
|
||||||
rtengine::CLUTStore clutStore;
|
namespace
|
||||||
|
|
||||||
using namespace rtengine;
|
|
||||||
|
|
||||||
const float MAXVAL8 = 255.;
|
|
||||||
|
|
||||||
CLUTStore::CLUTStore()
|
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
CLUT* CLUTStore::getClut( const Glib::ustring& filename )
|
std::unique_ptr<rtengine::Imagefloat> loadFile(
|
||||||
|
const Glib::ustring& filename,
|
||||||
|
const Glib::ustring& working_color_space,
|
||||||
|
unsigned int& clut_level
|
||||||
|
)
|
||||||
{
|
{
|
||||||
CLUT *result = 0;
|
std::unique_ptr<rtengine::Imagefloat> result;
|
||||||
m_mutex.lock();
|
|
||||||
Cluts::iterator cluts_it = m_cluts.find(filename);
|
|
||||||
|
|
||||||
if (cluts_it == m_cluts.end()) {
|
rtengine::StdImageSource img_src;
|
||||||
if (m_cluts.size() >= options.clutCacheSize) {
|
|
||||||
// Evict a "random" entry from cache
|
|
||||||
Cluts::iterator victim_it = m_cluts.begin();
|
|
||||||
|
|
||||||
if (--victim_it->second.first == -1) {
|
if (!Glib::file_test(filename, Glib::FILE_TEST_EXISTS) || img_src.load(filename)) {
|
||||||
delete victim_it->second.second;
|
|
||||||
m_cluts.erase(victim_it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cluts_it = m_cluts.insert(std::make_pair(filename, std::make_pair(0, new HaldCLUT))).first;
|
|
||||||
cluts_it->second.second->load( filename );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cluts_it->second.second->isValid()) {
|
|
||||||
result = cluts_it->second.second;
|
|
||||||
++cluts_it->second.first;
|
|
||||||
} else {
|
|
||||||
delete cluts_it->second.second;
|
|
||||||
m_cluts.erase(cluts_it);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_mutex.unlock();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLUTStore::releaseClut( const CLUT* clut )
|
|
||||||
{
|
|
||||||
m_mutex.lock();
|
|
||||||
|
|
||||||
for (Cluts::iterator cluts_it = m_cluts.begin(); cluts_it != m_cluts.end(); ++cluts_it) {
|
|
||||||
if (cluts_it->second.second == clut) {
|
|
||||||
if (--cluts_it->second.first == -1) {
|
|
||||||
delete cluts_it->second.second;
|
|
||||||
m_cluts.erase(cluts_it);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_mutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLUTStore::clearCache()
|
|
||||||
{
|
|
||||||
m_mutex.lock();
|
|
||||||
|
|
||||||
for (Cluts::iterator cluts_it = m_cluts.begin(); cluts_it != m_cluts.end();) {
|
|
||||||
if (--cluts_it->second.first == -1) {
|
|
||||||
delete cluts_it->second.second;
|
|
||||||
Cluts::iterator tmp = cluts_it;
|
|
||||||
++cluts_it;
|
|
||||||
m_cluts.erase(tmp);
|
|
||||||
} else {
|
|
||||||
++cluts_it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_mutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtengine::splitClutFilename( Glib::ustring filename, Glib::ustring &name, Glib::ustring &extension, Glib::ustring &profileName )
|
|
||||||
{
|
|
||||||
filename = Glib::path_get_basename( filename );
|
|
||||||
name = filename;
|
|
||||||
//remove dirs
|
|
||||||
size_t lastSlashPos = filename.find_last_of( "/" );
|
|
||||||
|
|
||||||
if ( lastSlashPos == Glib::ustring::npos ) {
|
|
||||||
lastSlashPos = filename.find_last_of( "\\" );
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t lastDotPos = filename.find_last_of( '.' );
|
|
||||||
|
|
||||||
if ( lastDotPos != Glib::ustring::npos ) {
|
|
||||||
name = filename.substr( 0, lastDotPos );
|
|
||||||
extension = filename.substr( lastDotPos + 1, Glib::ustring::npos );
|
|
||||||
}
|
|
||||||
|
|
||||||
profileName = "sRGB"; // sRGB by default
|
|
||||||
static std::vector<Glib::ustring> workingProfiles = rtengine::getWorkingProfiles();
|
|
||||||
|
|
||||||
for ( std::vector<Glib::ustring>::iterator it = workingProfiles.begin(); it != workingProfiles.end(); ++it ) {
|
|
||||||
Glib::ustring ¤tProfile = *it;
|
|
||||||
|
|
||||||
if ( std::search( name.rbegin(), name.rend(), currentProfile.rbegin(), currentProfile.rend() ) == name.rbegin() ) {
|
|
||||||
profileName = currentProfile;
|
|
||||||
name = name.substr( 0, name.size() - currentProfile.size() );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
||||||
|
|
||||||
HaldCLUT::HaldCLUT()
|
|
||||||
: m_clutImage( 0 ),
|
|
||||||
m_level (0),
|
|
||||||
m_profile( "sRGB" )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HaldCLUT::~HaldCLUT()
|
|
||||||
{
|
|
||||||
if ( m_clutImage ) {
|
|
||||||
m_clutImage->free();
|
|
||||||
m_clutImage = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HaldCLUT::load( Glib::ustring filename )
|
|
||||||
{
|
|
||||||
m_clutImage = loadFile( filename, "", m_level );
|
|
||||||
Glib::ustring name, ext;
|
|
||||||
splitClutFilename( filename, name, ext, m_profile );
|
|
||||||
|
|
||||||
if ( m_clutImage ) {
|
|
||||||
m_filename = filename;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Glib::ustring HaldCLUT::profile() const
|
|
||||||
{
|
|
||||||
return m_profile;
|
|
||||||
}
|
|
||||||
|
|
||||||
Imagefloat* HaldCLUT::loadFile( Glib::ustring filename, Glib::ustring workingColorSpace, int &outLevel )
|
|
||||||
{
|
|
||||||
Imagefloat *result = 0;
|
|
||||||
StdImageSource imgSrc;
|
|
||||||
|
|
||||||
if ( !Glib::file_test( filename, Glib::FILE_TEST_EXISTS ) || imgSrc.load(filename) ) {
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fw, fh;
|
int fw, fh;
|
||||||
imgSrc.getFullSize (fw, fh, TR_NONE);
|
img_src.getFullSize(fw, fh, TR_NONE);
|
||||||
|
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
|
|
||||||
//test on Hald format, copypasted from http://www.quelsolaar.com/technology/clut.html
|
if (fw == fh) {
|
||||||
if ( fw == fh ) {
|
unsigned int level = 1;
|
||||||
outLevel = 1;
|
while (level * level * level < fw) {
|
||||||
|
++level;
|
||||||
for(; outLevel * outLevel * outLevel < fw; outLevel++);
|
}
|
||||||
|
if (level * level * level == fw && level > 1) {
|
||||||
if( !( outLevel * outLevel * outLevel > fw ) ) {
|
clut_level = level;
|
||||||
valid = true;
|
valid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( valid ) {
|
if (valid) {
|
||||||
ColorTemp currWB = imgSrc.getWB();
|
rtengine::ColorTemp curr_wb = img_src.getWB();
|
||||||
Imagefloat* baseImg = new Imagefloat (fw, fh);
|
result = std::unique_ptr<rtengine::Imagefloat>(new rtengine::Imagefloat(fw, fh));
|
||||||
PreviewProps pp (0, 0, fw, fh, 1);
|
const PreviewProps pp(0, 0, fw, fh, 1);
|
||||||
|
|
||||||
procparams::ColorManagementParams icm;
|
rtengine::procparams::ColorManagementParams icm;
|
||||||
icm.working = workingColorSpace;
|
icm.working = working_color_space;
|
||||||
|
|
||||||
imgSrc.getImage (currWB, TR_NONE, baseImg, pp, procparams::ToneCurveParams(), icm, procparams::RAWParams());
|
img_src.getImage(curr_wb, TR_NONE, result.get(), pp, rtengine::procparams::ToneCurveParams(), icm, rtengine::procparams::RAWParams());
|
||||||
|
|
||||||
if ( !workingColorSpace.empty() ) {
|
if (!working_color_space.empty()) {
|
||||||
imgSrc.convertColorSpace(baseImg, icm, currWB);
|
img_src.convertColorSpace(result.get(), icm, curr_wb);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = baseImg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HaldCLUT::loadClut( Imagefloat *img, RawClut &outClut )
|
inline void posToXy(unsigned int pos, unsigned int width, unsigned int (&x)[2], unsigned int (&y)[2])
|
||||||
{
|
{
|
||||||
img->normalizeFloatTo1();
|
x[0] = pos % width;
|
||||||
int y_size = img->getH();
|
y[0] = pos / width;
|
||||||
int x_size = img->getW();
|
x[1] = (pos + 1) % width;
|
||||||
outClut.resize( x_size * y_size * 3 );
|
y[1] = (pos + 1) / width;
|
||||||
int clutIdx = 0;
|
}
|
||||||
|
|
||||||
//int level = m_level * m_level; (unused)
|
}
|
||||||
for(int y = 0; y < y_size; y++) {
|
|
||||||
for(int x = 0; x < x_size; x++) {
|
|
||||||
outClut[ clutIdx * 3 ] = img->r( y, x ) * MAXVAL8;
|
|
||||||
outClut[ clutIdx * 3 + 1 ] = img->g( y, x ) * MAXVAL8;
|
|
||||||
outClut[ clutIdx * 3 + 2 ] = img->b( y, x ) * MAXVAL8;
|
|
||||||
|
|
||||||
++clutIdx;
|
void rtengine::CLUT::splitClutFilename(
|
||||||
|
const Glib::ustring& filename,
|
||||||
|
Glib::ustring& name,
|
||||||
|
Glib::ustring& extension,
|
||||||
|
Glib::ustring& profile_name
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Glib::ustring basename = Glib::path_get_basename(filename);
|
||||||
|
|
||||||
|
Glib::ustring::size_type last_slash_pos = basename.rfind('/');
|
||||||
|
if (last_slash_pos == Glib::ustring::npos) {
|
||||||
|
last_slash_pos = basename.rfind('\\');
|
||||||
|
}
|
||||||
|
|
||||||
|
const Glib::ustring::size_type last_dot_pos = basename.rfind('.');
|
||||||
|
|
||||||
|
if (last_dot_pos != Glib::ustring::npos) {
|
||||||
|
name.assign(basename, 0, last_dot_pos);
|
||||||
|
extension.assign(basename, last_dot_pos + 1, Glib::ustring::npos);
|
||||||
|
} else {
|
||||||
|
name = basename;
|
||||||
|
}
|
||||||
|
|
||||||
|
profile_name = "sRGB";
|
||||||
|
|
||||||
|
for (const auto& working_profile : rtengine::getWorkingProfiles()) {
|
||||||
|
if ( std::search( name.rbegin(), name.rend(), working_profile.rbegin(), working_profile.rend() ) == name.rbegin() ) {
|
||||||
|
profile_name = working_profile;
|
||||||
|
name.erase(name.size() - working_profile.size());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Imagefloat* HaldCLUT::generateIdentImage( int level )
|
rtengine::HaldCLUT::HaldCLUT() :
|
||||||
|
clut_level(0),
|
||||||
|
clut_profile("sRGB")
|
||||||
{
|
{
|
||||||
int imageWidth = level * level * level;
|
|
||||||
Imagefloat *resultImg = new Imagefloat( imageWidth, imageWidth );
|
|
||||||
|
|
||||||
int cubeSideSize = level * level;
|
|
||||||
float step = MAXVALF / (cubeSideSize - 1);
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
for( int b = 0; b < cubeSideSize; ++b ) {
|
|
||||||
for ( int g = 0; g < cubeSideSize; ++g ) {
|
|
||||||
for ( int r = 0; r < cubeSideSize; ++r ) {
|
|
||||||
int x = pos / imageWidth;
|
|
||||||
int y = pos % imageWidth;
|
|
||||||
resultImg->r( x, y ) = step * r;
|
|
||||||
resultImg->g( x, y ) = step * g;
|
|
||||||
resultImg->b( x, y ) = step * b;
|
|
||||||
++pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultImg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtengine::HaldCLUT::~HaldCLUT()
|
||||||
bool HaldCLUT::isValid() const
|
|
||||||
{
|
{
|
||||||
return m_clutImage != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HaldCLUT::getRGB( float rr, float gg, float bb, float &outR, float &outG, float &outB ) const
|
bool rtengine::HaldCLUT::load(const Glib::ustring& filename)
|
||||||
{
|
{
|
||||||
rr /= MAXVALF;
|
clut_image = loadFile(filename, "", clut_level);
|
||||||
gg /= MAXVALF;
|
Glib::ustring name, ext;
|
||||||
bb /= MAXVALF;
|
splitClutFilename(filename, name, ext, clut_profile);
|
||||||
correct( *m_clutImage, m_level, rr, gg, bb, outR, outG, outB );
|
|
||||||
|
if (clut_image) {
|
||||||
|
clut_filename = filename;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline float valF( unsigned char val )
|
rtengine::HaldCLUT::operator bool() const
|
||||||
{
|
{
|
||||||
return float( val ) / MAXVAL8;
|
return static_cast<bool>(clut_image);
|
||||||
}
|
}
|
||||||
|
|
||||||
// copypasted from http://www.quelsolaar.com/technology/clut.html
|
Glib::ustring rtengine::HaldCLUT::getFilename() const
|
||||||
void HaldCLUT::correct( const HaldCLUT::RawClut& clut, int level, float rr, float gg, float bb, float &outR, float &outG, float &outB )
|
|
||||||
{
|
{
|
||||||
int color, red, green, blue, i, j;
|
return clut_filename;
|
||||||
float tmp[6], r, g, b;
|
|
||||||
level = level * level;
|
|
||||||
|
|
||||||
red = rr * (float)(level - 1);
|
|
||||||
|
|
||||||
if(red > level - 2) {
|
|
||||||
red = (float)level - 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(red < 0) {
|
|
||||||
red = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
green = gg * (float)(level - 1);
|
|
||||||
|
|
||||||
if(green > level - 2) {
|
|
||||||
green = (float)level - 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(green < 0) {
|
|
||||||
green = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
blue = bb * (float)(level - 1);
|
|
||||||
|
|
||||||
if(blue > level - 2) {
|
|
||||||
blue = (float)level - 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(blue < 0) {
|
|
||||||
blue = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = rr * (float)(level - 1) - red;
|
|
||||||
g = gg * (float)(level - 1) - green;
|
|
||||||
b = bb * (float)(level - 1) - blue;
|
|
||||||
|
|
||||||
color = red + green * level + blue * level * level;
|
|
||||||
|
|
||||||
i = color * 3;
|
|
||||||
j = (color + 1) * 3;
|
|
||||||
|
|
||||||
tmp[0] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r;
|
|
||||||
tmp[1] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r;
|
|
||||||
tmp[2] = valF( clut[i] ) * (1 - r) + valF( clut[j] ) * r;
|
|
||||||
|
|
||||||
i = (color + level) * 3;
|
|
||||||
j = (color + level + 1) * 3;
|
|
||||||
|
|
||||||
tmp[3] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r;
|
|
||||||
tmp[4] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r;
|
|
||||||
tmp[5] = valF( clut[i] ) * (1 - r) + valF( clut[j] ) * r;
|
|
||||||
|
|
||||||
outR = tmp[0] * (1 - g) + tmp[3] * g;
|
|
||||||
outG = tmp[1] * (1 - g) + tmp[4] * g;
|
|
||||||
outB = tmp[2] * (1 - g) + tmp[5] * g;
|
|
||||||
|
|
||||||
i = (color + level * level) * 3;
|
|
||||||
j = (color + level * level + 1) * 3;
|
|
||||||
|
|
||||||
tmp[0] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r;
|
|
||||||
tmp[1] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r;
|
|
||||||
tmp[2] = valF( clut[i] ) * (1 - r) + valF( clut[j] ) * r;
|
|
||||||
|
|
||||||
i = (color + level + level * level) * 3;
|
|
||||||
j = (color + level + level * level + 1) * 3;
|
|
||||||
|
|
||||||
tmp[3] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r;
|
|
||||||
tmp[4] = valF( clut[i++] ) * (1 - r) + valF( clut[j++] ) * r;
|
|
||||||
tmp[5] = valF( clut[i] ) * (1 - r) + valF( clut[j] ) * r;
|
|
||||||
|
|
||||||
tmp[0] = tmp[0] * (1 - g) + tmp[3] * g;
|
|
||||||
tmp[1] = tmp[1] * (1 - g) + tmp[4] * g;
|
|
||||||
tmp[2] = tmp[2] * (1 - g) + tmp[5] * g;
|
|
||||||
|
|
||||||
outR = outR * (1 - b) + tmp[0] * b;
|
|
||||||
outG = outG * (1 - b) + tmp[1] * b;
|
|
||||||
outB = outB * (1 - b) + tmp[2] * b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void pos2xy( int pos, int imageSideSize, int &outX, int &outY )
|
Glib::ustring rtengine::HaldCLUT::getProfile() const
|
||||||
{
|
{
|
||||||
outX = pos / imageSideSize;
|
return clut_profile;
|
||||||
outY = pos % imageSideSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HaldCLUT::correct( Imagefloat &clutImage, int level, float rr, float gg, float bb, float &outR, float &outG, float &outB )
|
void rtengine::HaldCLUT::getRGB(float r, float g, float b, float& out_r, float& out_g, float& out_b) const
|
||||||
{
|
{
|
||||||
int color, red, green, blue, i, j;
|
const unsigned int level = clut_level * clut_level;
|
||||||
float tmp[6], r, g, b;
|
|
||||||
level = level * level;
|
|
||||||
int imageSideSize = clutImage.getW();
|
|
||||||
|
|
||||||
red = rr * (float)(level - 1);
|
const float flevel_minus_one = static_cast<float>(level - 1) / 65535.0f;
|
||||||
|
const float flevel_minus_two = static_cast<float>(level - 2);
|
||||||
|
|
||||||
if(red > level - 2) {
|
const unsigned int red = std::min(flevel_minus_two, r * flevel_minus_one);
|
||||||
red = (float)level - 2;
|
const unsigned int green = std::min(flevel_minus_two, g * flevel_minus_one);
|
||||||
}
|
const unsigned int blue = std::min(flevel_minus_two, b * flevel_minus_one);
|
||||||
|
|
||||||
if(red < 0) {
|
r = r * flevel_minus_one - red;
|
||||||
red = 0;
|
g = g * flevel_minus_one - green;
|
||||||
}
|
b = b * flevel_minus_one - blue;
|
||||||
|
|
||||||
green = gg * (float)(level - 1);
|
const unsigned int level_square = level * level;
|
||||||
|
|
||||||
if(green > level - 2) {
|
const unsigned int color = red + green * level + blue * level_square;
|
||||||
green = (float)level - 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(green < 0) {
|
unsigned int x[2];
|
||||||
green = 0;
|
unsigned int y[2];
|
||||||
}
|
posToXy(color, clut_image->getWidth(), x, y);
|
||||||
|
|
||||||
blue = bb * (float)(level - 1);
|
float tmp1[4] __attribute__((aligned(16)));
|
||||||
|
tmp1[0] = clut_image->r(y[0], x[0]) * (1 - r) + clut_image->r(y[1], x[1]) * r;
|
||||||
|
tmp1[1] = clut_image->g(y[0], x[0]) * (1 - r) + clut_image->g(y[1], x[1]) * r;
|
||||||
|
tmp1[2] = clut_image->b(y[0], x[0]) * (1 - r) + clut_image->b(y[1], x[1]) * r;
|
||||||
|
|
||||||
if(blue > level - 2) {
|
posToXy(color + level, clut_image->getWidth(), x, y);
|
||||||
blue = (float)level - 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(blue < 0) {
|
float tmp2[4] __attribute__((aligned(16)));
|
||||||
blue = 0;
|
tmp2[0] = clut_image->r(y[0], x[0]) * (1 - r) + clut_image->r(y[1], x[1]) * r;
|
||||||
}
|
tmp2[1] = clut_image->g(y[0], x[0]) * (1 - r) + clut_image->g(y[1], x[1]) * r;
|
||||||
|
tmp2[2] = clut_image->b(y[0], x[0]) * (1 - r) + clut_image->b(y[1], x[1]) * r;
|
||||||
|
|
||||||
r = rr * (float)(level - 1) - red;
|
float out[4] __attribute__((aligned(16)));
|
||||||
g = gg * (float)(level - 1) - green;
|
out[0] = tmp1[0] * (1 - g) + tmp2[0] * g;
|
||||||
b = bb * (float)(level - 1) - blue;
|
out[1] = tmp1[1] * (1 - g) + tmp2[1] * g;
|
||||||
|
out[2] = tmp1[2] * (1 - g) + tmp2[2] * g;
|
||||||
|
|
||||||
color = red + green * level + blue * level * level;
|
posToXy(color + level_square, clut_image->getWidth(), x, y);
|
||||||
|
|
||||||
|
tmp1[0] = clut_image->r(y[0], x[0]) * (1 - r) + clut_image->r(y[1], x[1]) * r;
|
||||||
|
tmp1[1] = clut_image->g(y[0], x[0]) * (1 - r) + clut_image->g(y[1], x[1]) * r;
|
||||||
|
tmp1[2] = clut_image->b(y[0], x[0]) * (1 - r) + clut_image->b(y[1], x[1]) * r;
|
||||||
|
|
||||||
i = color;
|
posToXy(color + level + level_square, clut_image->getWidth(), x, y);
|
||||||
j = color + 1;
|
|
||||||
int xi, yi, xj, yj;
|
|
||||||
pos2xy( i, imageSideSize, xi, yi );
|
|
||||||
pos2xy( j, imageSideSize, xj, yj );
|
|
||||||
|
|
||||||
tmp[0] = clutImage.r( xi, yi ) * (1 - r) + clutImage.r( xj, yj ) * r;
|
tmp2[0] = clut_image->r(y[0], x[0]) * (1 - r) + clut_image->r(y[1], x[1]) * r;
|
||||||
tmp[1] = clutImage.g( xi, yi ) * (1 - r) + clutImage.g( xj, yj ) * r;
|
tmp2[1] = clut_image->g(y[0], x[0]) * (1 - r) + clut_image->g(y[1], x[1]) * r;
|
||||||
tmp[2] = clutImage.b( xi, yi ) * (1 - r) + clutImage.b( xj, yj ) * r;
|
tmp2[2] = clut_image->b(y[0], x[0]) * (1 - r) + clut_image->b(y[1], x[1]) * r;
|
||||||
|
|
||||||
i = color + level;
|
tmp1[0] = tmp1[0] * (1 - g) + tmp2[0] * g;
|
||||||
j = color + level + 1;
|
tmp1[1] = tmp1[1] * (1 - g) + tmp2[1] * g;
|
||||||
pos2xy( i, imageSideSize, xi, yi );
|
tmp1[2] = tmp1[2] * (1 - g) + tmp2[2] * g;
|
||||||
pos2xy( j, imageSideSize, xj, yj );
|
|
||||||
|
|
||||||
tmp[3] = clutImage.r( xi, yi ) * (1 - r) + clutImage.r( xj, yj ) * r;
|
out_r = out[0] * (1 - b) + tmp1[0] * b;
|
||||||
tmp[4] = clutImage.g( xi, yi ) * (1 - r) + clutImage.g( xj, yj ) * r;
|
out_g = out[1] * (1 - b) + tmp1[1] * b;
|
||||||
tmp[5] = clutImage.b( xi, yi ) * (1 - r) + clutImage.b( xj, yj ) * r;
|
out_b = out[2] * (1 - b) + tmp1[2] * b;
|
||||||
|
}
|
||||||
outR = tmp[0] * (1 - g) + tmp[3] * g;
|
|
||||||
outG = tmp[1] * (1 - g) + tmp[4] * g;
|
rtengine::CLUTStore& rtengine::CLUTStore::getInstance()
|
||||||
outB = tmp[2] * (1 - g) + tmp[5] * g;
|
{
|
||||||
|
static CLUTStore instance;
|
||||||
i = color + level * level;
|
return instance;
|
||||||
j = color + level * level + 1;
|
}
|
||||||
pos2xy( i, imageSideSize, xi, yi );
|
|
||||||
pos2xy( j, imageSideSize, xj, yj );
|
std::shared_ptr<rtengine::CLUT> rtengine::CLUTStore::getClut(const Glib::ustring& filename)
|
||||||
|
{
|
||||||
tmp[0] = clutImage.r( xi, yi ) * (1 - r) + clutImage.r( xj, yj ) * r;
|
std::shared_ptr<rtengine::CLUT> result;
|
||||||
tmp[1] = clutImage.g( xi, yi ) * (1 - r) + clutImage.g( xj, yj ) * r;
|
|
||||||
tmp[2] = clutImage.b( xi, yi ) * (1 - r) + clutImage.b( xj, yj ) * r;
|
if (!cache.get(filename, result)) {
|
||||||
|
std::unique_ptr<rtengine::HaldCLUT> clut(new rtengine::HaldCLUT);
|
||||||
i = color + level + level * level;
|
if (clut->load(filename)) {
|
||||||
j = color + level + level * level + 1;
|
result = std::move(clut);
|
||||||
pos2xy( i, imageSideSize, xi, yi );
|
cache.insert(filename, result);
|
||||||
pos2xy( j, imageSideSize, xj, yj );
|
}
|
||||||
|
}
|
||||||
tmp[3] = clutImage.r( xi, yi ) * (1 - r) + clutImage.r( xj, yj ) * r;
|
|
||||||
tmp[4] = clutImage.g( xi, yi ) * (1 - r) + clutImage.g( xj, yj ) * r;
|
return result;
|
||||||
tmp[5] = clutImage.b( xi, yi ) * (1 - r) + clutImage.b( xj, yj ) * r;
|
}
|
||||||
|
|
||||||
tmp[0] = tmp[0] * (1 - g) + tmp[3] * g;
|
void rtengine::CLUTStore::releaseClut(const std::shared_ptr<rtengine::CLUT>& clut)
|
||||||
tmp[1] = tmp[1] * (1 - g) + tmp[4] * g;
|
{
|
||||||
tmp[2] = tmp[2] * (1 - g) + tmp[5] * g;
|
cache.remove(clut->getFilename());
|
||||||
|
}
|
||||||
outR = outR * (1 - b) + tmp[0] * b;
|
|
||||||
outG = outG * (1 - b) + tmp[1] * b;
|
void rtengine::CLUTStore::clearCache()
|
||||||
outB = outB * (1 - b) + tmp[2] * b;
|
{
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
rtengine::CLUTStore::CLUTStore() :
|
||||||
|
cache(options.clutCacheSize)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
@ -1,107 +1,78 @@
|
|||||||
#ifndef CLUT_STORE_INCLUDED
|
#pragma once
|
||||||
#define CLUT_STORE_INCLUDED
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <gtkmm.h>
|
#include <gtkmm.h>
|
||||||
#include "../rtgui/threadutils.h"
|
|
||||||
#include "imagefloat.h"
|
#include "imagefloat.h"
|
||||||
#include <vector>
|
#include "cache.h"
|
||||||
#include <map>
|
|
||||||
|
|
||||||
namespace rtengine
|
namespace rtengine
|
||||||
{
|
{
|
||||||
|
|
||||||
// simple CLUT interface
|
|
||||||
class CLUT
|
class CLUT
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void getRGB( float r, float g, float b, float &outR, float &outG, float &outB ) const = 0;
|
CLUT() = default;
|
||||||
virtual Glib::ustring profile() const = 0;
|
CLUT(const CLUT& other) = delete;
|
||||||
protected:
|
CLUT& operator =(const CLUT& other) = delete;
|
||||||
virtual ~CLUT() {};
|
virtual ~CLUT() = default;
|
||||||
|
|
||||||
|
virtual explicit operator bool() const = 0;
|
||||||
|
|
||||||
|
virtual Glib::ustring getFilename() const = 0;
|
||||||
|
virtual Glib::ustring getProfile() const = 0;
|
||||||
|
|
||||||
|
virtual void getRGB(float r, float g, float b, float& out_r, float& out_g, float& out_b) const = 0;
|
||||||
|
|
||||||
|
static void splitClutFilename(
|
||||||
|
const Glib::ustring& filename,
|
||||||
|
Glib::ustring& name,
|
||||||
|
Glib::ustring& extension,
|
||||||
|
Glib::ustring& profile_name
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
class HaldCLUT : public CLUT
|
class HaldCLUT
|
||||||
|
: public CLUT
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HaldCLUT();
|
HaldCLUT();
|
||||||
~HaldCLUT();
|
~HaldCLUT();
|
||||||
void load( Glib::ustring filename );
|
|
||||||
bool isValid() const;
|
|
||||||
|
|
||||||
void getRGB( float r, float g, float b, float &outR, float &outG, float &outB ) const;
|
bool load(const Glib::ustring& filename);
|
||||||
Glib::ustring profile() const;
|
|
||||||
|
|
||||||
typedef std::vector<unsigned char> RawClut; // using 8 bit for reduce memory usage
|
explicit operator bool() const;
|
||||||
static void correct( const RawClut&, int level, float r, float g, float b, float &outR, float &outG, float &outB );
|
|
||||||
static void correct( Imagefloat &clutImage, int level, float rr, float gg, float bb, float &outR, float &outG, float &outB );
|
Glib::ustring getFilename() const;
|
||||||
static Imagefloat* generateIdentImage( int level );
|
Glib::ustring getProfile() const;
|
||||||
static Imagefloat* loadFile( Glib::ustring filename, Glib::ustring workingColorSpace, int &outLevel );
|
|
||||||
|
void getRGB(float r, float g, float b, float& out_r, float& out_g, float& out_b) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::unique_ptr<Imagefloat> clut_image;
|
||||||
void loadClut( Imagefloat *img, RawClut &outClut );
|
unsigned int clut_level;
|
||||||
|
Glib::ustring clut_filename;
|
||||||
Imagefloat *m_clutImage;
|
Glib::ustring clut_profile;
|
||||||
int m_level;
|
|
||||||
Glib::ustring m_filename;
|
|
||||||
Glib::ustring m_profile;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// CLUT cache
|
|
||||||
class CLUTStore
|
class CLUTStore
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CLUTStore();
|
static CLUTStore& getInstance();
|
||||||
|
|
||||||
CLUT* getClut( const Glib::ustring& filename );
|
CLUTStore(const CLUTStore& other) = delete;
|
||||||
void releaseClut( const CLUT* clut );
|
CLUTStore& operator =(const CLUTStore& other) = delete;
|
||||||
|
|
||||||
|
std::shared_ptr<CLUT> getClut(const Glib::ustring& filename);
|
||||||
|
void releaseClut(const std::shared_ptr<CLUT>& clut);
|
||||||
|
|
||||||
void clearCache();
|
void clearCache();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::map<Glib::ustring, std::pair<int, HaldCLUT*> > Cluts;
|
CLUTStore();
|
||||||
|
|
||||||
Cluts m_cluts;
|
Cache<Glib::ustring, std::shared_ptr<CLUT>> cache;
|
||||||
MyMutex m_mutex;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void splitClutFilename( Glib::ustring filename, Glib::ustring &name, Glib::ustring &extension, Glib::ustring &profileName );
|
}
|
||||||
|
|
||||||
}; //namespace rtengine
|
|
||||||
|
|
||||||
extern rtengine::CLUTStore clutStore;
|
|
||||||
|
|
||||||
namespace rtengine
|
|
||||||
{
|
|
||||||
|
|
||||||
//support class for automate call of clutStore.releaseClut()
|
|
||||||
class ClutPtr
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ClutPtr() : m_point( 0 ) {}
|
|
||||||
explicit ClutPtr(CLUT *p) : m_point( p ) {}
|
|
||||||
~ClutPtr()
|
|
||||||
{
|
|
||||||
clutStore.releaseClut( m_point );
|
|
||||||
}
|
|
||||||
const CLUT* operator-> () const
|
|
||||||
{
|
|
||||||
return m_point;
|
|
||||||
}
|
|
||||||
operator bool() const
|
|
||||||
{
|
|
||||||
return m_point != 0;
|
|
||||||
}
|
|
||||||
void set( CLUT *p )
|
|
||||||
{
|
|
||||||
m_point = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ClutPtr& operator=(ClutPtr const& cp );
|
|
||||||
CLUT *m_point;
|
|
||||||
};
|
|
||||||
|
|
||||||
}; //namespace rtengine
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -3205,21 +3205,21 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClutPtr colorLUT;
|
std::shared_ptr<CLUT> colorLUT;
|
||||||
bool clutAndWorkingProfilesAreSame = false;
|
bool clutAndWorkingProfilesAreSame = false;
|
||||||
TMatrix work2xyz, xyz2clut, clut2xyz, xyz2work;
|
TMatrix work2xyz, xyz2clut, clut2xyz, xyz2work;
|
||||||
|
|
||||||
if ( params->filmSimulation.enabled && !params->filmSimulation.clutFilename.empty() ) {
|
if ( params->filmSimulation.enabled && !params->filmSimulation.clutFilename.empty() ) {
|
||||||
colorLUT.set( clutStore.getClut( params->filmSimulation.clutFilename ) );
|
colorLUT = CLUTStore::getInstance().getClut( params->filmSimulation.clutFilename );
|
||||||
|
|
||||||
if ( colorLUT ) {
|
if ( colorLUT ) {
|
||||||
clutAndWorkingProfilesAreSame = colorLUT->profile() == params->icm.working;
|
clutAndWorkingProfilesAreSame = colorLUT->getProfile() == params->icm.working;
|
||||||
|
|
||||||
if ( !clutAndWorkingProfilesAreSame ) {
|
if ( !clutAndWorkingProfilesAreSame ) {
|
||||||
work2xyz = iccStore->workingSpaceMatrix( params->icm.working );
|
work2xyz = iccStore->workingSpaceMatrix( params->icm.working );
|
||||||
xyz2clut = iccStore->workingSpaceInverseMatrix( colorLUT->profile() );
|
xyz2clut = iccStore->workingSpaceInverseMatrix( colorLUT->getProfile() );
|
||||||
xyz2work = iccStore->workingSpaceInverseMatrix( params->icm.working );
|
xyz2work = iccStore->workingSpaceInverseMatrix( params->icm.working );
|
||||||
clut2xyz = iccStore->workingSpaceMatrix( colorLUT->profile() );
|
clut2xyz = iccStore->workingSpaceMatrix( colorLUT->getProfile() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4337,6 +4337,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer
|
|||||||
|
|
||||||
//Film Simulations
|
//Film Simulations
|
||||||
if ( colorLUT ) {
|
if ( colorLUT ) {
|
||||||
|
MyTime start, stop;
|
||||||
|
start.set();
|
||||||
for (int i = istart, ti = 0; i < tH; i++, ti++) {
|
for (int i = istart, ti = 0; i < tH; i++, ti++) {
|
||||||
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
|
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
|
||||||
float &sourceR = rtemp[ti * TS + tj];
|
float &sourceR = rtemp[ti * TS + tj];
|
||||||
@ -4375,6 +4377,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stop.set();
|
||||||
|
printf("Film simulation took %dus.\n", stop.etime(start));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -857,7 +857,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p
|
|||||||
|
|
||||||
// if clut was used and size of clut cache == 1 we free the memory used by the clutstore (default clut cache size = 1 for 32 bit OS)
|
// if clut was used and size of clut cache == 1 we free the memory used by the clutstore (default clut cache size = 1 for 32 bit OS)
|
||||||
if ( params.filmSimulation.enabled && !params.filmSimulation.clutFilename.empty() && options.clutCacheSize == 1) {
|
if ( params.filmSimulation.enabled && !params.filmSimulation.clutFilename.empty() && options.clutCacheSize == 1) {
|
||||||
clutStore.clearCache();
|
CLUTStore::getInstance().clearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
// freeing up some memory
|
// freeing up some memory
|
||||||
|
@ -72,7 +72,7 @@ void FilmSimulation::onClutSelected()
|
|||||||
|
|
||||||
if ( getEnabled() && !currentClutFilename.empty() && listener && currentClutFilename != m_oldClutFilename ) {
|
if ( getEnabled() && !currentClutFilename.empty() && listener && currentClutFilename != m_oldClutFilename ) {
|
||||||
Glib::ustring clutName, dummy;
|
Glib::ustring clutName, dummy;
|
||||||
splitClutFilename( currentClutFilename, clutName, dummy, dummy );
|
CLUT::splitClutFilename( currentClutFilename, clutName, dummy, dummy );
|
||||||
listener->panelChanged( EvFilmSimulationFilename, clutName );
|
listener->panelChanged( EvFilmSimulationFilename, clutName );
|
||||||
|
|
||||||
m_oldClutFilename = currentClutFilename;
|
m_oldClutFilename = currentClutFilename;
|
||||||
@ -132,7 +132,7 @@ void FilmSimulation::read( const rtengine::procparams::ProcParams* pp, const Par
|
|||||||
|
|
||||||
if ( !get_inconsistent() && !pp->filmSimulation.enabled ) {
|
if ( !get_inconsistent() && !pp->filmSimulation.enabled ) {
|
||||||
if (options.clutCacheSize == 1) {
|
if (options.clutCacheSize == 1) {
|
||||||
clutStore.clearCache();
|
CLUTStore::getInstance().clearCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ int ClutComboBox::parseDir (const Glib::ustring& path)
|
|||||||
for (const auto& entry : entries) {
|
for (const auto& entry : entries) {
|
||||||
|
|
||||||
Glib::ustring name, extension, profileName;
|
Glib::ustring name, extension, profileName;
|
||||||
splitClutFilename (entry, name, extension, profileName);
|
CLUT::splitClutFilename (entry, name, extension, profileName);
|
||||||
|
|
||||||
extension = extension.casefold ();
|
extension = extension.casefold ();
|
||||||
if (extension.compare ("tif") != 0 && extension.compare ("png") != 0) {
|
if (extension.compare ("tif") != 0 && extension.compare ("png") != 0) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user