PostGIS  2.5.0beta2dev-r@@SVN_REVISION@@

◆ RASTER_colorMap()

Datum RASTER_colorMap ( PG_FUNCTION_ARGS  )

Definition at line 4060 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, text_to_cstring(), genraster::value, and rt_colormap_entry_t::value.

Referenced by rtpg_colormap_arg_destroy().

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