GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-d6dec75dd4
raster/color_rules.c
Go to the documentation of this file.
1 /*!
2  \file lib/raster/color_rules.c
3 
4  \brief Raster Library - Read and parse color rules file
5 
6  (C) 2007-2016 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 Glynn Clements
13  */
14 
15 #include <stdio.h>
16 
17 #include <grass/gis.h>
18 #include <grass/colors.h>
19 #include <grass/raster.h>
20 #include <grass/glocale.h>
21 
22 struct rule {
23  int set;
24  int r, g, b;
25  DCELL val;
26 };
27 
28 enum rule_error {
29  CR_OK = 0,
34 };
35 
36 /*!
37  \brief Read color rule
38 
39  The val output parameter is always an absolute value and is derived
40  from the rule and the min and max values in case the rule is in percents.
41 
42  Always only one of the norm, nval, and dflt output parameters is set
43  to non-zero value, the others are set to zero.
44 
45  The return code can be translated to an error message using
46  the Rast_parse_color_rule_error() function.
47 
48  \param min, max min & max values (used only when color rules are in
49  percentage) \param buf string with the color rule \param[out] val value which
50  the color is assigned to \param[out] r,g,b color values \param[out] norm set
51  to non-zero value if the value and color are set \param[out] nval set to
52  non-zero value if rule is for null value \param[out] dflt set to non-zero
53  value if rule specifies the default color
54 
55  \returns enum rule_error values (non-zero on failure)
56  */
57 int Rast_parse_color_rule(DCELL min, DCELL max, const char *buf, DCELL *val,
58  int *r, int *g, int *b, int *norm, int *nval,
59  int *dflt)
60 {
61  char value[80], color[80];
62  double x;
63  char c;
64 
65  *norm = *nval = *dflt = 0;
66 
67  if (sscanf(buf, "%s %[^\n]", value, color) != 2)
68  return CR_ERROR_RULE_SYNTAX;
69 
70  /* we don't allow 'none' color here (ret == 2) */
71  /* G_str_to_color chops and has only 1 error state */
72  if (G_str_to_color(color, r, g, b) != 1)
73  return CR_ERROR_COLOR_SYNTAX;
74 
75  G_chop(value);
76 
77  if (G_strcasecmp(value, "default") == 0) {
78  *dflt = 1;
79  return CR_OK;
80  }
81 
82  if (G_strcasecmp(value, "nv") == 0) {
83  *nval = 1;
84  return CR_OK;
85  }
86 
87  if (sscanf(value, "%lf%c", &x, &c) == 2 && c == '%') {
88  if (x < 0 || x > 100)
89  return CR_ERROR_PERCENT;
90 
91  *val = min + (max - min) * (x / 100);
92  *norm = 1;
93  return CR_OK;
94  }
95 
96  if (sscanf(value, "%lf", val) == 1) {
97  *norm = 1;
98  return CR_OK;
99  }
100 
101  return CR_ERROR_VALUE;
102 }
103 
104 /*!
105  \brief Parse color rule
106 
107  \param code
108 
109  \return pointer to buffer with error message
110  */
111 const char *Rast_parse_color_rule_error(int code)
112 {
113  switch (code) {
114  case CR_OK:
115  return "";
117  return _("syntax error in the color rule");
119  return _("syntax error in the color format");
120  /* we no longer distinguish between these two errors
121  case CR_ERROR_RGB:
122  return _("R/G/B not in range 0-255");
123  case CR_ERROR_COLOR:
124  return _("invalid color name");
125  */
126  case CR_ERROR_PERCENT:
127  return _("percentage not in range 0-100");
128  case CR_ERROR_VALUE:
129  return _("invalid value");
130  default:
131  return _("unknown error");
132  }
133 }
134 
135 /*!
136  \brief Read color rule
137 
138  \param closure
139  \param min, max min & max values (used only when color rules are in
140  percentage) \param val value \param[out] r,g,b color values \param norm
141  \param nval
142  \param dflt
143 
144  \return 0 on failure
145  \return 1 on success
146  */
147 int Rast_read_color_rule(void *closure, DCELL min, DCELL max, DCELL *val,
148  int *r, int *g, int *b, int *norm, int *nval,
149  int *dflt)
150 {
151  char buf[1024];
152  FILE *fp = closure;
153  int ret;
154 
155  *norm = *nval = *dflt = 0;
156 
157  for (;;) {
158  if (!G_getl2(buf, sizeof(buf), fp))
159  return 0;
160 
161  G_strip(buf);
162  G_debug(5, "color buf = [%s]", buf);
163 
164  if (*buf == '\0')
165  continue;
166  if (*buf == '#')
167  continue;
168 
169  ret = Rast_parse_color_rule(min, max, buf, val, r, g, b, norm, nval,
170  dflt);
171  if (ret == 0)
172  return 1;
173 
174  G_fatal_error(_("bad rule (%s): [%s]"),
175  Rast_parse_color_rule_error(ret), buf);
176  }
177 
178  return 0;
179 }
180 
181 /*!
182  \brief Read color rules from file
183 
184  \param[out] colors pointer to Colors structure
185  \param min, max min & max values (used only when color rules are in
186  percentage) \param read_rule pointer to read_rule_fn structure \param closure
187 
188  \return 0 on failure
189  \return 1 on success
190  */
192  read_rule_fn *read_rule, void *closure)
193 {
194  struct rule *rule = NULL;
195  int nrules = 0;
196  struct rule dflt, null;
197  int set, is_null, is_dflt, r, g, b;
198  DCELL val;
199  int n;
200 
201  if (!read_rule)
202  read_rule = Rast_read_color_rule;
203 
204  Rast_init_colors(colors);
205 
206  /* initialization */
207  dflt.r = dflt.g = dflt.b = dflt.set = 0;
208  null.r = null.g = null.b = null.set = 0;
209 
210  while ((*read_rule)(closure, min, max, &val, &r, &g, &b, &set, &is_null,
211  &is_dflt)) {
212  struct rule *p = NULL;
213 
214  if (set) {
215  n = nrules++;
216  rule = G_realloc(rule, nrules * sizeof(struct rule));
217  p = &rule[n];
218  }
219  else if (is_dflt)
220  p = &dflt;
221  else if (is_null)
222  p = &null;
223 
224  if (!p)
225  G_fatal_error(_("Unknown error reading color rule"));
226 
227  p->r = r;
228  p->g = g;
229  p->b = b;
230  p->set = 1;
231  p->val = val;
232  }
233 
234  if (nrules == 0)
235  return 0;
236 
237  if (nrules == 1) {
238  const struct rule *p = &rule[0];
239 
240  Rast_set_d_color(p->val, p->r, p->g, p->b, colors);
241  }
242 
243  for (n = 1; n < nrules; n++) {
244  struct rule *lo = &rule[n - 1];
245  struct rule *hi = &rule[n];
246 
247  Rast_add_d_color_rule(&lo->val, lo->r, lo->g, lo->b, &hi->val, hi->r,
248  hi->g, hi->b, colors);
249  }
250 
251  G_free(rule);
252 
253  /* null value and default color set up, if rules are set up by user */
254  if (null.set)
255  Rast_set_null_value_color(null.r, null.g, null.b, colors);
256 
257  if (dflt.set)
258  Rast_set_default_color(dflt.r, dflt.g, dflt.b, colors);
259 
260  return 1;
261 }
262 
263 static int load_rules_file(struct Colors *colors, const char *path, DCELL min,
264  DCELL max)
265 {
266  FILE *fp;
267  int ret;
268 
269  fp = fopen(path, "r");
270 
271  if (!fp)
272  return 0;
273 
275  (void *)fp);
276 
277  fclose(fp);
278 
279  return ret;
280 }
281 
282 /*!
283  \brief Load color rules from file
284 
285  \param[out] colors pointer to Colors structure
286  \param path path to the color rules file
287  \param min, max min & max values (used only when color rules are in
288  percentage)
289 
290  \return 0 on failure
291  \return 1 on success
292  */
293 int Rast_load_colors(struct Colors *colors, const char *path, CELL min,
294  CELL max)
295 {
296  return load_rules_file(colors, path, (DCELL)min, (DCELL)max);
297 }
298 
299 /*!
300  \brief Load color floating-point rules from file
301 
302  \param[out] colors pointer to Colors structure
303  \param path path to the color rules file
304  \param min, max min & max values (used only when color rules are in
305  percentage)
306 
307  \return 0 on failure
308  \return 1 on success
309  */
310 int Rast_load_fp_colors(struct Colors *colors, const char *path, DCELL min,
311  DCELL max)
312 {
313  return load_rules_file(colors, path, min, max);
314 }
315 
316 static void load_rules_name(struct Colors *colors, const char *name, DCELL min,
317  DCELL max)
318 {
319  char path[GPATH_MAX];
320 
321  sprintf(path, "%s/etc/colors/%s", G_gisbase(), name);
322 
323  if (!load_rules_file(colors, path, min, max))
324  G_fatal_error(_("Unable to load color rules <%s>"), name);
325 }
326 
327 /*!
328  \brief Load color rules from predefined color table
329 
330  \param[out] colors pointer to Colors structure
331  \param name name of color table to load
332  \param min, max min & max values (used only when color rules are in
333  percentage)
334  */
335 void Rast_make_colors(struct Colors *colors, const char *name, CELL min,
336  CELL max)
337 {
338  load_rules_name(colors, name, (DCELL)min, (DCELL)max);
339 }
340 
341 /*!
342  \brief Load color rules from predefined floating-point color table
343 
344  \param[out] colors pointer to Colors structure
345  \param name name of color table to load
346  \param min, max min & max values (used only when color rules are in
347  percentage)
348  */
349 void Rast_make_fp_colors(struct Colors *colors, const char *name, DCELL min,
350  DCELL max)
351 {
352  load_rules_name(colors, name, min, max);
353 }
#define NULL
Definition: ccmath.h:32
int G_str_to_color(const char *, int *, int *, int *)
Parse color string and set red,green,blue.
Definition: color_str.c:101
int G_getl2(char *, int, FILE *)
Gets a line of text from a file of any pedigree.
Definition: getl.c:60
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_realloc(p, n)
Definition: defs/gis.h:96
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_strip(char *)
Removes all leading and trailing white space from string.
Definition: strings.c:300
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition: strings.c:47
const char * G_gisbase(void)
Get full path name of the top level module directory.
Definition: gisbase.c:39
char * G_chop(char *)
Chop leading and trailing white spaces.
Definition: strings.c:332
int G_debug(int, const char *,...) __attribute__((format(printf
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:38
void Rast_set_null_value_color(int, int, int, struct Colors *)
Set color for NULL-value.
Definition: color_set.c:79
int read_rule_fn(void *, DCELL, DCELL, DCELL *, int *, int *, int *, int *, int *, int *)
Definition: defs/raster.h:225
void Rast_set_d_color(DCELL, int, int, int, struct Colors *)
Set a category color (DCELL)
Definition: color_set.c:60
void Rast_init_colors(struct Colors *)
Initialize color structure.
Definition: color_init.c:25
void Rast_set_default_color(int, int, int, struct Colors *)
Set default color value.
Definition: color_set.c:99
#define min(x, y)
Definition: draw2.c:29
#define max(x, y)
Definition: draw2.c:30
#define GPATH_MAX
Definition: gis.h:194
double DCELL
Definition: gis.h:629
int CELL
Definition: gis.h:628
#define _(str)
Definition: glocale.h:10
float g
Definition: named_colr.c:7
const char * name
Definition: named_colr.c:6
double b
Definition: r_raster.c:39
double r
Definition: r_raster.c:39
int Rast_load_colors(struct Colors *colors, const char *path, CELL min, CELL max)
Load color rules from file.
int Rast_read_color_rule(void *closure, DCELL min, DCELL max, DCELL *val, int *r, int *g, int *b, int *norm, int *nval, int *dflt)
Read color rule.
int Rast_read_color_rules(struct Colors *colors, DCELL min, DCELL max, read_rule_fn *read_rule, void *closure)
Read color rules from file.
void Rast_make_fp_colors(struct Colors *colors, const char *name, DCELL min, DCELL max)
Load color rules from predefined floating-point color table.
int Rast_parse_color_rule(DCELL min, DCELL max, const char *buf, DCELL *val, int *r, int *g, int *b, int *norm, int *nval, int *dflt)
Read color rule.
const char * Rast_parse_color_rule_error(int code)
Parse color rule.
rule_error
@ CR_ERROR_COLOR_SYNTAX
@ CR_ERROR_VALUE
@ CR_ERROR_PERCENT
@ CR_OK
@ CR_ERROR_RULE_SYNTAX
void Rast_make_colors(struct Colors *colors, const char *name, CELL min, CELL max)
Load color rules from predefined color table.
int Rast_load_fp_colors(struct Colors *colors, const char *path, DCELL min, DCELL max)
Load color floating-point rules from file.
Definition: gis.h:686
Definition: path.h:15
#define x