WSL/SLF GitLab Repository

Commit 768f719a authored by Mathias Bavay's avatar Mathias Bavay
Browse files

The gradients now don't provide a transparency value (since it had to be...

The gradients now don't provide a transparency value (since it had to be either fully opaque or fully transparent) but only a boolean. PNGIO now uses a transparent color to encode transparency instead of a true alpha channel, leading to improved run times and smaller file size. The drawback is that pure white is now the transparent color.
parent ec3eb4a7
......@@ -249,30 +249,31 @@ void Gradient::set(const Type& type, const double& i_min, const double& i_max, c
//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)
void Gradient::getColor(const double& val, unsigned char& r, unsigned char& g, unsigned char& b, unsigned char& a) const
void Gradient::getColor(const double& val, unsigned char& r, unsigned char& g, unsigned char& b, bool& a) const
{
if(model==NULL) {
throw UnknownValueException("Please set the color gradient before using it!", AT);
}
if(val==IOUtils::nodata) {
r=0; g=0; b=0; a=0;
r=0; g=0; b=0; a=true;
return;
}
if(val==legend::bg_color) {
r=255; g=255; b=255; a=255;
r=254; g=254; b=254; a=false;
return;
}
if(val==legend::text_color) {
r=0; g=0; b=0; a=255;
r=0; g=0; b=0; a=false;
return;
}
if(autoscale && delta_val==0) { //constant data throughout the grid & autoscale are no friends...
r=g=b=125; a=255;
r=g=b=125; a=false;
return;
}
model->getColor(val, r, g, b, a);
a=false;
model->getColor(val, r, g, b);
}
void Gradient_model::setMinMax(const double& i_min, const double& i_max, const bool& i_autoscale)
......@@ -319,21 +320,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, unsigned char &a) const
void Gradient_model::getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &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);
a = 255; //no alpha for valid values
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Various Gradients
/////////////////////////////////////////////////////////////////////////////////////////////////
void gr_heat::getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a) const
void gr_heat::getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b) const
{
double val;
if(autoscale)
......@@ -349,7 +349,6 @@ void gr_heat::getColor(const double &i_val, unsigned char &r, unsigned char &g,
const double s = 1.-val*0.3;
HSV2RGB(h, s, v, r, g, b);
a = 255; //no alpha for valid values
}
gr_blue_pink::gr_blue_pink(const double& i_min, const double& i_max, const bool& i_autoscale) {
......@@ -378,13 +377,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, unsigned char &a) const
void gr_freeze::getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &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);
a = 255; //no alpha for valid values
}
gr_blue::gr_blue(const double& i_min, const double& i_max, const bool& i_autoscale) {
......
......@@ -125,7 +125,8 @@ namespace Color {
/////////////////////////////////////////////////////////////////////////////////////////////////
// Gradient class
/////////////////////////////////////////////////////////////////////////////////////////////////
//This class is the base class for the various gradients
//This class is the base class for the various gradients.
//DO NOT USE pure white in a gradient, since this might be interpreted as a transparent pixel!
class Gradient_model {
public:
Gradient_model() {setMinMax(0., 0., true);}; //do not use this constructor!
......@@ -133,7 +134,7 @@ class Gradient_model {
//setBgColor()
//setFgColor()
virtual void getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a) const;
virtual void getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &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);
......@@ -146,14 +147,15 @@ class Gradient_model {
/**
* @class Gradient
* @brief This converts numeric values into rgba values.
* @brief This converts numeric values into rgb values.
* The object is initialized with the range that the gradient should cover and the gradient type. Then each numeric value
* that is given will be converted into rgba values from the selected gradient. Data out of range are converted to either
* the minimum or the maximum of the gradient. Alpha channel is ONLY used by special pixels.
* that is given will be converted into rgb values from the selected gradient. Data out of range are converted to either
* the minimum or the maximum of the gradient. Special pixels should return a=true to indicate transparency (however, pure
* white is the transparency color, so do not use it in your gradients!).
*
* Some special pixels are recognized:
* - IOUtils::nodata returns a transparent pixel
* - legend::bg_color returns a white pixel
* - legend::bg_color returns an almost white pixel
* - legend::text_color returns a black pixel
*
* The autoscale is handled both by the object and its caller: if "autoscale==true", the gradient might adjust its control points, for
......@@ -225,9 +227,9 @@ class Gradient {
* @param r red (between 0 and 255)
* @param g green (between 0 and 255)
* @param b blue (between 0 and 255)
* @param a alpha (between 0 and 255)
* @param a transparent pixel?
*/
void getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a) const;
void getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &b, bool &a) const;
private:
double delta_val;
......@@ -238,7 +240,7 @@ class Gradient {
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, unsigned char &a) const;
void getColor(const double &i_val, unsigned char &r, unsigned char &g, unsigned char &b) const;
};
class gr_blue_pink : public Gradient_model {
......@@ -249,7 +251,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, unsigned char &a) const;
void getColor(const double &val, unsigned char &r, unsigned char &g, unsigned char &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
......
......@@ -27,8 +27,10 @@ namespace mio {
/**
* @page pngio PNGIO
* @section template_format Format
* *Put here the informations about the standard format that is implemented*
* No data read, only write (because of gradients)
* This plugin write data to the Portable Network Graphics format (see https://secure.wikimedia.org/wikipedia/en/wiki/Portable_Network_Graphics).
* No data read has been implemented, because reading an existing file would require the exact knowlege of the color gradient that has been used
* to create it. When writing grids, various color gradients will be used depending on the parameter that the data represents. Nodata values
* are represented by transparent pixels (transparency is acheived through a transparent color instead of a true alpha channel for size and performance).
* Finally, the naming scheme for meteo grids should be: YYYYMMDDHHmm_{MeteoGrids::Parameters}.png
*
* @section template_units Units
......@@ -274,10 +276,13 @@ void PNGIO::setFile(const std::string& filename, FILE *fp, png_structp& png_ptr,
png_init_io(png_ptr, fp);
// Write header (8 bit colour depth)
// 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_ALPHA, PNG_INTERLACE_NONE,
8, 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_set_tRNS(png_ptr, info_ptr, 0, 0, &trans_rgb_value);
}
unsigned int PNGIO::setLegend(const unsigned int &ncols, const unsigned int &nrows, const double &min, const double &max, Array2D<double> &legend_array)
......@@ -297,24 +302,35 @@ void PNGIO::writeDataSection(const Grid2DObject &grid, const Array2D<double> &le
{
const double ncols = grid.ncols, nrows = grid.nrows;
// Allocate memory for one row (4 bytes per pixel - RGBA)
// Allocate memory for one row (3 bytes per pixel - RGB)
const unsigned char channels = 3;
png_bytep row=NULL;
row = (png_bytep) malloc(4 * full_width * sizeof(png_byte));
row = (png_bytep) malloc(channels * full_width * sizeof(png_byte));
// Write image data
for(int y=nrows-1 ; y>=0 ; y--) {
//unsigned int x=0;
for(unsigned int x=0; x<ncols ; x++) {
const unsigned int i=x*4;
unsigned char r,g,b,a;
unsigned int x=0;
for(; x<ncols ; x++) {
const unsigned int i=x*channels;
unsigned char r,g,b;
bool a;
gradient.getColor(grid(x,y), r,g,b,a);
row[i]=r; row[i+1]=g; row[i+2]=b; row[i+3]=a;
if(a==true) {
row[i]=255; row[i+1]=255; row[i+2]=255;
} else {
row[i]=r; row[i+1]=g; row[i+2]=b;
}
}
for(unsigned int x=ncols; x<full_width; x++) {
const unsigned int i=x*4;
unsigned char r,g,b,a;
for(; x<full_width; x++) {
const unsigned int i=x*channels;
unsigned char r,g,b;
bool a;
gradient.getColor(legend_array(x-ncols,y), r,g,b,a);
row[i]=r; row[i+1]=g; row[i+2]=b; row[i+3]=a;
if(a==true) {
row[i]=255; row[i+1]=255; row[i+2]=255;
} else {
row[i]=r; row[i+1]=g; row[i+2]=b;
}
}
png_write_row(png_ptr, row);
}
......
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