Big update: 1) implemented scalable histogram (TooWaBoo's CSS untested but probably unnecessary now); 2) reverted graphical changes; 3) gridlines now multiply based on height and width; 4) removed cube-scaling; 5) implementend double-log scaling as the third alternative based on suggestion by @iliasg

This commit is contained in:
Thanatomanic
2018-06-17 10:01:16 +02:00
parent c8bddca09b
commit 9e735b2640
4 changed files with 121 additions and 162 deletions

View File

@@ -39,9 +39,9 @@ extern Options options;
HistogramPanel::HistogramPanel ()
{
set_vexpand(false);
set_vexpand(true);
set_hexpand(true);
set_valign(Gtk::ALIGN_START);
set_valign(Gtk::ALIGN_FILL);
set_halign(Gtk::ALIGN_FILL);
set_name("HistogramPanel");
@@ -464,10 +464,10 @@ void HistogramRGBArea::get_preferred_height_for_width_vfunc (int width, int &min
{
int bHeight = width / 30;
if (bHeight > 10) {
bHeight = 10; // it would be useful to scale this based on display dpi
} else if (bHeight < 5 ) {
bHeight = 5;
if (bHeight > 15) {
bHeight = 15;
} else if (bHeight < 10 ) {
bHeight = 10;
}
minimum_height = bHeight;
@@ -721,19 +721,15 @@ HistogramArea::~HistogramArea ()
}
}
/* Note: best case scenario would be to have the histogram size really flexible
by being able to resize the panel vertically, and the side-bar horizontally.
We would only need to enforce some lower limits then. */
Gtk::SizeRequestMode HistogramArea::get_request_mode_vfunc () const
{
return Gtk::SIZE_REQUEST_HEIGHT_FOR_WIDTH;
return Gtk::SIZE_REQUEST_CONSTANT_SIZE;
}
void HistogramArea::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const
{
int minimumWidth = 0;
int naturalWidth = 0; // unused?
int naturalWidth = 0;
get_preferred_width_vfunc (minimumWidth, naturalWidth);
get_preferred_height_for_width_vfunc (minimumWidth, minimum_height, natural_height);
}
@@ -745,16 +741,8 @@ void HistogramArea::get_preferred_width_vfunc (int &minimum_width, int &natural_
}
void HistogramArea::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const
{
/*int gHeight = width / 2;
if (gHeight > 150) {
gHeight = 150;
} else if (gHeight < 100) {
gHeight = 100;
}*/
int gHeight = width; // aspect ratio 1:1 should fit on most monitors
{
int gHeight = width * 0.618;
if (gHeight < 100) {
gHeight = 100;
}
@@ -763,7 +751,6 @@ void HistogramArea::get_preferred_height_for_width_vfunc (int width, int &minimu
natural_height = gHeight;
}
//unused?
void HistogramArea::get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const
{
get_preferred_width_vfunc (minimum_width, natural_width);
@@ -918,67 +905,53 @@ void HistogramArea::updateBackBuffer ()
cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
cr->set_line_width (1.0);
cr->set_operator(Cairo::OPERATOR_ADD);
cr->set_operator(Cairo::OPERATOR_SOURCE);
int ui = 0, oi = 0;
if (needBlue) {
drawCurve(cr, bhchanged, realhistheight, w, h);
cr->set_source_rgba (0.0, 0.0, 1.0, 0.4);
if (needLuma && !rawMode) {
drawCurve(cr, lhist, realhistheight, w, h);
cr->set_source_rgb (0.65, 0.65, 0.65);
cr->fill ();
drawCurve(cr, bhchanged, realhistheight, w, h);
cr->set_source_rgba (0.0, 0.0, 1.0, 0.9);
drawMarks(cr, lhist, realhistheight, w, ui, oi);
}
if (needChroma && !rawMode) {
drawCurve(cr, chist, realhistheight, w, h);
cr->set_source_rgb (0., 0., 0.);
cr->stroke ();
drawMarks(cr, bhchanged, realhistheight, w, ui, oi);
drawMarks(cr, chist, realhistheight, w, ui, oi);
}
if (needGreen) {
drawCurve(cr, ghchanged, realhistheight, w, h);
cr->set_source_rgba (0.0, 1.0, 0.0, 0.4);
cr->fill ();
drawCurve(cr, ghchanged, realhistheight, w, h);
cr->set_source_rgba (0.0, 1.0, 0.0, 0.9);
cr->stroke ();
drawMarks(cr, ghchanged, realhistheight, w, ui, oi);
}
if (needRed) {
drawCurve(cr, rhchanged, realhistheight, w, h);
cr->set_source_rgba (1.0, 0.0, 0.0, 0.4);
cr->fill ();
drawCurve(cr, rhchanged, realhistheight, w, h);
cr->set_source_rgba (1.0, 0.0, 0.0, 0.9);
cr->set_source_rgb (1.0, 0.0, 0.0);
cr->stroke ();
drawMarks(cr, rhchanged, realhistheight, w, ui, oi);
}
cr->set_operator(Cairo::OPERATOR_SOURCE);
if (needLuma && !rawMode) {
drawCurve(cr, lhist, realhistheight, w, h);
cr->set_source_rgb (0.9, 0.9, 0.9);
if (needGreen) {
drawCurve(cr, ghchanged, realhistheight, w, h);
cr->set_source_rgb (0.0, 1.0, 0.0);
cr->stroke ();
drawMarks(cr, lhist, realhistheight, w, ui, oi);
drawMarks(cr, ghchanged, realhistheight, w, ui, oi);
}
if (needChroma && !rawMode) {
drawCurve(cr, chist, realhistheight, w, h);
cr->set_source_rgb (0.4, 0.4, 0.4);
if (needBlue) {
drawCurve(cr, bhchanged, realhistheight, w, h);
cr->set_source_rgb (0.0, 0.0, 1.0);
cr->stroke ();
drawMarks(cr, chist, realhistheight, w, ui, oi);
drawMarks(cr, bhchanged, realhistheight, w, ui, oi);
}
}
cr->set_source_rgba (1., 1., 1., 0.35);
cr->set_source_rgba (1., 1., 1., 0.25);
cr->set_line_width (1.0);
cr->set_antialias(Cairo::ANTIALIAS_NONE);
@@ -988,51 +961,38 @@ void HistogramArea::updateBackBuffer ()
ch_ds[0] = 4;
cr->set_dash (ch_ds, 0);
cr->move_to(w / 4 + 0.5, 1.5);
cr->line_to(w / 4 + 0.5, h - 2);
cr->stroke();
cr->move_to(2 * w / 4 + 0.5, 1.5);
cr->line_to(2 * w / 4 + 0.5, h - 2);
cr->stroke();
cr->move_to(3 * w / 4 + 0.5, 1.5);
cr->line_to(3 * w / 4 + 0.5, h - 2);
cr->stroke();
// determine the number of gridlines based on current h/w
int nrOfHGridPartitions = (int)rtengine::min (16.0, pow (2.0, floor ((h - 100) / 250) + 2));
int nrOfVGridPartitions = (int)rtengine::min (16.0, pow (2.0, floor ((w - 100) / 250) + 2));
if (options.histogramDrawMode == 0)
{
cr->move_to(1.5, h / 4 + 0.5);
cr->line_to(w - 2, h / 4 + 0.5);
cr->stroke();
cr->move_to(1.5, 2 * h / 4 + 0.5);
cr->line_to(w - 2, 2 * h / 4 + 0.5);
cr->stroke();
cr->move_to(1.5, 3 * h / 4 + 0.5);
cr->line_to(w - 2, 3 * h / 4 + 0.5);
cr->stroke();
// draw vertical gridlines
if (options.histogramDrawMode < 2) {
for (int i = 1; i < nrOfVGridPartitions; i++) {
cr->move_to (i * w / nrOfVGridPartitions + 0.5, 1.5);
cr->line_to (i * w / nrOfVGridPartitions + 0.5, h - 2);
cr->stroke ();
}
} else {
for (int i = 1; i < nrOfVGridPartitions; i++) {
cr->move_to (scalingFunctionLog (w, i * w / nrOfVGridPartitions) + 0.5, 1.5);
cr->line_to (scalingFunctionLog (w, i * w / nrOfVGridPartitions) + 0.5, h - 2);
cr->stroke ();
}
}
if (options.histogramDrawMode == 1)
{
cr->move_to(1.5, h - scalingFunctionLog(h,h / 4 + 0.5));
cr->line_to(w - 2, h - scalingFunctionLog(h,h / 4 + 0.5));
cr->stroke();
cr->move_to(1.5, h - scalingFunctionLog(h,2 * h / 4 + 0.5));
cr->line_to(w - 2, h - scalingFunctionLog(h,2 * h / 4 + 0.5));
cr->stroke();
cr->move_to(1.5, h - scalingFunctionLog(h,3 * h / 4 + 0.5));
cr->line_to(w - 2, h - scalingFunctionLog(h,3 * h / 4 + 0.5));
cr->stroke();
}
if (options.histogramDrawMode == 2)
{
cr->move_to(1.5, scalingFunctionCube(h,h / 4 + 0.5));
cr->line_to(w - 2, scalingFunctionCube(h,h / 4 + 0.5));
cr->stroke();
cr->move_to(1.5, scalingFunctionCube(h,2 * h / 4 + 0.5));
cr->line_to(w - 2, scalingFunctionCube(h,2 * h / 4 + 0.5));
cr->stroke();
cr->move_to(1.5, scalingFunctionCube(h,3 * h / 4 + 0.5));
cr->line_to(w - 2, scalingFunctionCube(h,3 * h / 4 + 0.5));
cr->stroke();
// draw horizontal gridlines
if (options.histogramDrawMode == 0) {
for (int i = 1; i < nrOfHGridPartitions; i++) {
cr->move_to (1.5, i * h / nrOfHGridPartitions + 0.5);
cr->line_to (w - 2, i * h / nrOfHGridPartitions + 0.5);
cr->stroke ();
}
} else {
for (int i = 1; i < nrOfHGridPartitions; i++) {
cr->move_to (1.5, h - scalingFunctionLog(h, i * h / nrOfHGridPartitions) + 0.5);
cr->line_to (w - 2, h - scalingFunctionLog(h, i * h / nrOfHGridPartitions) + 0.5);
cr->stroke ();
}
}
cr->unset_dash();
@@ -1056,14 +1016,8 @@ void HistogramArea::on_realize ()
double HistogramArea::scalingFunctionLog(double vsize, double val)
{
double factor = 1.0; // can be tuned if necessary - makes the log 'steeper'
return vsize * log(factor / (factor + val)) / log(factor / vsize);
}
double HistogramArea::scalingFunctionCube(double vsize, double val)
{
double factor = 3.0; // can be tuned; higher values compress the middel part of the scale
return (val * (4 * (-1.0 + factor) * val * val - 6.0 * (-1.0 + factor) * val * vsize + (-2.0 + 3.0 * factor) * vsize *vsize))/(factor * vsize * vsize);
double factor = 20.0; // can be tuned if necessary - higher is flatter curve
return vsize * log(factor / (factor + val)) / log(factor / (factor + vsize));
}
void HistogramArea::drawCurve(Cairo::RefPtr<Cairo::Context> &cr,
@@ -1075,16 +1029,20 @@ void HistogramArea::drawCurve(Cairo::RefPtr<Cairo::Context> &cr,
for (int i = 0; i < 256; i++) {
double val = data[i] * (double)(vsize - 2) / scale;
if (drawMode == 1)
val = scalingFunctionLog((double)vsize,val);
if (drawMode == 2)
val = scalingFunctionCube((double)vsize,val);
if (drawMode > 0) { // scale y for single and double log-scale
val = scalingFunctionLog ((double)vsize, val);
}
if (val > vsize - 1) {
val = vsize - 1;
}
double iscaled = i;
if (drawMode == 2) { // scale x for double log-scale
iscaled = scalingFunctionLog (256.0, (double)i);
}
double posX = (i / 255.0) * (hsize - 1);
double posX = (iscaled / 255.0) * (hsize - 1);
double posY = vsize - 1 - val;
cr->line_to (posX, posY);
}