PostGIS  2.4.9dev-r@@SVN_REVISION@@

◆ RASTER_colorMap()

Datum RASTER_colorMap ( PG_FUNCTION_ARGS  )

Definition at line 4112 of file rtpg_mapalgebra.c.

References rtpg_colormap_arg_t::band, rtpg_colormap_arg_t::bandstats, rt_colormap_entry_t::color, rtpg_colormap_arg_t::colormap, rtpg_colormap_arg_t::element, rt_colormap_t::entry, rtpg_colormap_arg_t::entry, FALSE, rt_colormap_entry_t::isnodata, rt_bandstats_t::max, rt_colormap_t::method, rt_bandstats_t::min, pixval::nband, rtpg_colormap_arg_t::nband, rt_colormap_t::ncolor, rtpg_colormap_arg_t::nelement, rt_colormap_t::nentry, rtpg_colormap_arg_t::nentry, rtpg_colormap_arg_t::nodataentry, PG_FUNCTION_INFO_V1(), POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, rtrowdump::raster, rtpg_colormap_arg_t::raster, RASTER_mapAlgebraExpr(), rt_band_get_summary_stats(), rt_raster_clone(), rt_raster_colormap(), rt_raster_deserialize(), rt_raster_destroy(), rt_raster_get_band(), rt_raster_has_band(), rt_raster_serialize(), rtpg_colormap_arg_destroy(), rtpg_colormap_arg_init(), rtpg_strreplace(), rtpg_strsplit(), rtpg_strtoupper(), rtpg_trim(), rt_raster_serialized_t::size, genraster::value, and rt_colormap_entry_t::value.

Referenced by rtpg_colormap_arg_destroy().

