PostGIS  3.1.6dev-r@@SVN_REVISION@@

◆ RASTER_colorMap()

Datum RASTER_colorMap ( PG_FUNCTION_ARGS  )

Definition at line 4130 of file rtpg_mapalgebra.c.

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

Here is the call graph for this function: