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