4113 {
4114  rt_pgraster *pgraster = NULL;
4115  rtpg_colormap_arg arg = NULL;
4116  char *junk = NULL;
4117  rt_raster raster = NULL;
4118 
4119  POSTGIS_RT_DEBUG(3, "RASTER_colorMap: Starting");
4120 
4121  /* pgraster is NULL, return NULL */
4122  if (PG_ARGISNULL(0))
4123  PG_RETURN_NULL();
4124 
4125  /* init arg */
4126  arg = rtpg_colormap_arg_init();
4127  if (arg == NULL) {
4128  elog(ERROR, "RASTER_colorMap: Could not initialize argument structure");
4129  PG_RETURN_NULL();
4130  }
4131 
4132  /* raster (0) */
4133  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
4134 
4135  /* raster object */
4136  arg->raster = rt_raster_deserialize(pgraster, FALSE);
4137  if (!arg->raster) {
4139  PG_FREE_IF_COPY(pgraster, 0);
4140  elog(ERROR, "RASTER_colorMap: Could not deserialize raster");
4141  PG_RETURN_NULL();
4142  }
4143 
4144  /* nband (1) */
4145  if (!PG_ARGISNULL(1))
4146  arg->nband = PG_GETARG_INT32(1);
4147  POSTGIS_RT_DEBUGF(4, "nband = %d", arg->nband);
4148 
4149  /* check that band works */
4150  if (!rt_raster_has_band(arg->raster, arg->nband - 1)) {
4151  elog(NOTICE, "Raster does not have band at index %d. Returning empty raster", arg->nband);
4152 
4153  raster = rt_raster_clone(arg->raster, 0);
4154  if (raster == NULL) {
4156  PG_FREE_IF_COPY(pgraster, 0);
4157  elog(ERROR, "RASTER_colorMap: Could not create empty raster");
4158  PG_RETURN_NULL();
4159  }
4160 
4162  PG_FREE_IF_COPY(pgraster, 0);
4163 
4164  pgraster = rt_raster_serialize(raster);
4165  rt_raster_destroy(raster);
4166  if (pgraster == NULL)
4167  PG_RETURN_NULL();
4168 
4169  SET_VARSIZE(pgraster, ((rt_pgraster*) pgraster)->size);
4170  PG_RETURN_POINTER(pgraster);
4171  }
4172 
4173  /* get band */
4174  arg->band = rt_raster_get_band(arg->raster, arg->nband - 1);
4175  if (arg->band == NULL) {
4176  int nband = arg->nband;
4178  PG_FREE_IF_COPY(pgraster, 0);
4179  elog(ERROR, "RASTER_colorMap: Could not get band at index %d", nband);
4180  PG_RETURN_NULL();
4181  }
4182 
4183  /* method (3) */
4184  if (!PG_ARGISNULL(3)) {
4185  char *method = NULL;
4186  char *tmp = text_to_cstring(PG_GETARG_TEXT_P(3));
4187  POSTGIS_RT_DEBUGF(4, "raw method = %s", tmp);
4188 
4189  method = rtpg_trim(tmp);
4190  pfree(tmp);
4191  method = rtpg_strtoupper(method);
4192 
4193  if (strcmp(method, "INTERPOLATE") == 0)
4194  arg->colormap->method = CM_INTERPOLATE;
4195  else if (strcmp(method, "EXACT") == 0)
4196  arg->colormap->method = CM_EXACT;
4197  else if (strcmp(method, "NEAREST") == 0)
4198  arg->colormap->method = CM_NEAREST;
4199  else {
4200  elog(NOTICE, "Unknown value provided for method. Defaulting to INTERPOLATE");
4201  arg->colormap->method = CM_INTERPOLATE;
4202  }
4203  }
4204  /* default to INTERPOLATE */
4205  else
4206  arg->colormap->method = CM_INTERPOLATE;
4207  POSTGIS_RT_DEBUGF(4, "method = %d", arg->colormap->method);
4208 
4209  /* colormap (2) */
4210  if (PG_ARGISNULL(2)) {
4212  PG_FREE_IF_COPY(pgraster, 0);
4213  elog(ERROR, "RASTER_colorMap: Value must be provided for colormap");
4214  PG_RETURN_NULL();
4215  }
4216  else {
4217  char *tmp = NULL;
4218  char *colormap = text_to_cstring(PG_GETARG_TEXT_P(2));
4219  char *_entry;
4220  char *_element;
4221  int i = 0;
4222  int j = 0;
4223 
4224  POSTGIS_RT_DEBUGF(4, "colormap = %s", colormap);
4225 
4226  /* empty string */
4227  if (!strlen(colormap)) {
4229  PG_FREE_IF_COPY(pgraster, 0);
4230  elog(ERROR, "RASTER_colorMap: Value must be provided for colormap");
4231  PG_RETURN_NULL();
4232  }
4233 
4234  arg->entry = rtpg_strsplit(colormap, "\n", &(arg->nentry));
4235  pfree(colormap);
4236  if (arg->nentry < 1) {
4238  PG_FREE_IF_COPY(pgraster, 0);
4239  elog(ERROR, "RASTER_colorMap: Could not process the value provided for colormap");
4240  PG_RETURN_NULL();
4241  }
4242 
4243  /* allocate the max # of colormap entries */
4244  arg->colormap->entry = palloc(sizeof(struct rt_colormap_entry_t) * arg->nentry);
4245  if (arg->colormap->entry == NULL) {
4247  PG_FREE_IF_COPY(pgraster, 0);
4248  elog(ERROR, "RASTER_colorMap: Could not allocate memory for colormap entries");
4249  PG_RETURN_NULL();
4250  }
4251  memset(arg->colormap->entry, 0, sizeof(struct rt_colormap_entry_t) * arg->nentry);
4252 
4253  /* each entry */
4254  for (i = 0; i < arg->nentry; i++) {
4255  /* substitute space for other delimiters */
4256  tmp = rtpg_strreplace(arg->entry[i], ":", " ", NULL);
4257  _entry = rtpg_strreplace(tmp, ",", " ", NULL);
4258  pfree(tmp);
4259  tmp = rtpg_strreplace(_entry, "\t", " ", NULL);
4260  pfree(_entry);
4261  _entry = rtpg_trim(tmp);
4262  pfree(tmp);
4263 
4264  POSTGIS_RT_DEBUGF(4, "Processing entry[%d] = %s", i, arg->entry[i]);
4265  POSTGIS_RT_DEBUGF(4, "Cleaned entry[%d] = %s", i, _entry);
4266 
4267  /* empty entry, continue */
4268  if (!strlen(_entry)) {
4269  POSTGIS_RT_DEBUGF(3, "Skipping empty entry[%d]", i);
4270  pfree(_entry);
4271  continue;
4272  }
4273 
4274  arg->element = rtpg_strsplit(_entry, " ", &(arg->nelement));
4275  pfree(_entry);
4276  if (arg->nelement < 2) {
4278  PG_FREE_IF_COPY(pgraster, 0);
4279  elog(ERROR, "RASTER_colorMap: Could not process colormap entry %d", i + 1);
4280  PG_RETURN_NULL();
4281  }
4282  else if (arg->nelement > 5) {
4283  elog(NOTICE, "More than five elements in colormap entry %d. Using at most five elements", i + 1);
4284  arg->nelement = 5;
4285  }
4286 
4287  /* smallest # of colors */
4288  if ((arg->nelement - 1) < arg->colormap->ncolor)
4289  arg->colormap->ncolor = arg->nelement - 1;
4290 
4291  /* each element of entry */
4292  for (j = 0; j < arg->nelement; j++) {
4293 
4294  _element = rtpg_trim(arg->element[j]);
4295  _element = rtpg_strtoupper(_element);
4296  POSTGIS_RT_DEBUGF(4, "Processing entry[%d][%d] = %s", i, j, arg->element[j]);
4297  POSTGIS_RT_DEBUGF(4, "Cleaned entry[%d][%d] = %s", i, j, _element);
4298 
4299  /* first element is ALWAYS a band value, percentage OR "nv" string */
4300  if (j == 0) {
4301  char *percent = NULL;
4302 
4303  /* NODATA */
4304  if (
4305  strcmp(_element, "NV") == 0 ||
4306  strcmp(_element, "NULL") == 0 ||
4307  strcmp(_element, "NODATA") == 0
4308  ) {
4309  POSTGIS_RT_DEBUG(4, "Processing NODATA string");
4310 
4311  if (arg->nodataentry > -1) {
4312  elog(NOTICE, "More than one NODATA entry found. Using only the first one");
4313  }
4314  else {
4315  arg->colormap->entry[arg->colormap->nentry].isnodata = 1;
4316  /* no need to set value as value comes from band's NODATA */
4317  arg->colormap->entry[arg->colormap->nentry].value = 0;
4318  }
4319  }
4320  /* percent value */
4321  else if ((percent = strchr(_element, '%')) != NULL) {
4322  double value;
4323  POSTGIS_RT_DEBUG(4, "Processing percent string");
4324 
4325  /* get the band stats */
4326  if (arg->bandstats == NULL) {
4327  POSTGIS_RT_DEBUG(4, "Getting band stats");
4328 
4329  arg->bandstats = rt_band_get_summary_stats(arg->band, 1, 1, 0, NULL, NULL, NULL);
4330  if (arg->bandstats == NULL) {
4331  pfree(_element);
4333  PG_FREE_IF_COPY(pgraster, 0);
4334  elog(ERROR, "RASTER_colorMap: Could not get band's summary stats to process percentages");
4335  PG_RETURN_NULL();
4336  }
4337  }
4338 
4339  /* get the string before the percent char */
4340  tmp = palloc(sizeof(char) * (percent - _element + 1));
4341  if (tmp == NULL) {
4342  pfree(_element);
4344  PG_FREE_IF_COPY(pgraster, 0);
4345  elog(ERROR, "RASTER_colorMap: Could not allocate memory for value of percentage");
4346  PG_RETURN_NULL();
4347  }
4348 
4349  memcpy(tmp, _element, percent - _element);
4350  tmp[percent - _element] = '\0';
4351  POSTGIS_RT_DEBUGF(4, "Percent value = %s", tmp);
4352 
4353  /* get percentage value */
4354  errno = 0;
4355  value = strtod(tmp, NULL);
4356  pfree(tmp);
4357  if (errno != 0 || _element == junk) {
4358  pfree(_element);
4360  PG_FREE_IF_COPY(pgraster, 0);
4361  elog(ERROR, "RASTER_colorMap: Could not process percent string to value");
4362  PG_RETURN_NULL();
4363  }
4364 
4365  /* check percentage */
4366  if (value < 0.) {
4367  elog(NOTICE, "Percentage values cannot be less than zero. Defaulting to zero");
4368  value = 0.;
4369  }
4370  else if (value > 100.) {
4371  elog(NOTICE, "Percentage values cannot be greater than 100. Defaulting to 100");
4372  value = 100.;
4373  }
4374 
4375  /* get the true pixel value */
4376  /* TODO: should the percentage be quantile based? */
4377  arg->colormap->entry[arg->colormap->nentry].value = ((value / 100.) * (arg->bandstats->max - arg->bandstats->min)) + arg->bandstats->min;
4378  }
4379  /* straight value */
4380  else {
4381  errno = 0;
4382  arg->colormap->entry[arg->colormap->nentry].value = strtod(_element, &junk);
4383  if (errno != 0 || _element == junk) {
4384  pfree(_element);
4386  PG_FREE_IF_COPY(pgraster, 0);
4387  elog(ERROR, "RASTER_colorMap: Could not process string to value");
4388  PG_RETURN_NULL();
4389  }
4390  }
4391 
4392  }
4393  /* RGB values (0 - 255) */
4394  else {
4395  int value = 0;
4396 
4397  errno = 0;
4398  value = (int) strtod(_element, &junk);
4399  if (errno != 0 || _element == junk) {
4400  pfree(_element);
4402  PG_FREE_IF_COPY(pgraster, 0);
4403  elog(ERROR, "RASTER_colorMap: Could not process string to value");
4404  PG_RETURN_NULL();
4405  }
4406 
4407  if (value > 255) {
4408  elog(NOTICE, "RGBA value cannot be greater than 255. Defaulting to 255");
4409  value = 255;
4410  }
4411  else if (value < 0) {
4412  elog(NOTICE, "RGBA value cannot be less than zero. Defaulting to zero");
4413  value = 0;
4414  }
4415  arg->colormap->entry[arg->colormap->nentry].color[j - 1] = value;
4416  }
4417 
4418  pfree(_element);
4419  }
4420 
4421  POSTGIS_RT_DEBUGF(4, "colormap->entry[%d] (isnodata, value, R, G, B, A) = (%d, %f, %d, %d, %d, %d)",
4422  arg->colormap->nentry,
4423  arg->colormap->entry[arg->colormap->nentry].isnodata,
4424  arg->colormap->entry[arg->colormap->nentry].value,
4425  arg->colormap->entry[arg->colormap->nentry].color[0],
4426  arg->colormap->entry[arg->colormap->nentry].color[1],
4427  arg->colormap->entry[arg->colormap->nentry].color[2],
4428  arg->colormap->entry[arg->colormap->nentry].color[3]
4429  );
4430 
4431  arg->colormap->nentry++;
4432  }
4433 
4434  POSTGIS_RT_DEBUGF(4, "colormap->nentry = %d", arg->colormap->nentry);
4435  POSTGIS_RT_DEBUGF(4, "colormap->ncolor = %d", arg->colormap->ncolor);
4436  }
4437 
4438  /* call colormap */
4439  raster = rt_raster_colormap(arg->raster, arg->nband - 1, arg->colormap);
4440  if (raster == NULL) {
4442  PG_FREE_IF_COPY(pgraster, 0);
4443  elog(ERROR, "RASTER_colorMap: Could not create new raster with applied colormap");
4444  PG_RETURN_NULL();
4445  }
4446 
4448  PG_FREE_IF_COPY(pgraster, 0);
4449  pgraster = rt_raster_serialize(raster);
4450  rt_raster_destroy(raster);
4451 
4452  POSTGIS_RT_DEBUG(3, "RASTER_colorMap: Done");
4453 
4454  if (pgraster == NULL)
4455  PG_RETURN_NULL();
4456 
4457  SET_VARSIZE(pgraster, ((rt_pgraster*) pgraster)->size);
4458  PG_RETURN_POINTER(pgraster);
4459 }
char ** rtpg_strsplit(const char *str, const char *delimiter, int *n)
uint16_t nentry
Definition: librtcore.h:2444
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
Definition: rt_serialize.c:521
raster
Be careful!! Zeros function&#39;s input parameter can be a (height x width) array, not (width x height): ...
Definition: rtrowdump.py:121
char * rtpg_strreplace(const char *str, const char *oldstr, const char *newstr, int *count)
Definition: rtpg_internal.c:55
uint8_t color[4]
Definition: librtcore.h:2433
static void rtpg_colormap_arg_destroy(rtpg_colormap_arg arg)
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:65
nband
Definition: pixval.py:52
enum rt_colormap_t::@7 method
rt_raster rt_raster_clone(rt_raster raster, uint8_t deep)
Clone an existing raster.
Definition: rt_raster.c:1544
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition: rt_raster.c:381
char * rtpg_trim(const char *input)
int rt_raster_has_band(rt_raster raster, int nband)
Return TRUE if the raster has a band of this number.
Definition: rt_raster.c:1351
rt_colormap_entry entry
Definition: librtcore.h:2445
static rtpg_colormap_arg rtpg_colormap_arg_init()
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition: rt_raster.c:82
rt_bandstats rt_band_get_summary_stats(rt_band band, int exclude_nodata_value, double sample, int inc_vals, uint64_t *cK, double *cM, double *cQ)
Compute summary statistics for a band.
Definition: librtcore.h:2430
#define FALSE
Definition: dbfopen.c:168
Struct definitions.
Definition: librtcore.h:2201
int value
Definition: genraster.py:61
#define POSTGIS_RT_DEBUG(level, msg)
Definition: rtpostgis.h:61
int isnodata
Definition: librtcore.h:2431
rt_raster rt_raster_colormap(rt_raster raster, int nband, rt_colormap colormap)
Returns a new raster with up to four 8BUI bands (RGBA) from applying a colormap to the user-specified...
rt_raster rt_raster_deserialize(void *serialized, int header_only)
Return a raster from a serialized form.
Definition: rt_serialize.c:717
double value
Definition: librtcore.h:2432
char * rtpg_strtoupper(char *str)
Here is the call graph for this function:
Here is the caller graph for this function: