GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
raster/color_read.c
Go to the documentation of this file.
1 /*!
2  \file lib/raster/color_read.c
3 
4  \brief Raster Library - Read color table of raster map
5 
6  (C) 1999-2009, 2011 by the GRASS Development Team
7 
8  This program is free software under the GNU General Public
9  License (>=v2). Read the file COPYING that comes with GRASS
10  for details.
11 
12  \author USACERL and many others
13 */
14 
15 #include <string.h>
16 
17 #include <grass/gis.h>
18 #include <grass/raster.h>
19 #include <grass/glocale.h>
20 
21 static int read_new_colors(FILE *, struct Colors *);
22 static int read_old_colors(FILE *, struct Colors *);
23 
24 
25 /*!
26  \brief Read color table of raster map
27 
28  The color table for the raster map <i>name</i> in the specified
29  <i>mapset</i> is read into the <i>colors</i> structure. If the data
30  layer has no color table, a default color table is generated and 0
31  is returned. If there is an error reading the color table, a
32  diagnostic message is printed and -1 is returned. If the color
33  table is read ok, 1 is returned.
34 
35  This routine reads the rules from the color file. If the input
36  raster map is is a floating-point map it calls
37  Rast_mark_colors_as_fp().
38 
39  Note: If a secondary color file for map name <i>name</i> exists in
40  the current project, that color file is read. This allows the
41  user to define their own color lookup tables for cell maps found
42  in other mapsets.
43 
44  Warning message is printed if the color file is
45  missing or invalid.
46 
47  \param name map name
48  \param mapset mapset name
49  \param[out] colors pointer to Colors structure
50 
51  \return -1 on error
52  \return 0 if missing, but default colors generated
53  \return 1 on success
54 */
55 int Rast_read_colors(const char *name, const char *mapset,
56  struct Colors *colors)
57 {
58  int fp;
59  char buf[GNAME_MAX];
60  char *err;
61  char xname[GNAME_MAX];
62  struct Range range;
63  struct FPRange drange;
64  CELL min, max;
65  DCELL dmin, dmax;
66 
67  fp = Rast_map_is_fp(name, mapset);
68  Rast_init_colors(colors);
69 
70  strcpy(xname, name);
71  mapset = G_find_raster(xname, mapset);
72  name = xname;
73 
74  if (fp)
75  Rast_mark_colors_as_fp(colors);
76 
77  /* first look for secondary color table in current mapset */
78  sprintf(buf, "colr2/%s", mapset);
79  if (Rast__read_colors(buf, name, G_mapset(), colors) >= 0)
80  return 1;
81 
82  /* now look for the regular color table */
83  switch (Rast__read_colors("colr", name, mapset, colors)) {
84  case -2:
85  if (!fp) {
86  if (Rast_read_range(name, mapset, &range) >= 0) {
87  Rast_get_range_min_max(&range, &min, &max);
88  if (!Rast_is_c_null_value(&min) &&
89  !Rast_is_c_null_value(&max))
90  Rast_make_colors(colors, DEFAULT_COLOR_TABLE, min, max);
91  return 0;
92  }
93  }
94  else {
95  if (Rast_read_fp_range(name, mapset, &drange) >= 0) {
96  Rast_get_fp_range_min_max(&drange, &dmin, &dmax);
97  if (!Rast_is_d_null_value(&dmin) &&
98  !Rast_is_d_null_value(&dmax))
99  Rast_make_fp_colors(colors, DEFAULT_COLOR_TABLE, dmin, dmax);
100  return 0;
101  }
102  }
103  err = _("missing");
104  break;
105  case -1:
106  err = _("invalid");
107  break;
108  default:
109  return 1;
110  }
111 
112  G_warning(_("Color support for <%s@%s> %s"), name, mapset, err);
113  return -1;
114 }
115 
116 int Rast__read_colors(const char *element, const char *name,
117  const char *mapset, struct Colors *colors)
118 {
119  FILE *fd;
120  int stat;
121  char buf[1024];
122 
123  if (!(fd = G_fopen_old(element, name, mapset)))
124  return -2;
125 
126  /*
127  * first line in 4.0 color files is %
128  * otherwise it is pre 4.0
129  */
130  if (fgets(buf, sizeof buf, fd) == NULL) {
131  fclose(fd);
132  return -1;
133  }
134 
135  stat = 1;
136  if (colors) {
137  G_fseek(fd, 0L, 0);
138 
139  G_strip(buf);
140  if (*buf == '%') { /* 4.0 format */
141  stat = read_new_colors(fd, colors);
142  colors->version = 0; /* 4.0 format */
143  }
144  else {
145  stat = read_old_colors(fd, colors);
146  colors->version = -1; /* pre 4.0 format */
147  }
148  }
149 
150  fclose(fd);
151 
152  return stat;
153 }
154 
155 /* parse input lines with the following formats
156  * val1:r:g:b val2:r:g:b
157  * val:r:g:b (implies cat1==cat2)
158  *
159  * r:g:b can be just a single grey level
160  * cat1:x cat2:y
161  * cat:x
162  *
163  * optional lines are
164  * invert invert color table
165  * shift:n where n is the amount to shift the color table
166  * nv:r:g:b color to use for NULL values
167  * *:r:g:b color to use for undefined (beyond color rules)
168  */
169 static int read_new_colors(FILE * fd, struct Colors *colors)
170 {
171  double val1, val2;
172  long cat1, cat2;
173  int r1, g1, b1;
174  int r2, g2, b2;
175  char buf[1024];
176  char word1[256], word2[256];
177  int n, fp_rule;
178  int null, undef;
179  int modular;
180  DCELL shift;
181 
182  if (fgets(buf, sizeof buf, fd) == NULL)
183  return -1;
184  G_strip(buf);
185 
186  if (sscanf(buf + 1, "%lf %lf", &val1, &val2) == 2)
187  Rast_set_d_color_range((DCELL) val1, (DCELL) val2, colors);
188 
189  modular = 0;
190  while (fgets(buf, sizeof buf, fd)) {
191  null = undef = fp_rule = 0;
192  *word1 = *word2 = 0;
193  n = sscanf(buf, "%s %s", word1, word2);
194  if (n < 1)
195  continue;
196 
197  if (sscanf(word1, "shift:%lf", &shift) == 1
198  || (strcmp(word1, "shift:") == 0 &&
199  sscanf(word2, "%lf", &shift) == 1)) {
200  Rast_shift_d_colors(shift, colors);
201  continue;
202  }
203  if (strcmp(word1, "invert") == 0) {
204  Rast_invert_colors(colors);
205  continue;
206  }
207  if (strcmp(word1, "%%") == 0) {
208  modular = !modular;
209  continue;
210  }
211 
212  switch (sscanf(word1, "nv:%d:%d:%d", &r1, &g1, &b1)) {
213  case 1:
214  null = 1;
215  b1 = g1 = r1;
216  break;
217  case 3:
218  null = 1;
219  break;
220  }
221  if (!null)
222  switch (sscanf(word1, "*:%d:%d:%d", &r1, &g1, &b1)) {
223  case 1:
224  undef = 1;
225  b1 = g1 = r1;
226  break;
227  case 3:
228  undef = 1;
229  break;
230  }
231  if (!null && !undef)
232  switch (sscanf(word1, "%ld:%d:%d:%d", &cat1, &r1, &g1, &b1)) {
233  case 2:
234  b1 = g1 = r1;
235  break;
236  case 4:
237  break;
238  default:
239  if (sscanf(word1, "%lf:%d:%d:%d", &val1, &r1, &g1, &b1) == 4)
240  fp_rule = 1;
241  else if (sscanf(word1, "%lf:%d", &val1, &r1) == 2) {
242  fp_rule = 1;
243  b1 = g1 = r1;
244  }
245  else
246  continue; /* other lines are ignored */
247  }
248  if (n == 2) {
249  switch (sscanf(word2, "%ld:%d:%d:%d", &cat2, &r2, &g2, &b2)) {
250  case 2:
251  b2 = g2 = r2;
252  if (fp_rule)
253  val2 = (DCELL) cat2;
254  break;
255  case 4:
256  if (fp_rule)
257  val2 = (DCELL) cat2;
258  break;
259  default:
260  if (sscanf(word2, "%lf:%d:%d:%d", &val2, &r2, &g2, &b2) == 4) {
261  if (!fp_rule)
262  val1 = (DCELL) cat1;
263  fp_rule = 1;
264  }
265  else if (sscanf(word2, "%lf:%d", &val2, &r2) == 2) {
266  if (!fp_rule)
267  val1 = (DCELL) cat1;
268  fp_rule = 1;
269  b2 = g2 = r2;
270  }
271  else
272  continue; /* other lines are ignored */
273  }
274  }
275  else {
276  if (!fp_rule)
277  cat2 = cat1;
278  else
279  val2 = val1;
280  r2 = r1;
281  g2 = g1;
282  b2 = b1;
283  }
284  if (null)
285  Rast_set_null_value_color(r1, g1, b1, colors);
286  else if (undef)
287  Rast_set_default_color(r1, g1, b1, colors);
288 
289  else if (modular) {
290  if (fp_rule)
291  Rast_add_modular_d_color_rule((DCELL *) & val1, r1, g1,
292  b1, (DCELL *) & val2, r2,
293  g2, b2, colors);
294  else
295  Rast_add_modular_c_color_rule((CELL *) & cat1, r1, g1, b1,
296  (CELL *) & cat2, r2, g2, b2,
297  colors);
298  }
299  else {
300  if (fp_rule)
301  Rast_add_d_color_rule((DCELL *) & val1, r1, g1, b1,
302  (DCELL *) & val2, r2, g2, b2, colors);
303  else
304  Rast_add_c_color_rule((CELL *) & cat1, r1, g1, b1,
305  (CELL *) & cat2, r2, g2, b2, colors);
306  }
307  G_debug(3, "adding rule %ld=%.2lf %d %d %d %ld=%.2lf %d %d %d",
308  cat1, val1, r1, g1, b1, cat2, val2, r2, g2, b2);
309  }
310  return 1;
311 }
312 
313 static int read_old_colors(FILE * fd, struct Colors *colors)
314 {
315  char buf[256];
316  long n;
317  long min;
318  float red_f, grn_f, blu_f;
319  int red, grn, blu;
320  int old;
321  int zero;
322 
323  Rast_init_colors(colors);
324  /*
325  * first line in pre 3.0 color files is number of colors - ignore
326  * otherwise it is #min first color, and the next line is for color 0
327  */
328  if (fgets(buf, sizeof buf, fd) == NULL)
329  return -1;
330 
331  G_strip(buf);
332  if (*buf == '#') { /* 3.0 format */
333  old = 0;
334  if (sscanf(buf + 1, "%ld", &min) != 1) /* first color */
335  return -1;
336  zero = 1;
337  }
338  else {
339  old = 1;
340  min = 0;
341  zero = 0;
342  }
343 
344  colors->cmin = min;
345  n = min;
346  while (fgets(buf, sizeof buf, fd)) {
347  if (old) {
348  if (sscanf(buf, "%f %f %f", &red_f, &grn_f, &blu_f) != 3)
349  return -1;
350 
351  red = 256 * red_f;
352  grn = 256 * grn_f;
353  blu = 256 * blu_f;
354  }
355  else {
356  switch (sscanf(buf, "%d %d %d", &red, &grn, &blu)) {
357  case 1:
358  blu = grn = red;
359  break;
360  case 2:
361  blu = grn;
362  break;
363  case 3:
364  break;
365  default:
366  return -1;
367  }
368  }
369  if (zero) {
370  Rast__insert_color_into_lookup((CELL) 0, red, grn, blu,
371  &colors->fixed);
372  zero = 0;
373  }
374  else
375  Rast__insert_color_into_lookup((CELL) n++, red, grn, blu,
376  &colors->fixed);
377  }
378  colors->cmax = n - 1;
379 
380  return 0;
381 }
382 
383 /*!
384  * \brief Mark colors as floating-point.
385  *
386  * Sets a flag in the <i>colors</i> structure that indicates that
387  * these colors should only be looked up using floating-point raster
388  * data (not integer data). In particular if this flag is set, the
389  * routine Rast_get_c_colors_min_max() should return min=-255$^3$ and
390  * max=255$^3$.
391  *
392  * \param colors pointer to Colors structure
393  */
394 void Rast_mark_colors_as_fp(struct Colors *colors)
395 {
396  colors->is_float = 1;
397 }
struct _Color_Info_ fixed
Definition: gis.h:690
void Rast_add_c_color_rule(const CELL *, int, int, int, const CELL *, int, int, int, struct Colors *)
Adds the integer color rule (CELL version)
Definition: color_rule.c:75
#define Rast_is_d_null_value(dcellVal)
Definition: defs/raster.h:414
#define min(x, y)
Definition: draw2.c:31
int version
Definition: gis.h:678
void Rast_invert_colors(struct Colors *)
Definition: color_invrt.c:17
double DCELL
Definition: gis.h:614
void Rast_mark_colors_as_fp(struct Colors *colors)
Mark colors as floating-point.
DCELL cmax
Definition: gis.h:693
int Rast_read_colors(const char *name, const char *mapset, struct Colors *colors)
Read color table of raster map.
void Rast_shift_d_colors(DCELL, struct Colors *)
Definition: color_shift.c:22
int is_float
Definition: gis.h:681
void G_strip(char *)
Removes all leading and trailing white space from string.
Definition: strings.c:300
void Rast_set_d_color_range(DCELL, DCELL, struct Colors *)
Set color range (DCELL version)
Definition: color_range.c:42
#define NULL
Definition: ccmath.h:32
#define max(x, y)
Definition: draw2.c:32
int Rast_read_range(const char *, const char *, struct Range *)
Read raster range (CELL)
Definition: range.c:160
Definition: lidar.h:86
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
Definition: symbol/read.c:220
void Rast_get_fp_range_min_max(const struct FPRange *, DCELL *, DCELL *)
Get minimum and maximum value from fp range.
Definition: range.c:764
DCELL cmin
Definition: gis.h:692
int Rast__insert_color_into_lookup(CELL, int, int, int, struct _Color_Info_ *)
Definition: color_insrt.c:14
int Rast_add_modular_c_color_rule(const CELL *, int, int, int, const CELL *, int, int, int, struct Colors *)
Add modular integer color rule (CELL version)
Definition: color_rule.c:184
void G_fseek(FILE *, off_t, int)
Change the file position of the stream.
Definition: gis/seek.c:50
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
Definition: gis/open.c:253
void Rast_set_default_color(int, int, int, struct Colors *)
Set default color value.
Definition: color_set.c:100
int Rast__read_colors(const char *element, const char *name, const char *mapset, struct Colors *colors)
void Rast_set_null_value_color(int, int, int, struct Colors *)
Set color for NULL-value.
Definition: color_set.c:79
Definition: raster.h:225
Definition: gis.h:676
const char * G_find_raster(char *, const char *)
Find a raster map.
Definition: find_rast.c:55
int Rast_read_fp_range(const char *, const char *, struct FPRange *)
Read floating-point range.
Definition: range.c:71
#define DEFAULT_COLOR_TABLE
Definition: gis.h:383
const char * G_mapset(void)
Get current mapset name.
Definition: gis/mapset.c:33
#define GNAME_MAX
Definition: gis.h:177
void G_warning(const char *,...) __attribute__((format(printf
int CELL
Definition: gis.h:613
void Rast_make_colors(struct Colors *, const char *, CELL, CELL)
Load color rules from predefined color table.
int Rast_add_modular_d_color_rule(const DCELL *, int, int, int, const DCELL *, int, int, int, struct Colors *)
Add modular floating-point color rule (DCELL version)
Definition: color_rule.c:124
#define _(str)
Definition: glocale.h:10
void Rast_add_d_color_rule(const DCELL *, int, int, int, const DCELL *, int, int, int, struct Colors *)
Adds the floating-point color rule (DCELL version)
Definition: color_rule.c:35
void Rast_make_fp_colors(struct Colors *, const char *, DCELL, DCELL)
Load color rules from predefined floating-point color table.
const char * name
Definition: named_colr.c:7
void Rast_init_colors(struct Colors *)
Initialize color structure.
Definition: color_init.c:25
#define Rast_is_c_null_value(cellVal)
Definition: defs/raster.h:410
int G_debug(int, const char *,...) __attribute__((format(printf
int Rast_map_is_fp(const char *, const char *)
Check if raster map is floating-point.
Definition: raster/open.c:847
void Rast_get_range_min_max(const struct Range *, CELL *, CELL *)
Get range min and max.
Definition: range.c:714