PostGIS  3.4.0dev-r@@SVN_REVISION@@

◆ RASTER_colorMap()

Datum RASTER_colorMap ( PG_FUNCTION_ARGS  )

Definition at line 4063 of file rtpg_mapalgebra.c.

4064 {
4065  rt_pgraster *pgraster = NULL;
4066  rtpg_colormap_arg arg = NULL;
4067  char *junk = NULL;
4068  rt_raster raster = NULL;
4069 
4070  POSTGIS_RT_DEBUG(3, "RASTER_colorMap: Starting");
4071 
4072  /* pgraster is NULL, return NULL */
4073  if (PG_ARGISNULL(0))
4074  PG_RETURN_NULL();
4075 
4076  /* init arg */
4077  arg = rtpg_colormap_arg_init();
4078  if (arg == NULL) {
4079  elog(ERROR, "RASTER_colorMap: Could not initialize argument structure");
4080  PG_RETURN_NULL();
4081  }
4082 
4083  /* raster (0) */
4084  pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
4085 
4086  /* raster object */
4087  arg->raster = rt_raster_deserialize(pgraster, FALSE);
4088  if (!arg->raster) {
4090  PG_FREE_IF_COPY(pgraster, 0);
4091  elog(ERROR, "RASTER_colorMap: Could not deserialize raster");
4092  PG_RETURN_NULL();
4093  }
4094 
4095  /* nband (1) */
4096  if (!PG_ARGISNULL(1))
4097  arg->nband = PG_GETARG_INT32(1);
4098  POSTGIS_RT_DEBUGF(4, "nband = %d", arg->nband);
4099 
4100  /* check that band works */
4101  if (!rt_raster_has_band(arg->raster, arg->nband - 1)) {
4102  elog(NOTICE, "Raster does not have band at index %d. Returning empty raster", arg->nband);
4103 
4104  raster = rt_raster_clone(arg->raster, 0);
4105  if (raster == NULL) {
4107  PG_FREE_IF_COPY(pgraster, 0);
4108  elog(ERROR, "RASTER_colorMap: Could not create empty raster");
4109  PG_RETURN_NULL();
4110  }
4111 
4113  PG_FREE_IF_COPY(pgraster, 0);
4114 
4115  pgraster = rt_raster_serialize(raster);
4117  if (pgraster == NULL)
4118  PG_RETURN_NULL();
4119 
4120  SET_VARSIZE(pgraster, ((rt_pgraster*) pgraster)->size);
4121  PG_RETURN_POINTER(pgraster);
4122  }
4123 
4124  /* get band */
4125  arg->band = rt_raster_get_band(arg->raster, arg->nband - 1);
4126  if (arg->band == NULL) {
4127  int nband = arg->nband;
4129  PG_FREE_IF_COPY(pgraster, 0);
4130  elog(ERROR, "RASTER_colorMap: Could not get band at index %d", nband);
4131  PG_RETURN_NULL();
4132  }
4133 
4134  /* method (3) */
4135  if (!PG_ARGISNULL(3)) {
4136  char *method = NULL;
4137  char *tmp = text_to_cstring(PG_GETARG_TEXT_P(3));
4138  POSTGIS_RT_DEBUGF(4, "raw method = %s", tmp);
4139 
4140  method = rtpg_trim(tmp);
4141  pfree(tmp);
4142  method = rtpg_strtoupper(method);
4143 
4144  if (strcmp(method, "INTERPOLATE") == 0)
4145  arg->colormap->method = CM_INTERPOLATE;
4146  else if (strcmp(method, "EXACT") == 0)
4147  arg->colormap->method = CM_EXACT;
4148  else if (strcmp(method, "NEAREST") == 0)
4149  arg->colormap->method = CM_NEAREST;
4150  else {
4151  elog(NOTICE, "Unknown value provided for method. Defaulting to INTERPOLATE");
4152  arg->colormap->method = CM_INTERPOLATE;
4153  }
4154  }
4155  /* default to INTERPOLATE */
4156  else
4157  arg->colormap->method = CM_INTERPOLATE;
4158  POSTGIS_RT_DEBUGF(4, "method = %d", arg->colormap->method);
4159 
4160  /* colormap (2) */
4161  if (PG_ARGISNULL(2)) {
4163  PG_FREE_IF_COPY(pgraster, 0);
4164  elog(ERROR, "RASTER_colorMap: Value must be provided for colormap");
4165  PG_RETURN_NULL();
4166  }
4167  else {
4168  char *tmp = NULL;
4169  char *colormap = text_to_cstring(PG_GETARG_TEXT_P(2));
4170  char *_entry;
4171  char *_element;
4172  uint32_t i = 0;
4173  uint32_t j = 0;
4174 
4175  POSTGIS_RT_DEBUGF(4, "colormap = %s", colormap);
4176 
4177  /* empty string */
4178  if (!strlen(colormap)) {
4180  PG_FREE_IF_COPY(pgraster, 0);
4181  elog(ERROR, "RASTER_colorMap: Value must be provided for colormap");
4182  PG_RETURN_NULL();
4183  }
4184 
4185  arg->entry = rtpg_strsplit(colormap, "\n", &(arg->nentry));
4186  pfree(colormap);
4187  if (arg->nentry < 1) {
4189  PG_FREE_IF_COPY(pgraster, 0);
4190  elog(ERROR, "RASTER_colorMap: Could not process the value provided for colormap");
4191  PG_RETURN_NULL();
4192  }
4193 
4194  /* allocate the max # of colormap entries */
4195  arg->colormap->entry = palloc(sizeof(struct rt_colormap_entry_t) * arg->nentry);
4196  if (arg->colormap->entry == NULL) {
4198  PG_FREE_IF_COPY(pgraster, 0);
4199  elog(ERROR, "RASTER_colorMap: Could not allocate memory for colormap entries");
4200  PG_RETURN_NULL();
4201  }
4202  memset(arg->colormap->entry, 0, sizeof(struct rt_colormap_entry_t) * arg->nentry);
4203 
4204  /* each entry */
4205  for (i = 0; i < arg->nentry; i++) {
4206  /* substitute space for other delimiters */
4207  tmp = rtpg_strreplace(arg->entry[i], ":", " ", NULL);
4208  _entry = rtpg_strreplace(tmp, ",", " ", NULL);
4209  pfree(tmp);
4210  tmp = rtpg_strreplace(_entry, "\t", " ", NULL);
4211  pfree(_entry);
4212  _entry = rtpg_trim(tmp);
4213  pfree(tmp);
4214 
4215  POSTGIS_RT_DEBUGF(4, "Processing entry[%d] = %s", i, arg->entry[i]);
4216  POSTGIS_RT_DEBUGF(4, "Cleaned entry[%d] = %s", i, _entry);
4217 
4218  /* empty entry, continue */
4219  if (!strlen(_entry)) {
4220  POSTGIS_RT_DEBUGF(3, "Skipping empty entry[%d]", i);
4221  pfree(_entry);
4222  continue;
4223  }
4224 
4225  arg->element = rtpg_strsplit(_entry, " ", &(arg->nelement));
4226  pfree(_entry);
4227  if (arg->nelement < 2) {
4229  PG_FREE_IF_COPY(pgraster, 0);
4230  elog(ERROR, "RASTER_colorMap: Could not process colormap entry %d", i + 1);
4231  PG_RETURN_NULL();
4232  }
4233  else if (arg->nelement > 5) {
4234  elog(NOTICE, "More than five elements in colormap entry %d. Using at most five elements", i + 1);
4235  arg->nelement = 5;
4236  }
4237 
4238  /* smallest # of colors */
4239  if (((int)arg->nelement - 1) < arg->colormap->ncolor)
4240  arg->colormap->ncolor = arg->nelement - 1;
4241 
4242  /* each element of entry */
4243  for (j = 0; j < arg->nelement; j++) {
4244 
4245  _element = rtpg_trim(arg->element[j]);
4246  _element = rtpg_strtoupper(_element);
4247  POSTGIS_RT_DEBUGF(4, "Processing entry[%d][%d] = %s", i, j, arg->element[j]);
4248  POSTGIS_RT_DEBUGF(4, "Cleaned entry[%d][%d] = %s", i, j, _element);
4249 
4250  /* first element is ALWAYS a band value, percentage OR "nv" string */
4251  if (j == 0) {
4252  char *percent = NULL;
4253 
4254  /* NODATA */
4255  if (
4256  strcmp(_element, "NV") == 0 ||
4257  strcmp(_element, "NULL") == 0 ||
4258  strcmp(_element, "NODATA") == 0
4259  ) {
4260  POSTGIS_RT_DEBUG(4, "Processing NODATA string");
4261 
4262  if (arg->nodataentry > -1) {
4263  elog(NOTICE, "More than one NODATA entry found. Using only the first one");
4264  }
4265  else {
4266  arg->colormap->entry[arg->colormap->nentry].isnodata = 1;
4267  /* no need to set value as value comes from band's NODATA */
4268  arg->colormap->entry[arg->colormap->nentry].value = 0;
4269  }
4270  }
4271  /* percent value */
4272  else if ((percent = strchr(_element, '%')) != NULL) {
4273  double value;
4274  POSTGIS_RT_DEBUG(4, "Processing percent string");
4275 
4276  /* get the band stats */
4277  if (arg->bandstats == NULL) {
4278  POSTGIS_RT_DEBUG(4, "Getting band stats");
4279 
4280  arg->bandstats = rt_band_get_summary_stats(arg->band, 1, 1, 0, NULL, NULL, NULL);
4281  if (arg->bandstats == NULL) {
4282  pfree(_element);
4284  PG_FREE_IF_COPY(pgraster, 0);
4285  elog(ERROR, "RASTER_colorMap: Could not get band's summary stats to process percentages");
4286  PG_RETURN_NULL();
4287  }
4288  }
4289 
4290  /* get the string before the percent char */
4291  tmp = palloc(sizeof(char) * (percent - _element + 1));
4292  if (tmp == NULL) {
4293  pfree(_element);
4295  PG_FREE_IF_COPY(pgraster, 0);
4296  elog(ERROR, "RASTER_colorMap: Could not allocate memory for value of percentage");
4297  PG_RETURN_NULL();
4298  }
4299 
4300  memcpy(tmp, _element, percent - _element);
4301  tmp[percent - _element] = '\0';
4302  POSTGIS_RT_DEBUGF(4, "Percent value = %s", tmp);
4303 
4304  /* get percentage value */
4305  errno = 0;
4306  value = strtod(tmp, NULL);
4307  pfree(tmp);
4308  if (errno != 0 || _element == junk) {
4309  pfree(_element);
4311  PG_FREE_IF_COPY(pgraster, 0);
4312  elog(ERROR, "RASTER_colorMap: Could not process percent string to value");
4313  PG_RETURN_NULL();
4314  }
4315 
4316  /* check percentage */
4317  if (value < 0.) {
4318  elog(NOTICE, "Percentage values cannot be less than zero. Defaulting to zero");
4319  value = 0.;
4320  }
4321  else if (value > 100.) {
4322  elog(NOTICE, "Percentage values cannot be greater than 100. Defaulting to 100");
4323  value = 100.;
4324  }
4325 
4326  /* get the true pixel value */
4327  /* TODO: should the percentage be quantile based? */
4328  arg->colormap->entry[arg->colormap->nentry].value = ((value / 100.) * (arg->bandstats->max - arg->bandstats->min)) + arg->bandstats->min;
4329  }
4330  /* straight value */
4331  else {
4332  errno = 0;
4333  arg->colormap->entry[arg->colormap->nentry].value = strtod(_element, &junk);
4334  if (errno != 0 || _element == junk) {
4335  pfree(_element);
4337  PG_FREE_IF_COPY(pgraster, 0);
4338  elog(ERROR, "RASTER_colorMap: Could not process string to value");
4339  PG_RETURN_NULL();
4340  }
4341  }
4342 
4343  }
4344  /* RGB values (0 - 255) */
4345  else {
4346  int value = 0;
4347 
4348  errno = 0;
4349  value = (int) strtod(_element, &junk);
4350  if (errno != 0 || _element == junk) {
4351  pfree(_element);
4353  PG_FREE_IF_COPY(pgraster, 0);
4354  elog(ERROR, "RASTER_colorMap: Could not process string to value");
4355  PG_RETURN_NULL();
4356  }
4357 
4358  if (value > 255) {
4359  elog(NOTICE, "RGBA value cannot be greater than 255. Defaulting to 255");
4360  value = 255;
4361  }
4362  else if (value < 0) {
4363  elog(NOTICE, "RGBA value cannot be less than zero. Defaulting to zero");
4364  value = 0;
4365  }
4366  arg->colormap->entry[arg->colormap->nentry].color[j - 1] = value;
4367  }
4368 
4369  pfree(_element);
4370  }
4371 
4372  POSTGIS_RT_DEBUGF(4, "colormap->entry[%d] (isnodata, value, R, G, B, A) = (%d, %f, %d, %d, %d, %d)",
4373  arg->colormap->nentry,
4374  arg->colormap->entry[arg->colormap->nentry].isnodata,
4375  arg->colormap->entry[arg->colormap->nentry].value,
4376  arg->colormap->entry[arg->colormap->nentry].color[0],
4377  arg->colormap->entry[arg->colormap->nentry].color[1],
4378  arg->colormap->entry[arg->colormap->nentry].color[2],
4379  arg->colormap->entry[arg->colormap->nentry].color[3]
4380  );
4381 
4382  arg->colormap->nentry++;
4383  }
4384 
4385  POSTGIS_RT_DEBUGF(4, "colormap->nentry = %d", arg->colormap->nentry);
4386  POSTGIS_RT_DEBUGF(4, "colormap->ncolor = %d", arg->colormap->ncolor);
4387  }
4388 
4389  /* call colormap */
4390  raster = rt_raster_colormap(arg->raster, arg->nband - 1, arg->colormap);
4391  if (raster == NULL) {
4393  PG_FREE_IF_COPY(pgraster, 0);
4394  elog(ERROR, "RASTER_colorMap: Could not create new raster with applied colormap");
4395  PG_RETURN_NULL();
4396  }
4397 
4399  PG_FREE_IF_COPY(pgraster, 0);
4400  pgraster = rt_raster_serialize(raster);
4402 
4403  POSTGIS_RT_DEBUG(3, "RASTER_colorMap: Done");
4404 
4405  if (pgraster == NULL)
4406  PG_RETURN_NULL();
4407 
4408  SET_VARSIZE(pgraster, ((rt_pgraster*) pgraster)->size);
4409  PG_RETURN_POINTER(pgraster);
4410 }
#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:86
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:1375
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:1568
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:385
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:65
#define POSTGIS_RT_DEBUGF(level, msg,...)
Definition: rtpostgis.h:69
uint8_t color[4]
Definition: librtcore.h:2637
double value
Definition: librtcore.h:2636
int isnodata
Definition: librtcore.h:2635
Definition: librtcore.h:2634
rt_colormap_entry entry
Definition: librtcore.h:2649
enum rt_colormap_t::@12 method
uint16_t nentry
Definition: librtcore.h:2648
Struct definitions.
Definition: librtcore.h:2403

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: