PostGIS  3.0.6dev-r@@SVN_REVISION@@

◆ RASTER_colorMap()

Datum RASTER_colorMap ( PG_FUNCTION_ARGS  )

Definition at line 4124 of file rtpg_mapalgebra.c.

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

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, rtpg_colormap_arg_t::nband, pixval::nband, rt_colormap_t::ncolor, rtpg_colormap_arg_t::nelement, rt_colormap_t::nentry, rtpg_colormap_arg_t::nentry, rtpg_colormap_arg_t::nodataentry, POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, rtpg_colormap_arg_t::raster, rtrowdump::raster, 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(), text_to_cstring(), rt_colormap_entry_t::value, and genraster::value.

Here is the call graph for this function: