WSL/SLF GitLab Repository

Commit 244c1931 authored by Mathias Bavay's avatar Mathias Bavay
Browse files

A few hard coded parameters have been declared as static const (color depth...

A few hard coded parameters have been declared as static const (color depth per channel, max color per channel) in order to make the code cleaner. A new method has been introduced in the Gradient class: setNrOfColors. This allows to specify a reduced number of unique colors (even if still coded on 8 bits per channel). By using this call in PNGIO (with 8000 unique colors), the output remains visibly almost the same (only some very slow varying parts see a flat color instead of a slow gradient) while the run time is reduced by up to 5% and the file size more than halved.
parent 768f719a
......@@ -223,6 +223,7 @@ void Color::HSVtoRGB(const double& h, const double& s, const double& v, double &
/////////////////////////////////////////////////////////////////////////////////////////////////
// Gradient class
/////////////////////////////////////////////////////////////////////////////////////////////////
const unsigned char Gradient::channel_max_color = 255;
Gradient::Gradient(const Type& type, const double& i_min, const double& i_max, const bool& i_autoscale)
{
......@@ -233,6 +234,8 @@ void Gradient::set(const Type& type, const double& i_min, const double& i_max, c
{
delta_val = i_max - i_min;
autoscale = i_autoscale;
color_discretization = 0.; //color discretization turned off
nr_unique_colors = 0;
if(type==terrain) model = new gr_terrain(i_min, i_max, i_autoscale);
else if(type==slope) model = new gr_slope(i_min, i_max, i_autoscale);
......@@ -245,6 +248,11 @@ void Gradient::set(const Type& type, const double& i_min, const double& i_max, c
else if(type==bg_isomorphic) model = new gr_bg_isomorphic(i_min, i_max, i_autoscale);
}
void Gradient::setNrOfColors(const unsigned int& i_nr_unique_colors) {
nr_unique_colors = static_cast<unsigned char>( pow(i_nr_unique_colors, 1./3.) );
color_discretization = (double)channel_max_color/(double)nr_unique_colors;
}
//val between min_val and max_val
//return values between 0 and 255 per channel
//getColor: take value between min & max, as defined in the constructor (use min/max for rescaling gradient control points). Use autoscale bool only for specific adjustments (ie: remove sea level blue color in autoscale, etc) ie: autoscaling is done purely by the caller, who specifies the min/max for the gradient (and that should be enough)
......@@ -260,7 +268,7 @@ void Gradient::getColor(const double& val, unsigned char& r, unsigned char& g, u
return;
}
if(val==legend::bg_color) {
r=254; g=254; b=254; a=false;
r=channel_max_color-1; g=channel_max_color-1; b=channel_max_color-1; a=false;
return;
}
if(val==legend::text_color) {
......@@ -268,12 +276,22 @@ void Gradient::getColor(const double& val, unsigned char& r, unsigned char& g, u
return;
}
if(autoscale && delta_val==0) { //constant data throughout the grid & autoscale are no friends...
r=g=b=125; a=false;
r=g=b=channel_max_color/2; a=false;
return;
}
a=false;
model->getColor(val, r, g, b);
double r_d,g_d,b_d;
model->getColor(val, r_d, g_d, b_d);
if(nr_unique_colors==0.) {
r = static_cast<unsigned char>(r_d*channel_max_color);
g = static_cast<unsigned char>(g_d*channel_max_color);
b = static_cast<unsigned char>(b_d*channel_max_color);
} else {
r = static_cast<unsigned char>( static_cast<unsigned char>(r_d*nr_unique_colors)*color_discretization );
g = static_cast<unsigned char>( static_cast<unsigned char>(g_d*nr_unique_colors)*color_discretization );
b = static_cast<unsigned char>( static_cast<unsigned char>(b_d*nr_unique_colors)*color_discretization );
}
}
void Gradient_model::setMinMax(const double& i_min, const double& i_max, const bool& i_autoscale)
......@@ -320,20 +338,20 @@ void Gradient_model::HSV2RGB(const double& h, const double& s, const double& v,
b = static_cast<unsigned char>(b_d*255);
}
void Gradient_model::getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &b) const
void Gradient_model::getColor(const double &val, double &r, double &g, double &b) const
{
const double h = getInterpol(val, X, v_h);
const double s = getInterpol(val, X, v_s);
const double v = getInterpol(val, X, v_v);
HSV2RGB(h, s, v, r, g, b);
Color::HSVtoRGB(h, s, v, r, g, b);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Various Gradients
/////////////////////////////////////////////////////////////////////////////////////////////////
void gr_heat::getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b) const
void gr_heat::getColor(const double &i_val, double &r, double &g, double &b) const
{
double val;
if(autoscale)
......@@ -348,7 +366,7 @@ void gr_heat::getColor(const double &i_val, unsigned char &r, unsigned char &g,
const double v = val*0.75+0.25;
const double s = 1.-val*0.3;
HSV2RGB(h, s, v, r, g, b);
Color::HSVtoRGB(h, s, v, r, g, b);
}
gr_blue_pink::gr_blue_pink(const double& i_min, const double& i_max, const bool& i_autoscale) {
......@@ -377,12 +395,12 @@ gr_freeze::gr_freeze(const double& i_min, const double& i_max, const bool& i_aut
for(size_t i=0; i<X.size(); i++) X[i] = X[i]*delta_val + min_val;
}
void gr_freeze::getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &b) const
void gr_freeze::getColor(const double &val, double &r, double &g, double &b) const
{
//interpolation on RGB values
r = static_cast<unsigned char>(getInterpol(val, X, v_r)*255);
g = static_cast<unsigned char>(getInterpol(val, X, v_g)*255);
b = static_cast<unsigned char>(getInterpol(val, X, v_b)*255);
r = getInterpol(val, X, v_r);
g = getInterpol(val, X, v_g);
b = getInterpol(val, X, v_b);
}
gr_blue::gr_blue(const double& i_min, const double& i_max, const bool& i_autoscale) {
......
......@@ -134,7 +134,7 @@ class Gradient_model {
//setBgColor()
//setFgColor()
virtual void getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &b) const;
virtual void getColor(const double &val, double &r, double &g, double &b) const;
protected:
double getInterpol(const double& val, const std::vector<double>& X, const std::vector<double>& Y) const;
void setMinMax(const double& i_min, const double& i_max, const bool& i_autoscale);
......@@ -220,6 +220,15 @@ class Gradient {
//setBgColor()
//setFgColor()
/**
* @brief Set a reduced number of colors for the gradient
* The given argument is an upper bound for the number of unique colors in the generated
* gradient. This is a specially easy and useful way of reducing a file size with
* no run time overhead (and even a small benefit) and little visible impact if
* the number of colors remains large enough (say, at least a few thousands)
* @param i_nr_unique_colors maximum number of unique colors
*/
void setNrOfColors(const unsigned int& i_nr_unique_colors);
/**
* @brief Get RGB values for a given numeric value
* See class description for more explanations on the implementation/behavior
......@@ -231,16 +240,19 @@ class Gradient {
*/
void getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &b, bool &a) const;
static const unsigned char channel_max_color; ///< nr of colors per channel of the generated gradients
private:
double delta_val;
bool autoscale;
double color_discretization;
unsigned char nr_unique_colors;
Gradient_model *model;
};
class gr_heat : public Gradient_model {
public:
gr_heat(const double& i_min, const double& i_max, const bool& i_autoscale) {setMinMax(i_min, i_max, i_autoscale);};
void getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b) const;
void getColor(const double &i_val, double &r, double &g, double &b) const;
};
class gr_blue_pink : public Gradient_model {
......@@ -251,7 +263,7 @@ class gr_blue_pink : public Gradient_model {
class gr_freeze : public Gradient_model {
public:
gr_freeze(const double& i_min, const double& i_max, const bool& i_autoscale);
void getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &b) const;
void getColor(const double &val, double &r, double &g, double &b) const;
private:
//This gradient is interpolated in RGB color space
std::vector<double> X, v_r,v_g,v_b; ///<control points: vector of X and associated r,g,b. They must be in X ascending order
......
......@@ -70,6 +70,9 @@ namespace mio {
*/
const double PNGIO::plugin_nodata = -999.; //plugin specific nodata value. It can also be read by the plugin (depending on what is appropriate)
const unsigned char PNGIO::channel_depth = 8;
const unsigned char PNGIO::channel_max_color = 255;
const unsigned char PNGIO::transparent_grey = channel_max_color;
PNGIO::PNGIO(void (*delObj)(void*), const Config& i_cfg) : IOInterface(delObj), cfg(i_cfg)
{
......@@ -278,10 +281,10 @@ void PNGIO::setFile(const std::string& filename, FILE *fp, png_structp& png_ptr,
// Write header (8 bit colour depth). Alpha channel with PNG_COLOR_TYPE_RGB_ALPHA
png_set_IHDR(png_ptr, info_ptr, width, height,
8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
channel_depth, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
//set transparent color (ie: cheap transparency: leads to smaller files and shorter run times)
png_color_16 trans_rgb_value = {255, 255, 255, 255, 255};
png_color_16 trans_rgb_value = {transparent_grey, transparent_grey, transparent_grey, transparent_grey, transparent_grey};
png_set_tRNS(png_ptr, info_ptr, 0, 0, &trans_rgb_value);
}
......@@ -316,7 +319,7 @@ void PNGIO::writeDataSection(const Grid2DObject &grid, const Array2D<double> &le
bool a;
gradient.getColor(grid(x,y), r,g,b,a);
if(a==true) {
row[i]=255; row[i+1]=255; row[i+2]=255;
row[i]=transparent_grey; row[i+1]=transparent_grey; row[i+2]=transparent_grey;
} else {
row[i]=r; row[i+1]=g; row[i+2]=b;
}
......@@ -327,7 +330,7 @@ void PNGIO::writeDataSection(const Grid2DObject &grid, const Array2D<double> &le
bool a;
gradient.getColor(legend_array(x-ncols,y), r,g,b,a);
if(a==true) {
row[i]=255; row[i+1]=255; row[i+2]=255;
row[i]=transparent_grey; row[i+1]=transparent_grey; row[i+2]=transparent_grey;
} else {
row[i]=r; row[i+1]=g; row[i+2]=b;
}
......@@ -380,6 +383,7 @@ void PNGIO::write2DGrid(const Grid2DObject& grid_in, const std::string& filename
const double max = grid.grid2D.getMax();
Gradient gradient(Gradient::heat, min, max, autoscale);
gradient.setNrOfColors(8000);
Array2D<double> legend_array; //it will remain empty if there is no legend
const unsigned int full_width = setLegend(ncols, nrows, min, max, legend_array);
......@@ -473,6 +477,7 @@ void PNGIO::write2DGrid(const Grid2DObject& grid_in, const MeteoGrids::Parameter
} else {
gradient.set(Gradient::heat, min, max, autoscale);
}
gradient.setNrOfColors(8000);
Array2D<double> legend_array; //it will remain empty if there is no legend
const unsigned int full_width = setLegend(ncols, nrows, min, max, legend_array);
......
......@@ -88,6 +88,9 @@ class PNGIO : public IOInterface {
std::vector<std::string> metadata_key, metadata_text;
static const double plugin_nodata; //plugin specific nodata value, e.g. -999
static const unsigned char channel_depth;
static const unsigned char channel_max_color;
static const unsigned char transparent_grey;
};
} //namespace
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment