PostGIS  2.3.7dev-r@@SVN_REVISION@@
Datum RASTER_colorMap ( PG_FUNCTION_ARGS  )

Definition at line 4062 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, POSTGIS_RT_DEBUG, POSTGIS_RT_DEBUGF, rtrowdump::raster, rtpg_colormap_arg_t::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(), genraster::value, and rt_colormap_entry_t::value.

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

Here is the call graph for this function: