Solving most if not all bugs left

Still some features to add, but this commit should make this tool fully
usable.
This commit is contained in:
Hombre 2016-10-02 17:23:09 +02:00
parent 4506247985
commit aca00389d9
12 changed files with 444 additions and 306 deletions

View File

@ -361,6 +361,153 @@ void Color::cleanup ()
}
}
void Color::rgb2lab (Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b, bool workingSpace)
{
double xyz_rgb[3][3];
const double ep = 216.0 / 24389.0;
const double ka = 24389.0 / 27.0;
double var_R = r / 65535.0;
double var_G = g / 65535.0;
double var_B = b / 65535.0;
Glib::ustring profileCalc;
profileCalc = "sRGB"; //default
if (workingSpace) {
profileCalc = profileW; //display working
}
else {// if you want display = output space
if (profile == "RT_sRGB" || profile == "RT_sRGB_gBT709" || profile == "RT_sRGB_g10") {
profileCalc = "sRGB";
}
if (profile == "ProPhoto" || profile == "RT_Large_gBT709" || profile == "RT_Large_g10" || profile == "RT_Large_gsRGB") {
profileCalc = "ProPhoto";
}
if (profile == "AdobeRGB1998" || profile == "RT_Medium_gsRGB") {
profileCalc = "Adobe RGB";
}
if (profile == "WideGamutRGB") {
profileCalc = "WideGamut";
}
}
if (workingSpace) {//display working
if (profileW == "sRGB") { //apply sRGB inverse gamma
if ( var_R > 0.04045 ) {
var_R = pow ( ( ( var_R + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_R = var_R / 12.92;
}
if ( var_G > 0.04045 ) {
var_G = pow ( ( ( var_G + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_G = var_G / 12.92;
}
if ( var_B > 0.04045 ) {
var_B = pow ( ( ( var_B + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_B = var_B / 12.92;
}
} else if (profileW == "ProPhoto") { // apply inverse gamma 1.8
var_R = pow ( var_R, 1.8);
var_G = pow ( var_G, 1.8);
var_B = pow ( var_B, 1.8);
} else { // apply inverse gamma 2.2
var_R = pow ( var_R, 2.2);
var_G = pow ( var_G, 2.2);
var_B = pow ( var_B, 2.2);
}
} else { //display outout profile
if (profile == "RT_sRGB" || profile == "RT_Large_gsRGB" || profile == "RT_Medium_gsRGB") { //apply sRGB inverse gamma
if ( var_R > 0.04045 ) {
var_R = pow ( ( ( var_R + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_R = var_R / 12.92;
}
if ( var_G > 0.04045 ) {
var_G = pow ( ( ( var_G + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_G = var_G / 12.92;
}
if ( var_B > 0.04045 ) {
var_B = pow ( ( ( var_B + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_B = var_B / 12.92;
}
}
else if (profile == "RT_sRGB_gBT709" || profile == "RT_Large_gBT709") { //
if ( var_R > 0.0795 ) {
var_R = pow ( ( ( var_R + 0.0954 ) / 1.0954 ), 2.2);
} else {
var_R = var_R / 4.5;
}
if ( var_G > 0.0795 ) {
var_G = pow ( ( ( var_G + 0.0954 ) / 1.0954 ), 2.2);
} else {
var_G = var_G / 4.5;
}
if ( var_B > 0.0795 ) {
var_B = pow ( ( ( var_B + 0.0954 ) / 1.0954 ), 2.2);
} else {
var_B = var_B / 4.5;
}
} else if (profile == "ProPhoto") { // apply inverse gamma 1.8
var_R = pow ( var_R, 1.8);
var_G = pow ( var_G, 1.8);
var_B = pow ( var_B, 1.8);
} else if (profile == "RT_sRGB_g10" || profile == "RT_Large_g10") { // apply inverse gamma 1.8
var_R = pow ( var_R, 1.);
var_G = pow ( var_G, 1.);
var_B = pow ( var_B, 1.);
}
else {// apply inverse gamma 2.2
var_R = pow ( var_R, 2.2);
var_G = pow ( var_G, 2.2);
var_B = pow ( var_B, 2.2);
}
}
// TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix (profileW);
TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix (profileCalc);
for (int m = 0; m < 3; m++)
for (int n = 0; n < 3; n++) {
xyz_rgb[m][n] = wprof[m][n];
}
double varxx, varyy, varzz;
double var_X = ( xyz_rgb[0][0] * var_R + xyz_rgb[0][1] * var_G + xyz_rgb[0][2] * var_B ) / Color::D50x;
double var_Y = ( xyz_rgb[1][0] * var_R + xyz_rgb[1][1] * var_G + xyz_rgb[1][2] * var_B ) ;
double var_Z = ( xyz_rgb[2][0] * var_R + xyz_rgb[2][1] * var_G + xyz_rgb[2][2] * var_B ) / Color::D50z;
varxx = var_X > ep ? cbrt(var_X) : ( ka * var_X + 16.0) / 116.0 ;
varyy = var_Y > ep ? cbrt(var_Y) : ( ka * var_Y + 16.0) / 116.0 ;
varzz = var_Z > ep ? cbrt(var_Z) : ( ka * var_Z + 16.0) / 116.0 ;
LAB_l = ( 116 * varyy ) - 16;
LAB_a = 500 * ( varxx - varyy );
LAB_b = 200 * ( varyy - varzz );
}
void Color::rgb2hsl(float r, float g, float b, float &h, float &s, float &l)
{

View File

@ -175,6 +175,22 @@ public:
}
/**
* @brief Convert red/green/blue to L*a*b
* @brief Convert red/green/blue to hue/saturation/luminance
* @param profile output profile name
* @param profileW working profile name
* @param r red channel [0 ; 65535]
* @param g green channel [0 ; 65535]
* @param b blue channel [0 ; 65535]
* @param L Lab L channel [0 ; 1] (return value)
* @param a Lab a channel [0 ; 1] (return value)
* @param b Lab b channel [0; 1] (return value)
* @param workingSpace true: compute the Lab value using the Working color space ; false: use the Output color space
*/
static void rgb2lab (Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b, bool workingSpace);
/**
* @brief Convert red/green/blue to hue/saturation/luminance
* @param r red channel [0 ; 65535]

View File

@ -475,12 +475,12 @@ bool CropHandler::getEnabled ()
return enabled;
}
void CropHandler::colorPick (rtengine::Coord pickerPos, float &r, float &g, float &b, LockableColorPicker::PickerSize size)
void CropHandler::colorPick (rtengine::Coord pickerPos, float &r, float &g, float &b, LockableColorPicker::Size size)
{
int xSize = (int)size;
int ySize = (int)size;
int pixbufW = cropPixbuf->get_width();
int pixbufW = cropPixbuftrue->get_width();
rtengine::Coord topLeftPos(pickerPos.x - xSize/2, pickerPos.y - ySize/2);
if (topLeftPos.x > pixbufW || topLeftPos.y > pixbufW || topLeftPos.x + xSize < 0 || topLeftPos.y + ySize < 0) {
@ -510,9 +510,9 @@ void CropHandler::colorPick (rtengine::Coord pickerPos, float &r, float &g, floa
// Accumulating the data
std::uint32_t r2=0, g2=0, b2=0;
std::uint32_t count = 0;
const guint8* data = cropPixbuf->get_pixels();
const guint8* data = cropPixbuftrue->get_pixels();
for (int j = topLeftPos.y ; j < topLeftPos.y + ySize ; ++j) {
const guint8* data2 = data + cropPixbuf->get_rowstride()*j;
const guint8* data2 = data + cropPixbuftrue->get_rowstride()*j;
for (int i = topLeftPos.x ; i < topLeftPos.x + xSize ; ++i) {
const guint8* data3 = data2 + i*3;
rtengine::Coord currPos(i, j);

View File

@ -113,7 +113,7 @@ public:
void setEnabled (bool e);
bool getEnabled ();
void colorPick (rtengine::Coord pickerPos, float &r, float &g, float &b, LockableColorPicker::PickerSize size);
void colorPick (rtengine::Coord pickerPos, float &r, float &g, float &b, LockableColorPicker::Size size);
rtengine::DetailedCrop* getCrop()
{

View File

@ -322,11 +322,19 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
state = SDragPicker;
} else {
// Add a new Color Picker
int x2, y2;
screenCoordToImage(x, y, x2, y2);
LockableColorPicker *newPicker = new LockableColorPicker(x2, y2, LockableColorPicker::PickerSize::S15, 0., 0., 0., this);
rtengine::Coord imgPos, cropPos;
screenCoordToImage(x, y, imgPos.x, imgPos.y);
LockableColorPicker *newPicker = new LockableColorPicker(imgPos.x, imgPos.y, LockableColorPicker::Size::S15, 0., 0., 0., this, &cropHandler.colorParams.output, &cropHandler.colorParams.working);
colorPickers.push_back(newPicker);
hoveredPicker = newPicker;
imageCoordToCropImage(imgPos.x, imgPos.y, cropPos.x, cropPos.y);
float r=0.f, g=0.f, b=0.f;
LockableColorPicker::Validity validity = checkValidity (hoveredPicker, cropPos);
hoveredPicker->setValidity (validity);
if (validity == LockableColorPicker::Validity::INSIDE) {
cropHandler.colorPick(cropPos, r, g, b, hoveredPicker->getSize());
hoveredPicker->setRGB (r, g, b);
}
state = SDragPicker;
press_x = x;
press_y = y;
@ -854,9 +862,9 @@ void CropWindow::pointerMoved (int bstate, int x, int y)
}
imageCoordToCropImage(imgPos.x, imgPos.y, cropPos.x, cropPos.y);
float r=0.f, g=0.f, b=0.f;
bool isValid = isHoveredPickerFullyInside (cropPos);
hoveredPicker->setValidity (isValid);
if (isValid) {
LockableColorPicker::Validity validity = checkValidity (hoveredPicker, cropPos);
hoveredPicker->setValidity (validity);
if (validity == LockableColorPicker::Validity::INSIDE) {
cropHandler.colorPick(cropPos, r, g, b, hoveredPicker->getSize());
}
hoveredPicker->setPosition (imgPos, r, g, b);
@ -2032,23 +2040,41 @@ void CropWindow::changeZoom (int zoom, bool notify, int centerx, int centery)
iarea->redraw ();
}
bool CropWindow::isHoveredPickerFullyInside (const rtengine::Coord &pos)
LockableColorPicker::Validity CropWindow::checkValidity (LockableColorPicker* picker, const rtengine::Coord &pos)
{
return true;
if (!cropHandler.cropPixbuf) {
return false;
if (!cropHandler.cropPixbuftrue) {
return LockableColorPicker::Validity::OUTSIDE;
}
rtengine::Coord cropPos;
rtengine::Coord cropTopLeft, cropBottomRight, cropSize;
int skip;
cropHandler.getWindow(cropTopLeft.x, cropTopLeft.y, cropSize.x, cropSize.y, skip);
cropBottomRight = cropTopLeft + cropSize;
rtengine::Coord pickerPos, cropPickerPos;
hoveredPicker->getImagePosition(pickerPos);
picker->getImagePosition(pickerPos);
rtengine::Coord minPos(0, 0);
rtengine::Coord maxPos(cropHandler.cropPixbuf->get_width(), cropHandler.cropPixbuf->get_height());
rtengine::Coord halfPickerSize((int)hoveredPicker->getSize()/2, (int)hoveredPicker->getSize()/2);
rtengine::Coord maxPos(cropHandler.cropPixbuftrue->get_width(), cropHandler.cropPixbuftrue->get_height());
rtengine::Coord halfPickerSize((int)picker->getSize()/2, (int)picker->getSize()/2);
imageCoordToCropImage (pickerPos.x, pickerPos.y, cropPickerPos.x, cropPickerPos.y);
imageCoordToCropImage (cropTopLeft.x, cropTopLeft.y, minPos.x, minPos.y);
imageCoordToCropImage (cropBottomRight.x, cropBottomRight.y, maxPos.x, maxPos.y);
rtengine::Coord pickerMinPos = cropPickerPos - halfPickerSize;
rtengine::Coord pickerMaxPos = cropPickerPos + halfPickerSize;
return pickerMinPos >= minPos && pickerMaxPos <= maxPos;
if (pickerMaxPos.x < minPos.x || pickerMaxPos.y < minPos.y || pickerMinPos.x > maxPos.x || pickerMinPos.y > maxPos.y) {
return LockableColorPicker::Validity::OUTSIDE;
} else if (pickerMinPos >= minPos && pickerMaxPos < maxPos) {
return LockableColorPicker::Validity::INSIDE;
} else {
return LockableColorPicker::Validity::CROSSING;
}
}
void CropWindow::deleteColorPickers ()
{
for (auto colorPicker : colorPickers) {
delete colorPicker;
}
colorPickers.clear();
}
void CropWindow::screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& cropy)
@ -2360,6 +2386,7 @@ void CropWindow::cropImageUpdated ()
colorPicker->getImagePosition(imgPos);
imageCoordToCropImage(imgPos.x, imgPos.y, cropPos.x, cropPos.y);
float r=0.f, g=0.f, b=0.f;
colorPicker->setValidity (checkValidity (colorPicker, cropPos));
cropHandler.colorPick(cropPos, r, g, b, colorPicker->getSize());
colorPicker->setRGB (r, g, b);
}

View File

@ -105,7 +105,7 @@ class CropWindow : public LWButtonListener, public CropDisplayHandler, public Ed
void drawObservedFrame (Cairo::RefPtr<Cairo::Context> cr, int rw = 0, int rh = 0);
void changeZoom (int zoom, bool notify = true, int centerx = -1, int centery = -1);
bool isHoveredPickerFullyInside(const rtengine::Coord &pos);
LockableColorPicker::Validity checkValidity (LockableColorPicker* picker, const rtengine::Coord &pos);
// Used by the mainCropWindow only
void getObservedFrameArea (int& x, int& y, int& w, int& h, int rw = 0, int rh = 0);
@ -127,6 +127,7 @@ public:
{
observedCropWin = cw;
}
void deleteColorPickers ();
void screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& cropy);
void screenCoordToImage (int phyx, int phyy, int& imgx, int& imgy);

View File

@ -117,6 +117,7 @@ void ImageArea::setImProcCoordinator (rtengine::StagedImageProcessor* ipc_)
cropWins.clear();
mainCropWindow->deleteColorPickers ();
mainCropWindow->setObservedCropWin (NULL);
}

View File

@ -26,21 +26,24 @@
extern Options options;
LockableColorPicker::LockableColorPicker (CropWindow* cropWindow)
: cropWindow(cropWindow), displayedValues(ColorPickerType::RGB), position(0, 0), size(PickerSize::S20),
isValid(false), r(0.f), g(0.f), b(0.f), h(0.f), s(0.f), v(0.f)
{
}
LockableColorPicker::LockableColorPicker (CropWindow* cropWindow, Glib::ustring *oProfile, Glib::ustring *wProfile)
: cropWindow(cropWindow), displayedValues(ColorPickerType::RGB), position(0, 0), size(Size::S20),
outputProfile(oProfile), workingProfile(wProfile), validity(Validity::OUTSIDE),
r(0.f), g(0.f), b(0.f), h(0.f), s(0.f), v(0.f), L(0.f), a(0.f), bb(0.f)
{}
LockableColorPicker::LockableColorPicker (int x, int y, PickerSize size, const float R, const float G, const float B, CropWindow* cropWindow)
LockableColorPicker::LockableColorPicker (int x, int y, Size size, const float R, const float G, const float B, CropWindow* cropWindow, Glib::ustring *oProfile, Glib::ustring *wProfile)
: cropWindow(cropWindow), displayedValues(ColorPickerType::RGB), position(x, y), size(size),
isValid(false), r(R), g(G), b(B)
outputProfile(oProfile), workingProfile(wProfile), validity(Validity::OUTSIDE),
r(R), g(G), b(B), L(0.f), a(0.f), bb(0.f)
{
float h_, s_, v_;
rtengine::Color::rgb2hsv((float)r*65535.f, (float)g*65535.f, (float)b*65535.f, h_, s_, v_);
h = (int)(h_*255.f);
s = (int)(s_*255.f);
v = (int)(v_*255.f);
rtengine::Color::rgb2lab (*outputProfile, *workingProfile, r * 0xffff / 0xff, g * 0xffff / 0xff, b * 0xffff / 0xff, L, a, bb, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
}
void LockableColorPicker::updateBackBuffer ()
@ -48,20 +51,17 @@ void LockableColorPicker::updateBackBuffer ()
int newW, newH;
// -------------------- setting some key constants ---------------------
const float circlePadding = 3.f;
const float circlePadding = 3.f; // keep this value odd
// ---------------------------------------------------------------------
if (isValid) {
if (validity == Validity::INSIDE) {
Gtk::DrawingArea *iArea = cropWindow->getImageArea();
Cairo::RefPtr<Cairo::Context> bbcr = BackBuffer::getContext();
Glib::RefPtr<Pango::Context> pangoContext = iArea->get_pango_context ();
Pango::FontDescription fontd(options.colorPickerFont);
fontd.set_weight(Pango::WEIGHT_NORMAL);
pangoContext->set_font_description (fontd);
// for drawing text
bbcr->set_line_width (0.);
Glib::RefPtr<Pango::Layout> layout[3][2];
switch (displayedValues) {
@ -97,10 +97,10 @@ void LockableColorPicker::updateBackBuffer ()
int maxHRow2 = rtengine::max(h20, h21);
// -------------------- setting some key constants ---------------------
const int textPadding = 2;
const int textPadding = 3;
const int textWidth = maxWCol0 + maxWCol1 + textPadding;
const int textHeight = maxHRow0 + maxHRow1 + maxHRow2 + 2*textPadding;
const double opacity = 0.75;
const double opacity = 0.62;
// ---------------------------------------------------------------------
newW = rtengine::max<int>((int)size + 2 * circlePadding, textWidth + 2 * textPadding);
@ -108,29 +108,44 @@ void LockableColorPicker::updateBackBuffer ()
setDrawRectangle(Cairo::FORMAT_ARGB32, 0, 0, newW, newH, true);
float center = (float)size/2.f + circlePadding;
Cairo::RefPtr<Cairo::Context> bbcr = BackBuffer::getContext();
// cleaning the back buffer
bbcr->set_source_rgba (0., 0., 0., 0.);
bbcr->set_operator (Cairo::OPERATOR_CLEAR);
bbcr->paint ();
bbcr->set_operator (Cairo::OPERATOR_OVER);
// for drawing text
bbcr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
bbcr->set_line_width (0.);
float center = (float)size / 2.f + circlePadding;
// black background of the whole color picker
bbcr->set_line_width (0.);
bbcr->arc_negative (center, center, center, 0.f, (float)M_PI);
bbcr->line_to (0, 2.f * center + textHeight + 2*textPadding);
bbcr->line_to (textWidth + 2*textPadding, 2.f * center + textHeight + 2*textPadding);
bbcr->line_to (textWidth + 2*textPadding, 2.f * center);
bbcr->line_to (2.f * center, 2.f * center);
bbcr->close_path();
bbcr->set_source_rgba (0., 0., 0., opacity);
bbcr->arc_negative (center, center, center, 0., (double)M_PI);
bbcr->line_to (0, 2. * center + textHeight);
bbcr->arc_negative (2. * textPadding, 2. * center + textHeight, 2. * textPadding, (double)M_PI, (double)M_PI / 2.);
bbcr->line_to (textWidth, 2. * center + textHeight + 2. * textPadding);
bbcr->arc_negative (textWidth, 2. * center + textHeight, 2. * textPadding, (double)M_PI / 2., 0.);
bbcr->line_to (textWidth + 2. * textPadding, 2. * center + 2. * textPadding);
bbcr->arc_negative (textWidth, 2. * center + 2. * textPadding, 2. * textPadding, 0., (double)M_PI * 1.5);
bbcr->line_to (2. * center, 2. * center);
bbcr->close_path();
bbcr->set_line_join (Cairo::LINE_JOIN_BEVEL);
bbcr->set_line_cap (Cairo::LINE_CAP_SQUARE);
bbcr->fill ();
// light grey circle around the color mark
bbcr->arc (center, center, center - circlePadding / 2.f - 0.5f, 0.f, 2.f * (float)M_PI);
bbcr->set_source_rgb (0.7, 0.7, 0.7);
bbcr->set_line_width (circlePadding-2.f);
bbcr->arc (center, center, center - circlePadding / 2., 0., 2. * (double)M_PI);
bbcr->set_source_rgb (0.75, 0.75, 0.75);
bbcr->set_line_width (circlePadding - 2.);
bbcr->stroke ();
// spot disc with picked color
bbcr->arc (center, center, center - circlePadding - 0.5f, 0.f, 2.f * (float)M_PI);
bbcr->arc (center, center, center - circlePadding, 0., 2. * (double)M_PI);
bbcr->set_source_rgb (r, g, b); // <- set the picker color here
bbcr->set_line_width (0.);
bbcr->fill();
@ -141,7 +156,7 @@ void LockableColorPicker::updateBackBuffer ()
bbcr->set_line_cap (Cairo::LINE_CAP_ROUND);
bbcr->set_source_rgb (1., 1., 1.);
double txtOffsetX = textPadding;
double txtOffsetY = (double)size + 2.f * circlePadding + textPadding;
double txtOffsetY = (double)size + 2. * circlePadding + textPadding;
switch (iArea->get_direction()) {
case Gtk::TEXT_DIR_RTL:
bbcr->move_to (txtOffsetX , txtOffsetY);
@ -190,31 +205,37 @@ void LockableColorPicker::updateBackBuffer ()
anchorOffset.set (center, center);
} else {
setDirty (false);
} else if (validity == Validity::CROSSING) {
newH = newW = (int)size + 2 * circlePadding;
setDrawRectangle(Cairo::FORMAT_ARGB32, 0, 0, newW, newH, true);
Cairo::RefPtr<Cairo::Context> bbcr = BackBuffer::getContext();
bbcr->set_antialias(Cairo::ANTIALIAS_SUBPIXEL);
float center = (float)size/2.f + circlePadding;
bbcr->arc (center, center, center - circlePadding/2.f, 0.f, 2.f * (float)M_PI);
float center = (float)size / 2.f + circlePadding;
bbcr->arc (center, center, center - circlePadding / 2., 0., 2. * (double)M_PI);
bbcr->set_source_rgb (0., 0., 0.);
bbcr->set_line_width(circlePadding);
bbcr->stroke_preserve();
bbcr->set_source_rgb (1., 1., 1.);
bbcr->set_line_width(circlePadding-2.f);
bbcr->set_line_width(circlePadding - 2.);
bbcr->stroke ();
anchorOffset.set (center, center);
setDirty (false);
}
setDirty (false);
}
void LockableColorPicker::draw (Cairo::RefPtr<Cairo::Context> &cr)
{
if (validity == Validity::OUTSIDE) {
return;
}
if (isDirty()) {
updateBackBuffer();
}
@ -240,7 +261,9 @@ void LockableColorPicker::setPosition (const rtengine::Coord &newPos, const floa
s = (float)s_;
v = (float)v_;
if (isValid) {
rtengine::Color::rgb2lab (*outputProfile, *workingProfile, r * 0xffff / 0xff, g * 0xffff / 0xff, b * 0xffff / 0xff, L, a, bb, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
if (validity != Validity::OUTSIDE) {
setDirty(true);
}
}
@ -261,7 +284,9 @@ void LockableColorPicker::setRGB (const float R, const float G, const float B)
s = (float)s_;
v = (float)v_;
if (isValid) {
rtengine::Color::rgb2lab (*outputProfile, *workingProfile, r * 0xffff / 0xff, g * 0xffff / 0xff, b * 0xffff / 0xff, L, a, bb, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
if (validity != Validity::OUTSIDE) {
setDirty(true);
}
}
@ -293,15 +318,15 @@ bool LockableColorPicker::isOver (int x, int y)
return mousePos >= tl && mousePos <= br;
}
void LockableColorPicker::setValidity (bool isValid)
void LockableColorPicker::setValidity (Validity validity)
{
if (this->isValid != isValid) {
if (this->validity != validity) {
setDirty(true);
}
this->isValid = isValid;
this->validity = validity;
}
void LockableColorPicker::setSize (PickerSize newSize)
void LockableColorPicker::setSize (Size newSize)
{
if (size != newSize)
{
@ -310,23 +335,23 @@ void LockableColorPicker::setSize (PickerSize newSize)
}
}
LockableColorPicker::PickerSize LockableColorPicker::getSize ()
LockableColorPicker::Size LockableColorPicker::getSize ()
{
return size;
}
void LockableColorPicker::incSize ()
{
if (size < PickerSize::S30) {
size = (PickerSize)((int)size + 5);
if (size < Size::S30) {
size = (Size)((int)size + 5);
setDirty(true);
}
}
void LockableColorPicker::decSize ()
{
if (size > PickerSize::S5) {
size = (PickerSize)((int)size - 5);
if (size > Size::S5) {
size = (Size)((int)size - 5);
setDirty(true);
}
}

View File

@ -38,7 +38,7 @@ public:
class LockableColorPicker : BackBuffer
{
public:
enum class PickerSize {
enum class Size {
S5=5,
S10=10,
S15=15,
@ -46,26 +46,35 @@ public:
S25=25,
S30=30
};
enum class Validity {
INSIDE,
CROSSING,
OUTSIDE
};
private:
enum class ColorPickerType {
RGB,
HSV
HSV,
LAB
};
CropWindow* cropWindow; // the color picker is displayed in a single cropWindow, the one that the user has clicked in
ColorPickerType displayedValues;
rtengine::Coord position; // Coordinate in image space
rtengine::Coord anchorOffset;
PickerSize size;
bool isValid;
Size size;
Glib::ustring *outputProfile;
Glib::ustring *workingProfile;
Validity validity;
float r, g, b; // red green blue in [0;1] range
float h, s, v; // hue saturation value in [0;1] range
float L, a, bb; // L*a*b value in [0;1] range
void updateBackBuffer ();
public:
LockableColorPicker (CropWindow* cropWindow);
LockableColorPicker (int x, int y, PickerSize size, const float R, const float G, const float B, CropWindow* cropWindow);
LockableColorPicker (CropWindow* cropWindow, Glib::ustring *oProfile, Glib::ustring *wProfile);
LockableColorPicker (int x, int y, Size size, const float R, const float G, const float B, CropWindow* cropWindow, Glib::ustring *oProfile, Glib::ustring *wProfile);
void draw (Cairo::RefPtr<Cairo::Context> &cr);
@ -74,10 +83,10 @@ public:
void setRGB (const float R, const float G, const float B);
void getImagePosition (rtengine::Coord &imgPos);
void getScreenPosition (rtengine::Coord &screenPos);
PickerSize getSize ();
Size getSize ();
bool isOver (int x, int y);
void setValidity (bool isValid);
void setSize (PickerSize newSize);
void setValidity (Validity isValid);
void setSize (Size newSize);
void incSize ();
void decSize ();
};

View File

@ -266,7 +266,7 @@ void Navigator::pointerMoved (bool validPos, Glib::ustring profile, Glib::ustrin
float LAB_a, LAB_b, LAB_l;
//rgb2lab (r, g, b, LAB_l, LAB_a, LAB_b);
rgb2lab (profile, profileW, r, g, b, LAB_l, LAB_a, LAB_b); // TODO: Really sure this function works?
Color::rgb2lab (profile, profileW, r * 0xffff / 0xff, g * 0xffff / 0xff, b * 0xffff / 0xff, LAB_l, LAB_a, LAB_b, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
LAB_A->set_text (Glib::ustring::format(std::fixed, std::setprecision(1), LAB_a));
LAB_B->set_text (Glib::ustring::format(std::fixed, std::setprecision(1), LAB_b));
LAB_L->set_text (Glib::ustring::format(std::fixed, std::setprecision(1), LAB_l));
@ -328,150 +328,3 @@ void Navigator::cycleUnitsHSV (GdkEventButton *event) {
break;
}
}
void Navigator::rgb2lab (Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b)
{
double xyz_rgb[3][3];
const double ep = 216.0 / 24389.0;
const double ka = 24389.0 / 27.0;
double var_R = r / 255.0;
double var_G = g / 255.0;
double var_B = b / 255.0;
Glib::ustring profileCalc;
profileCalc = "sRGB"; //default
if(options.rtSettings.HistogramWorking) {
profileCalc = profileW; //display working
}
else {// if you want display = output space
if (profile == "RT_sRGB" || profile == "RT_sRGB_gBT709" || profile == "RT_sRGB_g10") {
profileCalc = "sRGB";
}
if (profile == "ProPhoto" || profile == "RT_Large_gBT709" || profile == "RT_Large_g10" || profile == "RT_Large_gsRGB") {
profileCalc = "ProPhoto";
}
if (profile == "AdobeRGB1998" || profile == "RT_Medium_gsRGB") {
profileCalc = "Adobe RGB";
}
if (profile == "WideGamutRGB") {
profileCalc = "WideGamut";
}
}
if(options.rtSettings.HistogramWorking) {//display working
if (profileW == "sRGB") { //apply sRGB inverse gamma
if ( var_R > 0.04045 ) {
var_R = pow ( ( ( var_R + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_R = var_R / 12.92;
}
if ( var_G > 0.04045 ) {
var_G = pow ( ( ( var_G + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_G = var_G / 12.92;
}
if ( var_B > 0.04045 ) {
var_B = pow ( ( ( var_B + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_B = var_B / 12.92;
}
} else if (profileW == "ProPhoto") { // apply inverse gamma 1.8
var_R = pow ( var_R, 1.8);
var_G = pow ( var_G, 1.8);
var_B = pow ( var_B, 1.8);
} else { // apply inverse gamma 2.2
var_R = pow ( var_R, 2.2);
var_G = pow ( var_G, 2.2);
var_B = pow ( var_B, 2.2);
}
} else { //display outout profile
if (profile == "RT_sRGB" || profile == "RT_Large_gsRGB" || profile == "RT_Medium_gsRGB") { //apply sRGB inverse gamma
if ( var_R > 0.04045 ) {
var_R = pow ( ( ( var_R + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_R = var_R / 12.92;
}
if ( var_G > 0.04045 ) {
var_G = pow ( ( ( var_G + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_G = var_G / 12.92;
}
if ( var_B > 0.04045 ) {
var_B = pow ( ( ( var_B + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_B = var_B / 12.92;
}
}
else if (profile == "RT_sRGB_gBT709" || profile == "RT_Large_gBT709") { //
if ( var_R > 0.0795 ) {
var_R = pow ( ( ( var_R + 0.0954 ) / 1.0954 ), 2.2);
} else {
var_R = var_R / 4.5;
}
if ( var_G > 0.0795 ) {
var_G = pow ( ( ( var_G + 0.0954 ) / 1.0954 ), 2.2);
} else {
var_G = var_G / 4.5;
}
if ( var_B > 0.0795 ) {
var_B = pow ( ( ( var_B + 0.0954 ) / 1.0954 ), 2.2);
} else {
var_B = var_B / 4.5;
}
} else if (profile == "ProPhoto") { // apply inverse gamma 1.8
var_R = pow ( var_R, 1.8);
var_G = pow ( var_G, 1.8);
var_B = pow ( var_B, 1.8);
} else if (profile == "RT_sRGB_g10" || profile == "RT_Large_g10") { // apply inverse gamma 1.8
var_R = pow ( var_R, 1.);
var_G = pow ( var_G, 1.);
var_B = pow ( var_B, 1.);
}
else {// apply inverse gamma 2.2
var_R = pow ( var_R, 2.2);
var_G = pow ( var_G, 2.2);
var_B = pow ( var_B, 2.2);
}
}
// TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix (profileW);
TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix (profileCalc);
for (int m = 0; m < 3; m++)
for (int n = 0; n < 3; n++) {
xyz_rgb[m][n] = wprof[m][n];
}
double varxx, varyy, varzz;
double var_X = ( xyz_rgb[0][0] * var_R + xyz_rgb[0][1] * var_G + xyz_rgb[0][2] * var_B ) / Color::D50x;
double var_Y = ( xyz_rgb[1][0] * var_R + xyz_rgb[1][1] * var_G + xyz_rgb[1][2] * var_B ) ;
double var_Z = ( xyz_rgb[2][0] * var_R + xyz_rgb[2][1] * var_G + xyz_rgb[2][2] * var_B ) / Color::D50z;
varxx = var_X > ep ? cbrt(var_X) : ( ka * var_X + 16.0) / 116.0 ;
varyy = var_Y > ep ? cbrt(var_Y) : ( ka * var_Y + 16.0) / 116.0 ;
varzz = var_Z > ep ? cbrt(var_Z) : ( ka * var_Z + 16.0) / 116.0 ;
LAB_l = ( 116 * varyy ) - 16;
LAB_a = 500 * ( varxx - varyy );
LAB_b = 200 * ( varyy - varzz );
}

View File

@ -46,8 +46,6 @@ protected:
Gtk::Label *lH, *lS, *lV;
Gtk::Label *lLAB_A, *lLAB_B, *lLAB_L;
void rgb2lab (Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b);
void setInvalid (int fullWidth = -1, int fullHeight = -1);
public:

View File

@ -109,17 +109,18 @@ ToolBar::~ToolBar ()
void ToolBar::setTool (ToolMode tool)
{
handConn.block (true);
cropConn.block (true);
bool handWasBlocked = handConn.block (true);
bool cropWasBlocked = cropConn.block (true);
bool wbWasBlocked = true, cpWasBlocked = true;
if (wbTool) {
wbConn.block (true);
wbWasBlocked = wbConn.block (true);
}
if (colPickerTool) {
cpConn.block (true);
cpWasBlocked = cpConn.block (true);
}
straConn.block (true);
bool straWasBlocked = straConn.block (true);
bool stopEdit = tool == TMHand && handTool->get_active() && editingMode;
@ -154,17 +155,17 @@ void ToolBar::setTool (ToolMode tool)
current = tool;
handConn.block (false);
cropConn.block (false);
if (!handWasBlocked) handConn.block (false);
if (!cropWasBlocked) cropConn.block (false);
if (wbTool) {
wbConn.block (false);
if (!wbWasBlocked) wbConn.block (false);
}
if (colPickerTool) {
cpConn.block (false);
if (!cpWasBlocked) cpConn.block (false);
}
straConn.block (false);
if (!straWasBlocked) straConn.block (false);
if (stopEdit) {
stopEditMode();
@ -178,7 +179,44 @@ void ToolBar::setTool (ToolMode tool)
void ToolBar::startEditMode()
{
if (!editingMode) {
handTool->set_active(true); // will call hand_pressed, with editingMode=false
bool handWasBlocked = handConn.block (true);
bool cropWasBlocked = cropConn.block (true);
bool wbWasBlocked = true, cpWasBlocked = true;
if (colPickerTool) {
cpWasBlocked = cpConn.block (true);
}
if (wbTool) {
wbWasBlocked = wbConn.block (true);
}
bool straWasBlocked = straConn.block (true);
if (current != TMHand) {
if (colPickerTool) {
colPickerTool->set_active(false);
}
if (wbTool) {
wbTool->set_active (false);
}
cropTool->set_active (false);
straTool->set_active (false);
current = TMHand;
}
handTool->set_active (true);
if (!handWasBlocked) handConn.block (false);
if (!cropWasBlocked) cropConn.block (false);
if (colPickerTool) {
if (!cpWasBlocked) cpConn.block (false);
}
if (wbTool) {
if (!wbWasBlocked) wbConn.block (false);
}
if (!straWasBlocked) straConn.block (false);
editingMode = true;
handTool->set_image(*editinghandimg);
}
@ -195,13 +233,6 @@ void ToolBar::stopEditMode()
{
if (editingMode) {
editingMode = false;
/* WARNING: Should we toggle the Hand button on?
* This method can be called while another tool is active, e.g. if the user toggle off
* the Subscriber's Edit button. For now, we keep that other tool active. If one want to
* switch to the Hand tool, uncommenting the following line should suffice (not tested).
*
* handTool->set_active(true);
*/
handTool->set_image(*handimg);
}
}
@ -209,18 +240,25 @@ void ToolBar::stopEditMode()
void ToolBar::hand_pressed ()
{
handConn.block (true);
cropConn.block (true);
bool handWasBlocked = handConn.block (true);
bool cropWasBlocked = cropConn.block (true);
bool wbWasBlocked = true, cpWasBlocked = true;
if (colPickerTool) {
cpConn.block (true);
cpWasBlocked = cpConn.block (true);
}
if (wbTool) {
wbConn.block (true);
wbWasBlocked = wbConn.block (true);
}
straConn.block (true);
bool straWasBlocked = straConn.block (true);
if (editingMode) {
stopEditMode();
if (listener) {
listener->editModeSwitchedOff ();
}
}
if (current != TMHand) {
if (colPickerTool) {
colPickerTool->set_active(false);
@ -232,27 +270,19 @@ void ToolBar::hand_pressed ()
cropTool->set_active (false);
straTool->set_active (false);
current = TMHand;
} else {
if (editingMode) {
stopEditMode();
}
if (listener) {
listener->editModeSwitchedOff ();
}
}
handTool->set_active (true);
handConn.block (false);
cropConn.block (false);
if (!handWasBlocked) handConn.block (false);
if (!cropWasBlocked) cropConn.block (false);
if (colPickerTool) {
cpConn.block (false);
if (!cpWasBlocked) cpConn.block (false);
}
if (wbTool) {
wbConn.block (false);
if (!wbWasBlocked) wbConn.block (false);
}
straConn.block (false);
if (!straWasBlocked) straConn.block (false);
if (listener) {
listener->toolSelected (TMHand);
@ -262,18 +292,25 @@ void ToolBar::hand_pressed ()
void ToolBar::wb_pressed ()
{
handConn.block (true);
cropConn.block (true);
bool handWasBlocked = handConn.block (true);
bool cropWasBlocked = cropConn.block (true);
bool wbWasBlocked = true, cpWasBlocked = true;
if (colPickerTool) {
cpConn.block (true);
cpWasBlocked = cpConn.block (true);
}
if (wbTool) {
wbConn.block (true);
wbWasBlocked = wbConn.block (true);
}
straConn.block (true);
bool straWasBlocked = straConn.block (true);
if (current != TMSpotWB) {
if (editingMode) {
stopEditMode();
if (listener) {
listener->editModeSwitchedOff ();
}
}
handTool->set_active (false);
cropTool->set_active (false);
straTool->set_active (false);
@ -287,16 +324,16 @@ void ToolBar::wb_pressed ()
wbTool->set_active (true);
}
handConn.block (false);
cropConn.block (false);
if (!handWasBlocked) handConn.block (false);
if (!cropWasBlocked) cropConn.block (false);
if (colPickerTool) {
cpConn.block (false);
if (!cpWasBlocked) cpConn.block (false);
}
if (wbTool) {
wbConn.block (false);
if (!wbWasBlocked) wbConn.block (false);
}
straConn.block (false);
if (!straWasBlocked) straConn.block (false);
if (listener) {
listener->toolSelected (TMSpotWB);
@ -307,14 +344,15 @@ void ToolBar::colPicker_pressed (GdkEventButton* event)
{
if (event->button == 1) {
handConn.block (true);
cropConn.block (true);
cpConn.block (true);
bool handWasBlocked = handConn.block (true);
bool cropWasBlocked = cropConn.block (true);
bool wbWasBlocked = true;
bool cpWasBlocked = cpConn.block (true);
if (wbTool) {
wbConn.block (true);
wbWasBlocked = wbConn.block (true);
}
straConn.block (true);
bool straWasBlocked = straConn.block (true);
cropTool->set_active (false);
if (wbTool) {
@ -324,21 +362,27 @@ void ToolBar::colPicker_pressed (GdkEventButton* event)
if (current != TMColorPicker) {
// Disabling all other tools, enabling the Picker tool and entering the "visible pickers" mode
if (editingMode) {
stopEditMode();
if (listener) {
listener->editModeSwitchedOff ();
}
}
handTool->set_active (false);
showColorPickers(true);
current = TMColorPicker;
} else {
// Disabling the picker tool, enabling the Hand tool and keeping the "visible pickers" mode
handTool->set_active (true);
colPickerTool->set_active (false);
//colPickerTool->set_active (false); Done by the standard event handler
current = TMHand;
}
handConn.block (false);
cropConn.block (false);
cpConn.block (false);
wbConn.block (false);
straConn.block (false);
if (!handWasBlocked) handConn.block (false);
if (!cropWasBlocked) cropConn.block (false);
if (!cpWasBlocked) cpConn.block (false);
if (!wbWasBlocked) wbConn.block (false);
if (!straWasBlocked) straConn.block (false);
if (listener) {
listener->toolSelected (current);
@ -346,14 +390,14 @@ void ToolBar::colPicker_pressed (GdkEventButton* event)
} else if (event->button == 3) {
if (current == TMColorPicker) {
// Disabling the Picker tool and entering into the "invisible pickers" mode
cpConn.block (true);
handConn.block (true);
bool cpWasBlocked = cpConn.block (true);
bool handWasBlocked = handConn.block (true);
handTool->set_active (true);
colPickerTool->set_active (false);
current = TMHand;
showColorPickers(false);
cpConn.block (false);
handConn.block (false);
if (!cpWasBlocked) cpConn.block (false);
if (!handWasBlocked) handConn.block (false);
} else {
// The Picker tool is already disabled, entering into the "invisible pickers" mode
switchColorPickersVisibility();
@ -386,17 +430,26 @@ void ToolBar::switchColorPickersVisibility()
void ToolBar::crop_pressed ()
{
handConn.block (true);
cropConn.block (true);
bool handWasBlocked = handConn.block (true);
bool cropWasBlocked = cropConn.block (true);
bool wbWasBlocked = true, cpWasBlocked = true;
if (colPickerTool) {
cpConn.block(true);
if (wbTool) {
wbConn.block (true);
}
straConn.block (true);
if (wbTool) {
wbWasBlocked = wbConn.block (true);
}
bool straWasBlocked = straConn.block (true);
if (current != TMCropSelect) {
if (editingMode) {
stopEditMode();
if (listener) {
listener->editModeSwitchedOff ();
}
}
handTool->set_active (false);
if (colPickerTool) {
colPickerTool->set_active(false);
@ -410,11 +463,12 @@ void ToolBar::crop_pressed ()
}
cropTool->set_active (true);
handConn.block (false);
cropConn.block (false);
cpConn.block(false);
wbConn.block (false);
straConn.block (false);
cropTool->grab_focus ();
if (!handWasBlocked) handConn.block (false);
if (!cropWasBlocked) cropConn.block (false);
if (!cpWasBlocked) cpConn.block(false);
if (!wbWasBlocked) wbConn.block (false);
if (!straWasBlocked) straConn.block (false);
if (listener) {
listener->toolSelected (TMCropSelect);
@ -424,19 +478,26 @@ void ToolBar::crop_pressed ()
void ToolBar::stra_pressed ()
{
handConn.block (true);
cropConn.block (true);
bool handWasBlocked = handConn.block (true);
bool cropWasBlocked = cropConn.block (true);
bool wbWasBlocked = true, cpWasBlocked = true;
if (colPickerTool) {
cpConn.block (true);
cpWasBlocked = cpConn.block (true);
}
if (wbTool) {
wbConn.block (true);
wbWasBlocked = wbConn.block (true);
}
straConn.block (true);
bool straWasBlocked = straConn.block (true);
if (current != TMStraighten) {
if (editingMode) {
stopEditMode();
if (listener) {
listener->editModeSwitchedOff ();
}
}
handTool->set_active (false);
if (colPickerTool) {
colPickerTool->set_active(false);
@ -450,15 +511,15 @@ void ToolBar::stra_pressed ()
}
straTool->set_active (true);
handConn.block (false);
cropConn.block (false);
cpConn.block (false);
if (!handWasBlocked) handConn.block (false);
if (!cropWasBlocked) cropConn.block (false);
if (!cpWasBlocked) cpConn.block (false);
if (wbTool) {
wbConn.block (false);
if (!wbWasBlocked) wbConn.block (false);
}
straConn.block (false);
if (!straWasBlocked) straConn.block (false);
if (listener) {
listener->toolSelected (TMStraighten);