PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ RASTER_colorMap()

Datum RASTER_colorMap ( PG_FUNCTION_ARGS  )

Definition at line 4227 of file rtpg_mapalgebra.c.

4228{
4229 rt_pgraster *pgraster = NULL;
4230 rtpg_colormap_arg arg = NULL;
4231 char *junk = NULL;
4232 rt_raster raster = NULL;
4233
4234 POSTGIS_RT_DEBUG(3, "RASTER_colorMap: Starting");
4235
4236 /* pgraster is NULL, return NULL */
4237 if (PG_ARGISNULL(0))
4238 PG_RETURN_NULL();
4239
4240 /* init arg */
4241 arg = rtpg_colormap_arg_init();
4242 if (arg == NULL) {
4243 elog(ERROR, "RASTER_colorMap: Could not initialize argument structure");
4244 PG_RETURN_NULL();
4245 }
4246
4247 /* raster (0) */
4248 pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
4249
4250 /* raster object */
4251 arg->raster = rt_raster_deserialize(pgraster, FALSE);
4252 if (!arg->raster) {
4254 PG_FREE_IF_COPY(pgraster, 0);
4255 elog(ERROR, "RASTER_colorMap: Could not deserialize raster");
4256 PG_RETURN_NULL();
4257 }
4258
4259 /* nband (1) */
4260 if (!PG_ARGISNULL(1))
4261 arg->nband = PG_GETARG_INT32(1);
4262 POSTGIS_RT_DEBUGF(4, "nband = %d", arg->nband);
4263
4264 /* check that band works */
4265 if (!rt_raster_has_band(arg->raster, arg->nband - 1)) {
4266 elog(NOTICE, "Raster does not have band at index %d. Returning empty raster", arg->nband);
4267
4268 raster = rt_raster_clone(arg->raster, 0);
4269 if (raster == NULL) {
4271 PG_FREE_IF_COPY(pgraster, 0);
4272 elog(ERROR, "RASTER_colorMap: Could not create empty raster");
4273 PG_RETURN_NULL();
4274 }
4275
4277 PG_FREE_IF_COPY(pgraster, 0);
4278
4279 pgraster = rt_raster_serialize(raster);
4280 rt_raster_destroy(raster);
4281 if (pgraster == NULL)
4282 PG_RETURN_NULL();
4283
4284 SET_VARSIZE(pgraster, ((rt_pgraster*) pgraster)->size);
4285 PG_RETURN_POINTER(pgraster);
4286 }
4287
4288 /* get band */
4289 arg->band = rt_raster_get_band(arg->raster, arg->nband - 1);
4290 if (arg->band == NULL) {
4291 int nband = arg->nband;
4293 PG_FREE_IF_COPY(pgraster, 0);
4294 elog(ERROR, "RASTER_colorMap: Could not get band at index %d", nband);
4295 PG_RETURN_NULL();
4296 }
4297
4298 /* method (3) */
4299 if (!PG_ARGISNULL(3)) {
4300 char *method = NULL;
4301 char *tmp = text_to_cstring(PG_GETARG_TEXT_P(3));
4302 POSTGIS_RT_DEBUGF(4, "raw method = %s", tmp);
4303
4304 method = rtpg_trim(tmp);
4305 pfree(tmp);
4306 method = rtpg_strtoupper(method);
4307
4308 if (strcmp(method, "INTERPOLATE") == 0)
4309 arg->colormap->method = CM_INTERPOLATE;
4310 else if (strcmp(method, "EXACT") == 0)
4311 arg->colormap->method = CM_EXACT;
4312 else if (strcmp(method, "NEAREST") == 0)
4313 arg->colormap->method = CM_NEAREST;
4314 else {
4315 elog(NOTICE, "Unknown value provided for method. Defaulting to INTERPOLATE");
4316 arg->colormap->method = CM_INTERPOLATE;
4317 }
4318 }
4319 /* default to INTERPOLATE */
4320 else
4321 arg->colormap->method = CM_INTERPOLATE;
4322 POSTGIS_RT_DEBUGF(4, "method = %d", arg->colormap->method);
4323
4324 /* colormap (2) */
4325 if (PG_ARGISNULL(2)) {
4327 PG_FREE_IF_COPY(pgraster, 0);
4328 elog(ERROR, "RASTER_colorMap: Value must be provided for colormap");
4329 PG_RETURN_NULL();
4330 }
4331 else {
4332 char *tmp = NULL;
4333 char *colormap = text_to_cstring(PG_GETARG_TEXT_P(2));
4334 char *_entry;
4335 char *_element;
4336 uint32_t i = 0;
4337 uint32_t j = 0;
4338
4339 POSTGIS_RT_DEBUGF(4, "colormap = %s", colormap);
4340
4341 /* empty string */
4342 if (!strlen(colormap)) {
4344 PG_FREE_IF_COPY(pgraster, 0);
4345 elog(ERROR, "RASTER_colorMap: Value must be provided for colormap");
4346 PG_RETURN_NULL();
4347 }
4348
4349 arg->entry = rtpg_strsplit(colormap, "\n", &(arg->nentry));
4350 pfree(colormap);
4351 if (arg->nentry < 1) {
4353 PG_FREE_IF_COPY(pgraster, 0);
4354 elog(ERROR, "RASTER_colorMap: Could not process the value provided for colormap");
4355 PG_RETURN_NULL();
4356 }
4357
4358 /* allocate the max # of colormap entries */
4359 arg->colormap->entry = palloc(sizeof(struct rt_colormap_entry_t) * arg->nentry);
4360 if (arg->colormap->entry == NULL) {
4362 PG_FREE_IF_COPY(pgraster, 0);
4363 elog(ERROR, "RASTER_colorMap: Could not allocate memory for colormap entries");
4364 PG_RETURN_NULL();
4365 }
4366 memset(arg->colormap->entry, 0, sizeof(struct rt_colormap_entry_t) * arg->nentry);
4367
4368 /* each entry */
4369 for (i = 0; i < arg->nentry; i++) {
4370 /* substitute space for other delimiters */
4371 tmp = rtpg_strreplace(arg->entry[i], ":", " ", NULL);
4372 _entry = rtpg_strreplace(tmp, ",", " ", NULL);
4373 pfree(tmp);
4374 tmp = rtpg_strreplace(_entry, "\t", " ", NULL);
4375 pfree(_entry);
4376 _entry = rtpg_trim(tmp);
4377 pfree(tmp);
4378
4379 POSTGIS_RT_DEBUGF(4, "Processing entry[%d] = %s", i, arg->entry[i]);
4380 POSTGIS_RT_DEBUGF(4, "Cleaned entry[%d] = %s", i, _entry);
4381
4382 /* empty entry, continue */
4383 if (!strlen(_entry)) {
4384 POSTGIS_RT_DEBUGF(3, "Skipping empty entry[%d]", i);
4385 pfree(_entry);
4386 continue;
4387 }
4388
4389 arg->element = rtpg_strsplit(_entry, " ", &(arg->nelement));
4390 pfree(_entry);
4391 if (arg->nelement < 2) {
4393 PG_FREE_IF_COPY(pgraster, 0);
4394 elog(ERROR, "RASTER_colorMap: Could not process colormap entry %d", i + 1);
4395 PG_RETURN_NULL();
4396 }
4397 else if (arg->nelement > 5) {
4398 elog(NOTICE, "More than five elements in colormap entry %d. Using at most five elements", i + 1);
4399 arg->nelement = 5;
4400 }
4401
4402 /* smallest # of colors */
4403 if (((int)arg->nelement - 1) < arg->colormap->ncolor)
4404 arg->colormap->ncolor = arg->nelement - 1;
4405
4406 /* each element of entry */
4407 for (j = 0; j < arg->nelement; j++) {
4408
4409 _element = rtpg_trim(arg->element[j]);
4410 _element = rtpg_strtoupper(_element);
4411 POSTGIS_RT_DEBUGF(4, "Processing entry[%d][%d] = %s", i, j, arg->element[j]);
4412 POSTGIS_RT_DEBUGF(4, "Cleaned entry[%d][%d] = %s", i, j, _element);
4413
4414 /* first element is ALWAYS a band value, percentage OR "nv" string */
4415 if (j == 0) {
4416 char *percent = NULL;
4417
4418 /* NODATA */
4419 if (
4420 strcmp(_element, "NV") == 0 ||
4421 strcmp(_element, "NULL") == 0 ||
4422 strcmp(_element, "NODATA") == 0
4423 ) {
4424 POSTGIS_RT_DEBUG(4, "Processing NODATA string");
4425
4426 if (arg->nodataentry > -1) {
4427 elog(NOTICE, "More than one NODATA entry found. Using only the first one");
4428 }
4429 else {
4430 arg->colormap->entry[arg->colormap->nentry].isnodata = 1;
4431 /* no need to set value as value comes from band's NODATA */
4432 arg->colormap->entry[arg->colormap->nentry].value = 0;
4433 }
4434 }
4435 /* percent value */
4436 else if ((percent = strchr(_element, '%')) != NULL) {
4437 double value;
4438 POSTGIS_RT_DEBUG(4, "Processing percent string");
4439
4440 /* get the band stats */
4441 if (arg->bandstats == NULL) {
4442 POSTGIS_RT_DEBUG(4, "Getting band stats");
4443
4444 arg->bandstats = rt_band_get_summary_stats(arg->band, 1, 1, 0, NULL, NULL, NULL);
4445 if (arg->bandstats == NULL) {
4446 pfree(_element);
4448 PG_FREE_IF_COPY(pgraster, 0);
4449 elog(ERROR, "RASTER_colorMap: Could not get band's summary stats to process percentages");
4450 PG_RETURN_NULL();
4451 }
4452 }
4453
4454 /* get the string before the percent char */
4455 tmp = palloc(sizeof(char) * (percent - _element + 1));
4456 if (tmp == NULL) {
4457 pfree(_element);
4459 PG_FREE_IF_COPY(pgraster, 0);
4460 elog(ERROR, "RASTER_colorMap: Could not allocate memory for value of percentage");
4461 PG_RETURN_NULL();
4462 }
4463
4464 memcpy(tmp, _element, percent - _element);
4465 tmp[percent - _element] = '\0';
4466 POSTGIS_RT_DEBUGF(4, "Percent value = %s", tmp);
4467
4468 /* get percentage value */
4469 errno = 0;
4470 value = strtod(tmp, NULL);
4471 pfree(tmp);
4472 if (errno != 0 || _element == junk) {
4473 pfree(_element);
4475 PG_FREE_IF_COPY(pgraster, 0);
4476 elog(ERROR, "RASTER_colorMap: Could not process percent string to value");
4477 PG_RETURN_NULL();
4478 }
4479
4480 /* check percentage */
4481 if (value < 0.) {
4482 elog(NOTICE, "Percentage values cannot be less than zero. Defaulting to zero");
4483 value = 0.;
4484 }
4485 else if (value > 100.) {
4486 elog(NOTICE, "Percentage values cannot be greater than 100. Defaulting to 100");
4487 value = 100.;
4488 }
4489
4490 /* get the true pixel value */
4491 /* TODO: should the percentage be quantile based? */
4492 arg->colormap->entry[arg->colormap->nentry].value = ((value / 100.) * (arg->bandstats->max - arg->bandstats->min)) + arg->bandstats->min;
4493 }
4494 /* straight value */
4495 else {
4496 errno = 0;
4497 arg->colormap->entry[arg->colormap->nentry].value = strtod(_element, &junk);
4498 if (errno != 0 || _element == junk) {
4499 pfree(_element);
4501 PG_FREE_IF_COPY(pgraster, 0);
4502 elog(ERROR, "RASTER_colorMap: Could not process string to value");
4503 PG_RETURN_NULL();
4504 }
4505 }
4506
4507 }
4508 /* RGB values (0 - 255) */
4509 else {
4510 int value = 0;
4511
4512 errno = 0;
4513 value = (int) strtod(_element, &junk);
4514 if (errno != 0 || _element == junk) {
4515 pfree(_element);
4517 PG_FREE_IF_COPY(pgraster, 0);
4518 elog(ERROR, "RASTER_colorMap: Could not process string to value");
4519 PG_RETURN_NULL();
4520 }
4521
4522 if (value > 255) {
4523 elog(NOTICE, "RGBA value cannot be greater than 255. Defaulting to 255");
4524 value = 255;
4525 }
4526 else if (value < 0) {
4527 elog(NOTICE, "RGBA value cannot be less than zero. Defaulting to zero");
4528 value = 0;
4529 }
4530 arg->colormap->entry[arg->colormap->nentry].color[j - 1] = value;
4531 }
4532
4533 pfree(_element);
4534 }
4535
4536 POSTGIS_RT_DEBUGF(4, "colormap->entry[%d] (isnodata, value, R, G, B, A) = (%d, %f, %d, %d, %d, %d)",
4537 arg->colormap->nentry,
4538 arg->colormap->entry[arg->colormap->nentry].isnodata,
4539 arg->colormap->entry[arg->colormap->nentry].value,
4540 arg->colormap->entry[arg->colormap->nentry].color[0],
4541 arg->colormap->entry[arg->colormap->nentry].color[1],
4542 arg->colormap->entry[arg->colormap->nentry].color[2],
4543 arg->colormap->entry[arg->colormap->nentry].color[3]
4544 );
4545
4546 arg->colormap->nentry++;
4547 }
4548
4549 POSTGIS_RT_DEBUGF(4, "colormap->nentry = %d", arg->colormap->nentry);
4550 POSTGIS_RT_DEBUGF(4, "colormap->ncolor = %d", arg->colormap->ncolor);
4551 }
4552
4553 /* call colormap */
4554 raster = rt_raster_colormap(arg->raster, arg->nband - 1, arg->colormap);
4555 if (raster == NULL) {
4557 PG_FREE_IF_COPY(pgraster, 0);
4558 elog(ERROR, "RASTER_colorMap: Could not create new raster with applied colormap");
4559 PG_RETURN_NULL();
4560 }
4561
4563 PG_FREE_IF_COPY(pgraster, 0);
4564 pgraster = rt_raster_serialize(raster);
4565 rt_raster_destroy(raster);
4566
4567 POSTGIS_RT_DEBUG(3, "RASTER_colorMap: Done");
4568
4569 if (pgraster == NULL)
4570 PG_RETURN_NULL();
4571
4572 SET_VARSIZE(pgraster, ((rt_pgraster*) pgraster)->size);
4573 PG_RETURN_POINTER(pgraster);
4574}
#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:1253
rt_raster rt_raster_clone(rt_raster raster, uint8_t deep)
Clone an existing raster.
Definition rt_raster.c:1446
void * rt_raster_serialize(rt_raster raster)
Return this raster in serialized form.
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.
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:56
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
Definition rtrowdump.py:125
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)
char * rtpg_trim(const char *input)
char * rtpg_strtoupper(char *str)
static rtpg_colormap_arg rtpg_colormap_arg_init(void)
static void rtpg_colormap_arg_destroy(rtpg_colormap_arg arg)
#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:2700
double value
Definition librtcore.h:2699
int isnodata
Definition librtcore.h:2698
Definition librtcore.h:2697
rt_colormap_entry entry
Definition librtcore.h:2712
uint16_t nentry
Definition librtcore.h:2711
enum rt_colormap_t::@13 method
Struct definitions.
Definition librtcore.h:2452

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, 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, 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(), and rt_colormap_entry_t::value.

Here is the call graph for this function: