merge with Dev
This commit is contained in:
commit
bfca2e2dd6
@ -2,7 +2,7 @@
|
||||
This file is part of RawTherapee.
|
||||
|
||||
Copyright (c) 2016-2018 TooWaBoo
|
||||
Version 2.96
|
||||
Version 2.98
|
||||
|
||||
RawTherapee is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -164,7 +164,9 @@ undershoot {
|
||||
}
|
||||
|
||||
label {
|
||||
margin: 0 0.19em;
|
||||
padding: 0.083333333333333333em 0;
|
||||
margin: 0.19em;
|
||||
min-height: 1.333333333333333333em;
|
||||
}
|
||||
|
||||
/*** Frames ************************************************************************************/
|
||||
@ -323,11 +325,8 @@ fontchooser scrolledwindow,
|
||||
padding-bottom: 0.25em;
|
||||
background-color: @bg-dark-grey;
|
||||
}
|
||||
#Navigator box label {
|
||||
padding: 0.166666666666666666em 0;
|
||||
}
|
||||
#Navigator > label:nth-child(2) {
|
||||
margin-top: 0.5em;
|
||||
#Navigator label {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*** end ***************************************************************************************/
|
||||
@ -927,14 +926,18 @@ window.csd:not(.fullscreen) #MainNotebook > header.top {
|
||||
border-bottom: 0.083333333333333333em solid @view-grid-border;
|
||||
margin-left: 0.083333333333333333em;
|
||||
margin-right: 0.083333333333333333em;
|
||||
padding: 0 0.19em;
|
||||
}
|
||||
#ToolPanelNotebook > header tabs {
|
||||
margin-bottom: 0.333333333333333333em;
|
||||
margin: 0 0 0.25em;
|
||||
}
|
||||
#ToolPanelNotebook > header tab > box > image{
|
||||
#ToolPanelNotebook > header tab {
|
||||
padding: 0;
|
||||
}
|
||||
#ToolPanelNotebook > header tab image{
|
||||
min-height: 2em;
|
||||
min-width: 2em;
|
||||
margin: 0.25em 0 0.333333333333333333em;
|
||||
margin: 0.19em 0.25em 0.333333333333333333em;
|
||||
padding: 0;
|
||||
}
|
||||
#ToolPanelNotebook > stack {
|
||||
@ -963,11 +966,6 @@ window.csd:not(.fullscreen) #MainNotebook > header.top {
|
||||
#PrefNotebook > header {
|
||||
margin: -0.666666666666666666em -0.666666666666666666em 0.333333333333333333em;
|
||||
}
|
||||
#PrefNotebook > header tab label,
|
||||
#AboutNotebook > header tab label {
|
||||
padding-top: 0.25em;
|
||||
padding-bottom: 0.25em;
|
||||
}
|
||||
#PrefNotebook > stack {
|
||||
margin: 0 -0.666666666666666666em;
|
||||
}
|
||||
@ -994,9 +992,6 @@ window.csd:not(.fullscreen) #MainNotebook > header.top {
|
||||
background-color: @bg-dark-grey;
|
||||
padding-left: 0.333333333333333333em;
|
||||
}
|
||||
#MetaPanelNotebook > header tab label{
|
||||
margin: 0.083333333333333333em 0.083333333333333333em 0.19em;
|
||||
}
|
||||
#MetaPanelNotebook > stack {
|
||||
background-color: @bg-dark-grey;
|
||||
padding: 0 0 0.5em 0;
|
||||
@ -1036,8 +1031,10 @@ window.csd:not(.fullscreen) #MainNotebook > header.top {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#MetaPanelNotebook label {
|
||||
padding: 0.083333333333333333em 0 0;
|
||||
#MetaPanelNotebook stack label {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*** end ***************************************************************************************/
|
||||
@ -1093,9 +1090,13 @@ window.csd:not(.fullscreen) #MainNotebook > header.top {
|
||||
border-left: 0.083333333333333333em solid @bg-dark-grey;
|
||||
}
|
||||
|
||||
/* !!! Must be same height as "Small Lock Button" */
|
||||
#BeforeAfterContainer label {
|
||||
min-height: 2.666666666666666666em;
|
||||
padding: 0 0.5em;
|
||||
min-height: 2em;
|
||||
min-width: 2em;
|
||||
margin: 0.25em 0;
|
||||
border: 0.083333333333333333em solid transparent;
|
||||
}
|
||||
|
||||
#EditorToolbarTop {
|
||||
@ -1478,13 +1479,21 @@ scale + image + image + button.flat {
|
||||
margin-bottom: 0.095em;
|
||||
}
|
||||
|
||||
/*Color chooser & buttons */
|
||||
/* Color chooser & buttons */
|
||||
button.color {
|
||||
min-height: 1.166666666666666666em;
|
||||
min-width: 2.75em;
|
||||
padding: 0.25em;
|
||||
min-width: 3.25em;
|
||||
box-shadow: none;
|
||||
background-image: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
button.color colorswatch,
|
||||
|
||||
button.color colorswatch {
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
margin: 1px;
|
||||
border-radius: 0.2em;
|
||||
}
|
||||
|
||||
colorchooser colorswatch {
|
||||
border: 1px solid @bg-button-border;
|
||||
}
|
||||
@ -1492,6 +1501,13 @@ colorchooser colorswatch#add-color-button:first-child {
|
||||
border-radius: 5.5px 0 0 5.5px;
|
||||
}
|
||||
|
||||
/* Font chooser button */
|
||||
button.font label{
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
margin: 0 0.19em;
|
||||
}
|
||||
|
||||
/* Save, Cancel, OK ... buttons */
|
||||
dialog .dialog-action-area button {
|
||||
min-height: 2.166666666666666666em;
|
||||
@ -1708,9 +1724,6 @@ window treeview > header image {
|
||||
min-width: 1.333333333333333333em;
|
||||
}
|
||||
|
||||
.view button.text-button label {
|
||||
margin: 0;
|
||||
}
|
||||
window .view button {
|
||||
border: none;
|
||||
border-bottom: 0.083333333333333333em solid @view-grid-border;
|
||||
@ -1792,11 +1805,7 @@ popover button.text-button:active {
|
||||
/*** end ***************************************************************************************/
|
||||
|
||||
/*** Checkbox & Radio **************************************************************************/
|
||||
checkbutton {
|
||||
padding: 0;
|
||||
margin: 0.083333333333333333em 0.19em;
|
||||
min-height: 1.666666666666666666em;/*x*/
|
||||
}
|
||||
checkbutton,
|
||||
radiobutton {
|
||||
padding: 0.083333333333333333em 0;
|
||||
margin: 0.19em;
|
||||
@ -1839,16 +1848,11 @@ frame > checkbutton check{
|
||||
}
|
||||
|
||||
#PartialPaste checkbutton {
|
||||
min-height: 1.166666666666666666em;
|
||||
margin-top: calc(0.416666666666666666em - 4px);
|
||||
margin-bottom: calc(0.416666666666666666em - 4px)
|
||||
padding: 0;
|
||||
margin: 0.19em 0 0 0.583333333333333333em;
|
||||
}
|
||||
#PartialPaste checkbutton:not(#PartialPasteHeader) {
|
||||
margin-left: 1.166666666666666666em;
|
||||
}
|
||||
#PartialPasteHeader {
|
||||
margin-left: 0.5em;
|
||||
padding-top: calc(0.666666666666666666em - 5px)
|
||||
margin: 0 0 0 1.166666666666666666em;
|
||||
}
|
||||
|
||||
/*** end ***************************************************************************************/
|
||||
@ -1908,8 +1912,8 @@ spinbutton {
|
||||
margin-bottom: 0.333333333333333333em;
|
||||
}
|
||||
#MyExpander checkbutton + label + spinbutton {
|
||||
margin-top: 0.333333333333333333em;
|
||||
margin-bottom: 0.333333333333333333em;
|
||||
margin-top: 0.416666666666666666em;
|
||||
margin-bottom: 0.416666666666666666em;
|
||||
}
|
||||
/**/
|
||||
|
||||
|
@ -824,37 +824,13 @@ void Crop::update(int todo)
|
||||
const Glib::ustring profile = params.icm.workingProfile;
|
||||
|
||||
if (profile == "sRGB" || profile == "Adobe RGB" || profile == "ProPhoto" || profile == "WideGamut" || profile == "BruceRGB" || profile == "Beta RGB" || profile == "BestRGB" || profile == "Rec2020" || profile == "ACESp0" || profile == "ACESp1") {
|
||||
int cw = baseCrop->getWidth();
|
||||
int ch = baseCrop->getHeight();
|
||||
const int cw = baseCrop->getWidth();
|
||||
const int ch = baseCrop->getHeight();
|
||||
workingCrop = new Imagefloat(cw, ch);
|
||||
baseCrop->copyData(workingCrop);
|
||||
//first put gamma TRC to 1
|
||||
Imagefloat* readyImg0 = parent->ipf.workingtrc(workingCrop, cw, ch, -5, params.icm.workingProfile, 2.4, 12.92310);
|
||||
#pragma omp parallel for
|
||||
|
||||
for (int row = 0; row < ch; row++) {
|
||||
for (int col = 0; col < cw; col++) {
|
||||
workingCrop->r(row, col) = (float)readyImg0->r(row, col);
|
||||
workingCrop->g(row, col) = (float)readyImg0->g(row, col);
|
||||
workingCrop->b(row, col) = (float)readyImg0->b(row, col);
|
||||
}
|
||||
}
|
||||
|
||||
delete readyImg0;
|
||||
|
||||
parent->ipf.workingtrc(baseCrop, workingCrop, cw, ch, -5, params.icm.workingProfile, 2.4, 12.92310, true, false);
|
||||
//adjust gamma TRC
|
||||
Imagefloat* readyImg = parent->ipf.workingtrc(workingCrop, cw, ch, 5, params.icm.workingProfile, params.icm.workingTRCGamma, params.icm.workingTRCSlope);
|
||||
#pragma omp parallel for
|
||||
|
||||
for (int row = 0; row < ch; row++) {
|
||||
for (int col = 0; col < cw; col++) {
|
||||
workingCrop->r(row, col) = (float)readyImg->r(row, col);
|
||||
workingCrop->g(row, col) = (float)readyImg->g(row, col);
|
||||
workingCrop->b(row, col) = (float)readyImg->b(row, col);
|
||||
}
|
||||
}
|
||||
|
||||
delete readyImg;
|
||||
parent->ipf.workingtrc(workingCrop, workingCrop, cw, ch, 5, params.icm.workingProfile, params.icm.workingTRCGamma, params.icm.workingTRCSlope, false, true);
|
||||
}
|
||||
}
|
||||
double rrm, ggm, bbm;
|
||||
|
@ -38,6 +38,8 @@
|
||||
#include "../rtgui/threadutils.h"
|
||||
#include "lcms2_plugin.h"
|
||||
|
||||
#include "color.h"
|
||||
|
||||
#include "cJSON.h"
|
||||
#define inkc_constant 0x696E6B43
|
||||
namespace rtengine
|
||||
@ -208,8 +210,85 @@ const char* wpnames[] = {"sRGB", "Adobe RGB", "ProPhoto", "WideGamut", "BruceRGB
|
||||
// high g=1.3 s=3.35 for high dynamic images
|
||||
//low g=2.6 s=6.9 for low contrast images
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// helper functions to fix V2 profiles TRCs, used in
|
||||
// rtengine::ProfileContent::toProfile()
|
||||
// see https://github.com/Beep6581/RawTherapee/issues/5026
|
||||
// -----------------------------------------------------------------------------
|
||||
bool is_RTv2_profile(cmsHPROFILE profile)
|
||||
{
|
||||
if (int(cmsGetProfileVersion(profile)) != 2) {
|
||||
return false;
|
||||
}
|
||||
const cmsMLU *mlu = static_cast<const cmsMLU *>(cmsReadTag(profile, cmsSigDeviceMfgDescTag));
|
||||
if (!mlu) {
|
||||
return false;
|
||||
}
|
||||
cmsUInt32Number sz = cmsMLUgetASCII(mlu, "en", "US", nullptr, 0);
|
||||
if (!sz) {
|
||||
return false;
|
||||
}
|
||||
std::vector<char> buf(sz);
|
||||
cmsMLUgetASCII(mlu, "en", "US", &buf[0], sz);
|
||||
buf.back() = 0; // sanity
|
||||
return strcmp(&buf[0], "RawTherapee") == 0;
|
||||
}
|
||||
|
||||
|
||||
bool get_RT_gamma_slope(cmsHPROFILE profile, double &gammatag, double &slopetag)
|
||||
{
|
||||
const cmsMLU *modelDescMLU = static_cast<const cmsMLU *>(cmsReadTag(profile, cmsSigDeviceModelDescTag));
|
||||
if (modelDescMLU) {
|
||||
cmsUInt32Number count = cmsMLUgetWide(modelDescMLU, "en", "US", nullptr, 0);
|
||||
if (count) {
|
||||
std::vector<wchar_t> vbuf(count);
|
||||
wchar_t *buffer = &vbuf[0];
|
||||
count = cmsMLUgetWide(modelDescMLU, "en", "US", buffer, count);
|
||||
Glib::ustring modelDesc;
|
||||
#if __SIZEOF_WCHAR_T__ == 2
|
||||
char *cModelDesc = g_utf16_to_utf8((unsigned short int*)buffer, -1, nullptr, nullptr, nullptr); // convert to utf-8 in a buffer allocated by glib
|
||||
if (cModelDesc) {
|
||||
modelDesc.assign(cModelDesc);
|
||||
g_free(cModelDesc);
|
||||
}
|
||||
#else
|
||||
modelDesc = utf32_to_utf8(buffer, count);
|
||||
#endif
|
||||
if (!modelDesc.empty()) {
|
||||
std::size_t pos = modelDesc.find("g");
|
||||
std::size_t posmid = modelDesc.find("s");
|
||||
std::size_t posend = modelDesc.find("!");
|
||||
std::string strgamma = modelDesc.substr(pos + 1, (posmid - pos));
|
||||
gammatag = std::stod(strgamma.c_str());
|
||||
std::string strslope = modelDesc.substr(posmid + 1, (posend - posmid));
|
||||
slopetag = std::stod(strslope.c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Glib::ustring get_profile_description(cmsHPROFILE profile)
|
||||
{
|
||||
const cmsMLU *mlu = static_cast<const cmsMLU *>(cmsReadTag(profile, cmsSigProfileDescriptionTag));
|
||||
if (!mlu) {
|
||||
return "";
|
||||
}
|
||||
cmsUInt32Number sz = cmsMLUgetASCII(mlu, "en", "US", nullptr, 0);
|
||||
if (!sz) {
|
||||
return "";
|
||||
}
|
||||
std::vector<char> buf(sz);
|
||||
cmsMLUgetASCII(mlu, "en", "US", &buf[0], sz);
|
||||
buf.back() = 0; // sanity
|
||||
return std::string(&buf[0]);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
rtengine::ProfileContent::ProfileContent() = default;
|
||||
|
||||
rtengine::ProfileContent::ProfileContent(const Glib::ustring& fileName)
|
||||
@ -255,11 +334,52 @@ rtengine::ProfileContent::ProfileContent(cmsHPROFILE hProfile)
|
||||
|
||||
cmsHPROFILE rtengine::ProfileContent::toProfile() const
|
||||
{
|
||||
cmsHPROFILE profile = nullptr;
|
||||
if (!data.empty()) {
|
||||
profile = cmsOpenProfileFromMem(data.c_str(), data.size());
|
||||
// if this is a V2 profile generated by RawTherapee, we rebuild the
|
||||
// TRC. See https://github.com/Beep6581/RawTherapee/issues/5026 and
|
||||
// the references in there
|
||||
if (profile && is_RTv2_profile(profile)) {
|
||||
double gammatag, slopetag;
|
||||
if (get_RT_gamma_slope(profile, gammatag, slopetag)) {
|
||||
constexpr double eps = 0.000000001; // not divide by zero
|
||||
double pwr = 1.0 / gammatag;
|
||||
double ts = slopetag;
|
||||
double slope = slopetag == 0 ? eps : slopetag;
|
||||
|
||||
return
|
||||
!data.empty()
|
||||
? cmsOpenProfileFromMem(data.c_str(), data.size())
|
||||
: nullptr;
|
||||
GammaValues g_b; //gamma parameters
|
||||
Color::calcGamma(pwr, ts, 0, g_b); // call to calcGamma with selected gamma and slope : return parameters for LCMS2
|
||||
cmsFloat64Number gammaParams[7]; //gamma parameters
|
||||
gammaParams[4] = g_b[3] * ts;
|
||||
gammaParams[0] = gammatag;
|
||||
gammaParams[1] = 1. / (1.0 + g_b[4]);
|
||||
gammaParams[2] = g_b[4] / (1.0 + g_b[4]);
|
||||
gammaParams[3] = 1. / slope;
|
||||
gammaParams[5] = 0.0;
|
||||
gammaParams[6] = 0.0;
|
||||
|
||||
cmsToneCurve* GammaTRC;
|
||||
if (slopetag == 0.) {
|
||||
//printf("gammatag=%f\n", gammatag);
|
||||
GammaTRC = cmsBuildGamma(NULL, gammatag);
|
||||
} else {
|
||||
GammaTRC = cmsBuildParametricToneCurve(nullptr, 5, gammaParams); //5 = smoother than 4
|
||||
}
|
||||
cmsWriteTag(profile, cmsSigRedTRCTag, GammaTRC);
|
||||
cmsWriteTag(profile, cmsSigGreenTRCTag, GammaTRC);
|
||||
cmsWriteTag(profile, cmsSigBlueTRCTag, GammaTRC);
|
||||
cmsFreeToneCurve(GammaTRC);
|
||||
|
||||
if (settings->verbose) {
|
||||
std::cout << "ICCStore: rebuilt TRC for RTv2 profile " << get_profile_description(profile) << ": gamma=" << gammatag << ", slope=" << slopetag << std::endl;
|
||||
}
|
||||
} else if (settings->verbose) {
|
||||
std::cout << "ICCStore: no gamma/slope info found for RTv2 profile " << get_profile_description(profile) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
const std::string& rtengine::ProfileContent::getData() const
|
||||
|
@ -474,52 +474,6 @@ void Imagefloat::calcCroppedHistogram(const ProcParams ¶ms, float scale, LUT
|
||||
|
||||
}
|
||||
|
||||
// Parallelized transformation; create transform with cmsFLAGS_NOCACHE!
|
||||
void Imagefloat::ExecCMSTransform2(cmsHTRANSFORM hTransform)
|
||||
{
|
||||
|
||||
// LittleCMS cannot parallelize planar setups -- Hombre: LCMS2.4 can! But it we use this new feature, memory allocation
|
||||
// have to be modified too to build temporary buffers that allow multi processor execution
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel
|
||||
#endif
|
||||
{
|
||||
AlignedBuffer<float> pBuf(width * 3);
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp for schedule(static)
|
||||
#endif
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
float *p = pBuf.data, *pR = r(y), *pG = g(y), *pB = b(y);
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
*(p++) = *(pR++)/ 65535.f;
|
||||
*(p++) = *(pG++)/ 65535.f;
|
||||
*(p++) = *(pB++)/ 65535.f;
|
||||
|
||||
}
|
||||
|
||||
cmsDoTransform (hTransform, pBuf.data, pBuf.data, width);
|
||||
|
||||
p = pBuf.data;
|
||||
pR = r(y);
|
||||
pG = g(y);
|
||||
pB = b(y);
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
*(pR++) = *(p++);
|
||||
*(pG++) = *(p++);
|
||||
*(pB++) = *(p++);
|
||||
}
|
||||
} // End of parallelization
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Parallelized transformation; create transform with cmsFLAGS_NOCACHE!
|
||||
void Imagefloat::ExecCMSTransform(cmsHTRANSFORM hTransform)
|
||||
{
|
||||
@ -533,7 +487,7 @@ void Imagefloat::ExecCMSTransform(cmsHTRANSFORM hTransform)
|
||||
AlignedBuffer<float> pBuf(width * 3);
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp for schedule(static)
|
||||
#pragma omp for schedule(dynamic, 16)
|
||||
#endif
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
|
@ -222,8 +222,6 @@ public:
|
||||
void normalizeFloatTo1();
|
||||
void normalizeFloatTo65535();
|
||||
void calcCroppedHistogram(const ProcParams ¶ms, float scale, LUTu & hist);
|
||||
void ExecCMSTransform2(cmsHTRANSFORM hTransform);
|
||||
|
||||
void ExecCMSTransform(cmsHTRANSFORM hTransform);
|
||||
void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy);
|
||||
};
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include "color.h"
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
@ -540,38 +539,15 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange)
|
||||
orig_prev->copyData(oprevi);
|
||||
}
|
||||
|
||||
Glib::ustring profile = params.icm.workingProfile;
|
||||
const Glib::ustring profile = params.icm.workingProfile;
|
||||
|
||||
if (profile == "sRGB" || profile == "Adobe RGB" || profile == "ProPhoto" || profile == "WideGamut" || profile == "BruceRGB" || profile == "Beta RGB" || profile == "BestRGB" || profile == "Rec2020" || profile == "ACESp0" || profile == "ACESp1") {
|
||||
int cw = oprevi->getWidth();
|
||||
int ch = oprevi->getHeight();
|
||||
const int cw = oprevi->getWidth();
|
||||
const int ch = oprevi->getHeight();
|
||||
// put gamma TRC to 1
|
||||
Imagefloat* readyImg0 = ipf.workingtrc(oprevi, cw, ch, -5, params.icm.workingProfile, 2.4, 12.92310);
|
||||
#pragma omp parallel for
|
||||
|
||||
for (int row = 0; row < ch; row++) {
|
||||
for (int col = 0; col < cw; col++) {
|
||||
oprevi->r(row, col) = (float)readyImg0->r(row, col);
|
||||
oprevi->g(row, col) = (float)readyImg0->g(row, col);
|
||||
oprevi->b(row, col) = (float)readyImg0->b(row, col);
|
||||
}
|
||||
}
|
||||
|
||||
delete readyImg0;
|
||||
ipf.workingtrc(oprevi, oprevi, cw, ch, -5, params.icm.workingProfile, 2.4, 12.92310, true, false);
|
||||
//adjust TRC
|
||||
Imagefloat* readyImg = ipf.workingtrc(oprevi, cw, ch, 5, params.icm.workingProfile, params.icm.workingTRCGamma, params.icm.workingTRCSlope);
|
||||
#pragma omp parallel for
|
||||
|
||||
for (int row = 0; row < ch; row++) {
|
||||
for (int col = 0; col < cw; col++) {
|
||||
oprevi->r(row, col) = (float)readyImg->r(row, col);
|
||||
oprevi->g(row, col) = (float)readyImg->g(row, col);
|
||||
oprevi->b(row, col) = (float)readyImg->b(row, col);
|
||||
}
|
||||
}
|
||||
|
||||
delete readyImg;
|
||||
|
||||
ipf.workingtrc(oprevi, oprevi, cw, ch, 5, params.icm.workingProfile, params.icm.workingTRCGamma, params.icm.workingTRCSlope, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -407,7 +407,7 @@ public:
|
||||
Image8* lab2rgb(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool consider_histogram_settings = true);
|
||||
Imagefloat* lab2rgbOut(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm);
|
||||
// CieImage *ciec;
|
||||
Imagefloat* workingtrc(Imagefloat* working, int cw, int ch, int mul, Glib::ustring profile, double gampos, double slpos);
|
||||
void workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, int ch, int mul, const Glib::ustring &profile, double gampos, double slpos, bool normalizeIn = true, bool normalizeOut = true);
|
||||
|
||||
bool transCoord(int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1, const LensCorrection *pLCPMap = nullptr);
|
||||
bool transCoord(int W, int H, const std::vector<Coord2D> &src, std::vector<Coord2D> &red, std::vector<Coord2D> &green, std::vector<Coord2D> &blue, double ascaleDef = -1, const LensCorrection *pLCPMap = nullptr);
|
||||
|
@ -303,82 +303,7 @@ Imagefloat* ImProcFunctions::lab2rgbOut(LabImage* lab, int cx, int cy, int cw, i
|
||||
}
|
||||
|
||||
Imagefloat* image = new Imagefloat(cw, ch);
|
||||
|
||||
cmsHPROFILE oprof = nullptr;
|
||||
|
||||
oprof = ICCStore::getInstance()->getProfile(icm.outputProfile);
|
||||
Glib::ustring outtest = icm.outputProfile;
|
||||
std::string fileis_RTv2 = outtest.substr(0, 4);
|
||||
//printf("IsRTv2=%s\n", fileis_RTv2.c_str());
|
||||
if(fileis_RTv2 == "RTv2") {//Only fot ICC v2 : read tag from desc to retrieve gamma and slope save before in generate ICC v2
|
||||
//due to bug in LCMS in CmsToneCurve
|
||||
//printf("icmout=%s \n",icm.output.c_str());
|
||||
GammaValues g_b; //gamma parameters
|
||||
const double eps = 0.000000001; // not divide by zero
|
||||
double gammatag = 2.4;
|
||||
double slopetag = 12.92310;
|
||||
cmsMLU *modelDescMLU = (cmsMLU*) (cmsReadTag(oprof, cmsSigDeviceModelDescTag));
|
||||
if (modelDescMLU) {
|
||||
cmsUInt32Number count = cmsMLUgetWide(modelDescMLU, "en", "US", nullptr, 0); // get buffer length first
|
||||
if (count) {
|
||||
wchar_t *buffer = new wchar_t[count];
|
||||
count = cmsMLUgetWide(modelDescMLU, "en", "US", buffer, count); // now put the string in the buffer
|
||||
Glib::ustring modelDesc;
|
||||
#if __SIZEOF_WCHAR_T__ == 2
|
||||
char* cModelDesc = g_utf16_to_utf8((unsigned short int*)buffer, -1, nullptr, nullptr, nullptr); // convert to utf-8 in a buffer allocated by glib
|
||||
if (cModelDesc) {
|
||||
modelDesc.assign(cModelDesc);
|
||||
g_free(cModelDesc);
|
||||
}
|
||||
#else
|
||||
modelDesc = utf32_to_utf8(buffer, count);
|
||||
#endif
|
||||
delete [] buffer;
|
||||
if (!modelDesc.empty()) {
|
||||
std::size_t pos = modelDesc.find("g");
|
||||
std::size_t posmid = modelDesc.find("s");
|
||||
std::size_t posend = modelDesc.find("!");
|
||||
std::string strgamma = modelDesc.substr(pos + 1, (posmid - pos));
|
||||
gammatag = std::stod(strgamma.c_str());
|
||||
std::string strslope = modelDesc.substr(posmid + 1, (posend - posmid));
|
||||
slopetag = std::stod(strslope.c_str());
|
||||
// printf("gam=%f slo=%f\n", gammatag, slopetag);
|
||||
}
|
||||
} else {
|
||||
printf("Error: lab2rgbOut / String length is null!\n");
|
||||
}
|
||||
} else {
|
||||
printf("Error: lab2rgbOut / cmsReadTag/cmsSigDeviceModelDescTag failed!\n");
|
||||
}
|
||||
|
||||
double pwr = 1.0 / gammatag;
|
||||
double ts = slopetag;
|
||||
double slope = slopetag == 0 ? eps : slopetag;
|
||||
|
||||
int mode = 0;
|
||||
Color::calcGamma(pwr, ts, mode, g_b); // call to calcGamma with selected gamma and slope : return parameters for LCMS2
|
||||
cmsFloat64Number gammaParams[7]; //gamma parameters
|
||||
gammaParams[4] = g_b[3] * ts;
|
||||
gammaParams[0] = gammatag;
|
||||
gammaParams[1] = 1. / (1.0 + g_b[4]);
|
||||
gammaParams[2] = g_b[4] / (1.0 + g_b[4]);
|
||||
gammaParams[3] = 1. / slope;
|
||||
gammaParams[5] = 0.0;
|
||||
gammaParams[6] = 0.0;
|
||||
|
||||
cmsToneCurve* GammaTRC[3];
|
||||
if(slopetag == 0.) {
|
||||
//printf("gammatag=%f\n", gammatag);
|
||||
GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildGamma(NULL, gammatag);
|
||||
}
|
||||
else {
|
||||
GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(nullptr, 5, gammaParams); //5 = smoother than 4
|
||||
}
|
||||
cmsWriteTag(oprof, cmsSigRedTRCTag, GammaTRC[0]);
|
||||
cmsWriteTag(oprof, cmsSigGreenTRCTag, GammaTRC[1]);
|
||||
cmsWriteTag(oprof, cmsSigBlueTRCTag, GammaTRC[2]);
|
||||
cmsFreeToneCurve(GammaTRC[0]);
|
||||
}
|
||||
cmsHPROFILE oprof = ICCStore::getInstance()->getProfile(icm.outputProfile);
|
||||
|
||||
if (oprof) {
|
||||
cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE;
|
||||
@ -432,42 +357,35 @@ Imagefloat* ImProcFunctions::lab2rgbOut(LabImage* lab, int cx, int cy, int cw, i
|
||||
}
|
||||
|
||||
|
||||
Imagefloat* ImProcFunctions::workingtrc(Imagefloat* working, int cw, int ch, int mul, Glib::ustring profile, double gampos, double slpos)
|
||||
void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, int ch, int mul, const Glib::ustring &profile, double gampos, double slpos, bool normalizeIn, bool normalizeOut)
|
||||
{
|
||||
TMatrix wprof;
|
||||
|
||||
wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile);
|
||||
const TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile);
|
||||
|
||||
double dx = Color::D50x;
|
||||
double dz = Color::D50z;
|
||||
{
|
||||
dx = dz = 1.0;
|
||||
}
|
||||
double toxyz[3][3] = {
|
||||
const float toxyz[3][3] = {
|
||||
{
|
||||
(wprof[0][0] / dx), //I have suppressed / Color::D50x
|
||||
(wprof[0][1] / dx),
|
||||
(wprof[0][2] / dx)
|
||||
static_cast<float>(wprof[0][0] / (dx * (normalizeIn ? 65535.0 : 1.0))), //I have suppressed / Color::D50x
|
||||
static_cast<float>(wprof[0][1] / (dx * (normalizeIn ? 65535.0 : 1.0))),
|
||||
static_cast<float>(wprof[0][2] / (dx * (normalizeIn ? 65535.0 : 1.0)))
|
||||
}, {
|
||||
(wprof[1][0]),
|
||||
(wprof[1][1]),
|
||||
(wprof[1][2])
|
||||
static_cast<float>(wprof[1][0] / (normalizeIn ? 65535.0 : 1.0)),
|
||||
static_cast<float>(wprof[1][1] / (normalizeIn ? 65535.0 : 1.0)),
|
||||
static_cast<float>(wprof[1][2] / (normalizeIn ? 65535.0 : 1.0))
|
||||
}, {
|
||||
(wprof[2][0] / dz), //I have suppressed / Color::D50z
|
||||
(wprof[2][1] / dz),
|
||||
(wprof[2][2] / dz)
|
||||
static_cast<float>(wprof[2][0] / (dz * (normalizeIn ? 65535.0 : 1.0))), //I have suppressed / Color::D50z
|
||||
static_cast<float>(wprof[2][1] / (dz * (normalizeIn ? 65535.0 : 1.0))),
|
||||
static_cast<float>(wprof[2][2] / (dz * (normalizeIn ? 65535.0 : 1.0)))
|
||||
}
|
||||
};
|
||||
|
||||
Imagefloat* image = new Imagefloat(cw, ch);
|
||||
|
||||
double pwr;
|
||||
double ts;
|
||||
ts = slpos;
|
||||
|
||||
double pwr = 1.0 / gampos;
|
||||
double ts = slpos;
|
||||
int five = mul;
|
||||
|
||||
pwr = 1.0 / gampos;
|
||||
|
||||
if (gampos < 1.0) {
|
||||
pwr = gampos;
|
||||
@ -476,7 +394,7 @@ Imagefloat* ImProcFunctions::workingtrc(Imagefloat* working, int cw, int ch, int
|
||||
}
|
||||
|
||||
// int select_temp = 1; //5003K
|
||||
const double eps = 0.000000001; // not divide by zero
|
||||
constexpr double eps = 0.000000001; // not divide by zero
|
||||
|
||||
enum class ColorTemp {
|
||||
D50 = 5003, // for Widegamut, ProPhoto Best, Beta -> D50
|
||||
@ -486,10 +404,8 @@ Imagefloat* ImProcFunctions::workingtrc(Imagefloat* working, int cw, int ch, int
|
||||
};
|
||||
ColorTemp temp = ColorTemp::D50;
|
||||
|
||||
cmsHPROFILE oprofdef;
|
||||
float p[6]; //primaries
|
||||
|
||||
if (true) {
|
||||
//primaries for 10 working profiles ==> output profiles
|
||||
if (profile == "WideGamut") {
|
||||
p[0] = 0.7350; //Widegamut primaries
|
||||
@ -581,18 +497,10 @@ Imagefloat* ImProcFunctions::workingtrc(Imagefloat* working, int cw, int ch, int
|
||||
}
|
||||
|
||||
GammaValues g_a; //gamma parameters
|
||||
int mode = 0;
|
||||
constexpr int mode = 0;
|
||||
Color::calcGamma(pwr, ts, mode, g_a); // call to calcGamma with selected gamma and slope : return parameters for LCMS2
|
||||
|
||||
cmsCIExyY xyD;
|
||||
|
||||
cmsCIExyYTRIPLE Primaries = {
|
||||
{p[0], p[1], 1.0}, // red
|
||||
{p[2], p[3], 1.0}, // green
|
||||
{p[4], p[5], 1.0} // blue
|
||||
};
|
||||
|
||||
cmsToneCurve* GammaTRC[3];
|
||||
cmsFloat64Number gammaParams[7];
|
||||
gammaParams[4] = g_a[3] * ts;
|
||||
gammaParams[0] = gampos;
|
||||
@ -604,63 +512,64 @@ Imagefloat* ImProcFunctions::workingtrc(Imagefloat* working, int cw, int ch, int
|
||||
// printf("ga0=%f ga1=%f ga2=%f ga3=%f ga4=%f\n", ga0, ga1, ga2, ga3, ga4);
|
||||
|
||||
// 7 parameters for smoother curves
|
||||
cmsCIExyY xyD;
|
||||
cmsWhitePointFromTemp(&xyD, (double)temp);
|
||||
if (profile == "ACESp0") {
|
||||
xyD = {0.32168, 0.33767, 1.0};//refine white point to avoid differences
|
||||
}
|
||||
|
||||
cmsToneCurve* GammaTRC[3];
|
||||
GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(NULL, five, gammaParams);//5 = more smoother than 4
|
||||
oprofdef = cmsCreateRGBProfile(&xyD, &Primaries, GammaTRC);
|
||||
|
||||
const cmsCIExyYTRIPLE Primaries = {
|
||||
{p[0], p[1], 1.0}, // red
|
||||
{p[2], p[3], 1.0}, // green
|
||||
{p[4], p[5], 1.0} // blue
|
||||
};
|
||||
const cmsHPROFILE oprofdef = cmsCreateRGBProfile(&xyD, &Primaries, GammaTRC);
|
||||
|
||||
cmsFreeToneCurve(GammaTRC[0]);
|
||||
}
|
||||
|
||||
if (oprofdef) {
|
||||
#pragma omp parallel for if (multiThread)
|
||||
|
||||
for (int i = 0; i < ch; i++) {
|
||||
float* rr = working->r(i);
|
||||
float* rg = working->g(i);
|
||||
float* rb = working->b(i);
|
||||
|
||||
float* xa = (float*)image->r(i);
|
||||
float* ya = (float*)image->g(i);
|
||||
float* za = (float*)image->b(i);
|
||||
|
||||
for (int j = 0; j < cw; j++) {
|
||||
float r1 = rr[j];
|
||||
float g1 = rg[j];
|
||||
float b1 = rb[j];
|
||||
|
||||
float x_ = toxyz[0][0] * r1 + toxyz[0][1] * g1 + toxyz[0][2] * b1;
|
||||
float y_ = toxyz[1][0] * r1 + toxyz[1][1] * g1 + toxyz[1][2] * b1;
|
||||
float z_ = toxyz[2][0] * r1 + toxyz[2][1] * g1 + toxyz[2][2] * b1;
|
||||
|
||||
xa[j] = ( x_) ;
|
||||
ya[j] = ( y_);
|
||||
za[j] = ( z_);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE;
|
||||
|
||||
|
||||
constexpr cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE;
|
||||
const cmsHPROFILE iprof = ICCStore::getInstance()->getXYZProfile();
|
||||
lcmsMutex->lock();
|
||||
cmsHPROFILE iprof = ICCStore::getInstance()->getXYZProfile();
|
||||
// cmsHTRANSFORM hTransform = cmsCreateTransform(iprof, TYPE_RGB_16, oprofdef, TYPE_RGB_16, params->icm.outputIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE);
|
||||
cmsHTRANSFORM hTransform = cmsCreateTransform(iprof, TYPE_RGB_FLT, oprofdef, TYPE_RGB_FLT, params->icm.outputIntent, flags);
|
||||
const cmsHTRANSFORM hTransform = cmsCreateTransform(iprof, TYPE_RGB_FLT, oprofdef, TYPE_RGB_FLT, params->icm.outputIntent, flags);
|
||||
lcmsMutex->unlock();
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel if (multiThread)
|
||||
#endif
|
||||
{
|
||||
AlignedBuffer<float> pBuf(cw * 3);
|
||||
const float normalize = normalizeOut ? 65535.f : 1.f;
|
||||
|
||||
image->ExecCMSTransform2(hTransform);
|
||||
#ifdef _OPENMP
|
||||
#pragma omp for schedule(dynamic, 16) nowait
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < ch; ++i) {
|
||||
float *p = pBuf.data;
|
||||
for (int j = 0; j < cw; ++j) {
|
||||
const float r = src->r(i, j);
|
||||
const float g = src->g(i, j);
|
||||
const float b = src->b(i, j);
|
||||
|
||||
*(p++) = toxyz[0][0] * r + toxyz[0][1] * g + toxyz[0][2] * b;
|
||||
*(p++) = toxyz[1][0] * r + toxyz[1][1] * g + toxyz[1][2] * b;
|
||||
*(p++) = toxyz[2][0] * r + toxyz[2][1] * g + toxyz[2][2] * b;
|
||||
}
|
||||
p = pBuf.data;
|
||||
cmsDoTransform(hTransform, p, p, cw);
|
||||
for (int j = 0; j < cw; ++j) {
|
||||
dst->r(i, j) = *(p++) * normalize;
|
||||
dst->g(i, j) = *(p++) * normalize;
|
||||
dst->b(i, j) = *(p++) * normalize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmsDeleteTransform(hTransform);
|
||||
image->normalizeFloatTo65535();
|
||||
|
||||
}
|
||||
|
||||
|
||||
return image;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -902,39 +902,15 @@ private:
|
||||
|
||||
//gamma TRC working
|
||||
if (params.icm.workingTRC == "Custom") { //exec TRC IN free
|
||||
Glib::ustring profile;
|
||||
profile = params.icm.workingProfile;
|
||||
const Glib::ustring profile = params.icm.workingProfile;
|
||||
|
||||
if (profile == "sRGB" || profile == "Adobe RGB" || profile == "ProPhoto" || profile == "WideGamut" || profile == "BruceRGB" || profile == "Beta RGB" || profile == "BestRGB" || profile == "Rec2020" || profile == "ACESp0" || profile == "ACESp1") {
|
||||
int cw = baseImg->getWidth();
|
||||
int ch = baseImg->getHeight();
|
||||
const int cw = baseImg->getWidth();
|
||||
const int ch = baseImg->getHeight();
|
||||
// put gamma TRC to 1
|
||||
Imagefloat* readyImg0 = ipf.workingtrc(baseImg, cw, ch, -5, params.icm.workingProfile, 2.4, 12.92310);
|
||||
#pragma omp parallel for
|
||||
|
||||
for (int row = 0; row < ch; row++) {
|
||||
for (int col = 0; col < cw; col++) {
|
||||
baseImg->r(row, col) = (float)readyImg0->r(row, col);
|
||||
baseImg->g(row, col) = (float)readyImg0->g(row, col);
|
||||
baseImg->b(row, col) = (float)readyImg0->b(row, col);
|
||||
}
|
||||
}
|
||||
|
||||
delete readyImg0;
|
||||
|
||||
ipf.workingtrc(baseImg, baseImg, cw, ch, -5, params.icm.workingProfile, 2.4, 12.92310, true, false);
|
||||
//adjust TRC
|
||||
Imagefloat* readyImg = ipf.workingtrc(baseImg, cw, ch, 5, params.icm.workingProfile, params.icm.workingTRCGamma, params.icm.workingTRCSlope);
|
||||
#pragma omp parallel for
|
||||
|
||||
for (int row = 0; row < ch; row++) {
|
||||
for (int col = 0; col < cw; col++) {
|
||||
baseImg->r(row, col) = (float)readyImg->r(row, col);
|
||||
baseImg->g(row, col) = (float)readyImg->g(row, col);
|
||||
baseImg->b(row, col) = (float)readyImg->b(row, col);
|
||||
}
|
||||
}
|
||||
|
||||
delete readyImg;
|
||||
ipf.workingtrc(baseImg, baseImg, cw, ch, 5, params.icm.workingProfile, params.icm.workingTRCGamma, params.icm.workingTRCSlope, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,6 +286,20 @@ Crop::Crop():
|
||||
|
||||
nx = ny = nw = nh = 0;
|
||||
lastRotationDeg = 0;
|
||||
|
||||
//GTK318
|
||||
#if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 20
|
||||
methodgrid->set_row_spacing(4);
|
||||
methodgrid->set_column_spacing(4);
|
||||
settingsgrid->set_row_spacing(4);
|
||||
settingsgrid->set_column_spacing(4);
|
||||
ppigrid->set_row_spacing(4);
|
||||
ppigrid->set_column_spacing(4);
|
||||
ppisubgrid->set_row_spacing(4);
|
||||
ppisubgrid->set_column_spacing(4);
|
||||
#endif
|
||||
//GTK318
|
||||
|
||||
show_all ();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user