GRASS 8 Programmer's Manual 8.6.0dev(2026)-8843f13794
Loading...
Searching...
No Matches
raster/color_write.c
Go to the documentation of this file.
1/*!
2 * \file lib/raster/color_write.c
3 *
4 * \brief Raster Library - Write color table of raster map
5 *
6 * SPDX-FileCopyrightText: 1999-2009 GRASS Development Team
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 *
9 * \author USACERL and many others
10 */
11
12#include <string.h>
13#include <stdlib.h>
14#include <stdio.h>
15#include <grass/gis.h>
16#include <grass/glocale.h>
17#include <grass/raster.h>
18
19static void write_rules(FILE *, struct _Color_Rule_ *, DCELL, DCELL);
20static void write_new_colors(FILE *, struct Colors *);
21static void write_old_colors(FILE *, struct Colors *);
22static void forced_write_old_colors(FILE *, struct Colors *);
23static void format_min(char *, double);
24static void format_max(char *, double);
25
26#define FORMAT_STR_SZ 100
27
28/*!
29 * \brief Write map layer color table
30 *
31 * The color table is written for the raster map <i>name</i> in the
32 * specified <i>mapset</i> from the <i>colors</i> structure.
33 *
34 * If there is an error, -1 is returned. No diagnostic is
35 * printed. Otherwise, 1 is returned.
36 *
37 * The <i>colors</i> structure must be created properly, i.e.,
38 * Rast_init_colors() to initialize the structure and Rast_add_c_color_rule()
39 * to set the category colors. These routines are called by
40 * higher level routines which read or create entire color tables,
41 * such as Rast_read_colors() or Rast_make_ramp_colors().
42 *
43 * <b>Note:</b> The calling sequence for this function deserves
44 * special attention. The <i>mapset</i> parameter seems to imply that
45 * it is possible to overwrite the color table for a raster map which
46 * is in another mapset. However, this is not what actually
47 * happens. It is very useful for users to create their own color
48 * tables for raster maps in other mapsets, but without overwriting
49 * other users' color tables for the same raster map. If <i>mapset</i>
50 * is the current mapset, then the color file for <i>name</i> will be
51 * overwritten by the new color table. But if <i>mapset</i> is not the
52 * current mapset, then the color table is actually written in the
53 * current mapset under the <tt>colr2</tt> element as:
54 * <tt>colr2/mapset/name</tt>.
55 *
56 * The rules are written out using floating-point format, removing
57 * trailing zeros (possibly producing integers). The flag marking the
58 * colors as floating-point is <b>not</b> written.
59 *
60 * If the environment variable FORCE_GRASS3_COLORS is set (to anything at all)
61 * then the output format is 3.0, even if the structure contains 4.0 rules.
62 * This allows users to create 3.0 color files for export to sites which
63 * don't yet have 4.0
64 *
65 * \param name map name
66 * \param mapset mapset name
67 * \param colors pointer to structure Colors which holds color info
68 *
69 * \return void
70 */
71void Rast_write_colors(const char *name, const char *mapset,
72 struct Colors *colors)
73{
74 char element[512];
76 FILE *fd;
77
79 if (strcmp(xmapset, mapset) != 0)
80 G_fatal_error(_("Qualified name <%s> doesn't match mapset <%s>"),
81 name, mapset);
82 name = xname;
83 }
84 /*
85 * if mapset is current mapset, remove colr2 file (created by pre 3.0 grass)
86 * and then write original color table
87 * else write secondary color table
88 */
89 snprintf(element, sizeof(element), "colr2/%s", mapset);
90 if (strcmp(mapset, G_mapset()) == 0) {
91 G_remove(element, name); /* get rid of existing colr2, if any */
92 strcpy(element, "colr");
93 }
94 if (!(fd = G_fopen_new(element, name)))
95 G_fatal_error(_("Unable to create <%s> file for map <%s>"), element,
96 name);
97
98 Rast__write_colors(fd, colors);
99 fclose(fd);
100}
101
102/*!
103 * \brief Write map layer color table
104 *
105 * \param fd file descriptor
106 * \param colors pointer to Colors structure which holds color info
107 */
108void Rast__write_colors(FILE *fd, struct Colors *colors)
109{
110 if (getenv("FORCE_GRASS3_COLORS"))
111 forced_write_old_colors(fd, colors);
112 else if (colors->version < 0)
113 write_old_colors(fd, colors);
114 else
115 write_new_colors(fd, colors);
116}
117
118static void write_new_colors(FILE *fd, struct Colors *colors)
119{
120 char str1[100], str2[100];
121
122 format_min(str1, (double)colors->cmin);
123 format_max(str2, (double)colors->cmax);
124 fprintf(fd, "%% %s %s\n", str1, str2);
125
126 if (colors->shift) {
127 snprintf(str2, sizeof(str2), "%.17g", (double)colors->shift);
129 fprintf(fd, "shift:%s\n", str2);
130 }
131 if (colors->invert)
132 fprintf(fd, "invert\n");
133
134 if (colors->null_set) {
135 fprintf(fd, "nv:%d", colors->null_red);
136 if (colors->null_red != colors->null_grn ||
137 colors->null_red != colors->null_blu)
138 fprintf(fd, ":%d:%d", colors->null_grn, colors->null_blu);
139 fprintf(fd, "\n");
140 }
141 if (colors->undef_set) {
142 fprintf(fd, "*:%d", colors->undef_red);
143 if (colors->undef_red != colors->undef_grn ||
144 colors->undef_red != colors->undef_blu)
145 fprintf(fd, ":%d:%d", colors->undef_grn, colors->undef_blu);
146 fprintf(fd, "\n");
147 }
148 if (colors->modular.rules) {
149 fprintf(fd, "%s\n", "%%");
150 write_rules(fd, colors->modular.rules, colors->cmin, colors->cmax);
151 fprintf(fd, "%s\n", "%%");
152 }
153 if (colors->fixed.rules)
154 write_rules(fd, colors->fixed.rules, colors->cmin, colors->cmax);
155}
156
157/* overall min and max data values in color table */
158static void write_rules(FILE *fd, struct _Color_Rule_ *crules, DCELL dmin,
159 DCELL dmax)
160{
161 struct _Color_Rule_ *rule;
162 char str[FORMAT_STR_SZ];
163
164 /* find the end of the rules list */
165 rule = crules;
166 while (rule->next)
167 rule = rule->next;
168
169 /* write out the rules in reverse order */
170 for (; rule; rule = rule->prev) {
171 if (rule->low.value == dmin)
172 format_min(str, (double)rule->low.value);
173 else {
174 snprintf(str, FORMAT_STR_SZ, "%.17g", (double)rule->low.value);
175 G_trim_decimal(str);
176 }
177 fprintf(fd, "%s:%d", str, (int)rule->low.red);
178 if (rule->low.red != rule->low.grn || rule->low.red != rule->low.blu)
179 fprintf(fd, ":%d:%d", rule->low.grn, rule->low.blu);
180 /* even if low==high, write second end when the high is dmax */
181 if (rule->high.value == dmax || rule->low.value != rule->high.value) {
182 if (rule->high.value == dmax)
183 format_max(str, (double)rule->high.value);
184 else {
185 snprintf(str, FORMAT_STR_SZ, "%.17g", (double)rule->high.value);
186 G_trim_decimal(str);
187 }
188 fprintf(fd, " %s:%d", str, (int)rule->high.red);
189 if (rule->high.red != rule->high.grn ||
190 rule->high.red != rule->high.blu)
191 fprintf(fd, ":%d:%d", rule->high.grn, rule->high.blu);
192 }
193 fprintf(fd, "\n");
194 }
195}
196
197static void write_old_colors(FILE *fd, struct Colors *colors)
198{
199 int i, n;
200
201 fprintf(fd, "#%ld first color\n", (long)colors->fixed.min);
202 if (colors->null_set) {
203 fprintf(fd, "%d %d %d\n", (int)colors->null_red, (int)colors->null_grn,
204 (int)colors->null_blu);
205 }
206 else
207 fprintf(fd, "255 255 255\n"); /* white */
208
209 n = colors->fixed.max - colors->fixed.min + 1;
210
211 for (i = 0; i < n; i++) {
212 fprintf(fd, "%d", (int)colors->fixed.lookup.red[i]);
213 if (colors->fixed.lookup.red[i] != colors->fixed.lookup.grn[i] ||
214 colors->fixed.lookup.red[i] != colors->fixed.lookup.blu[i])
215 fprintf(fd, " %d %d", (int)colors->fixed.lookup.grn[i],
216 (int)colors->fixed.lookup.blu[i]);
217 fprintf(fd, "\n");
218 }
219}
220
221static void forced_write_old_colors(FILE *fd, struct Colors *colors)
222{
223 int red, grn, blu;
224 CELL cat;
225
226 fprintf(fd, "#%ld first color\n", (long)colors->cmin);
227 cat = 0;
228 Rast_get_c_color(&cat, &red, &grn, &blu, colors);
229 fprintf(fd, "%d %d %d\n", red, grn, blu);
230
231 for (cat = colors->cmin; cat <= colors->cmax; cat++) {
232 Rast_get_c_color(&cat, &red, &grn, &blu, colors);
233 fprintf(fd, "%d", red);
234 if (red != grn || red != blu)
235 fprintf(fd, " %d %d", grn, blu);
236 fprintf(fd, "\n");
237 }
238}
239
240static void format_min(char *str, double dval)
241{
242 double dtmp;
243
244 snprintf(str, FORMAT_STR_SZ, "%.17g", dval);
245 /* Note that G_trim_decimal() does not trim e.g. 1.0000000e-20 */
246 G_trim_decimal(str);
247 sscanf(str, "%lf", &dtmp);
248 if (dtmp != dval) { /* if no zeros after decimal point were trimmed */
249 /* lower dval by GRASS_EPSILON fraction */
250 if (dval > 0)
251 snprintf(str, FORMAT_STR_SZ, "%.17g", dval * (1 - GRASS_EPSILON));
252 else
253 snprintf(str, FORMAT_STR_SZ, "%.17g", dval * (1 + GRASS_EPSILON));
254 }
255}
256
257static void format_max(char *str, double dval)
258{
259 double dtmp;
260
261 snprintf(str, FORMAT_STR_SZ, "%.17g", dval);
262 /* Note that G_trim_decimal() does not trim e.g. 1.0000000e-20 */
263 G_trim_decimal(str);
264 sscanf(str, "%lf", &dtmp);
265 if (dtmp != dval) { /* if no zeros after decimal point were trimmed */
266 /* increase dval by by GRASS_EPSILON fraction */
267 if (dval > 0)
268 snprintf(str, FORMAT_STR_SZ, "%.17g", dval * (1 + GRASS_EPSILON));
269 else
270 snprintf(str, FORMAT_STR_SZ, "%.17g", dval * (1 - GRASS_EPSILON));
271 }
272}
int G_name_is_fully_qualified(const char *, char *, char *)
Check if map name is fully qualified (map @ mapset)
Definition nme_in_mps.c:34
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
FILE * G_fopen_new(const char *, const char *)
Open a new database file.
Definition gis/open.c:218
void G_trim_decimal(char *)
Removes trailing zeros from decimal number.
Definition trim_dec.c:22
int G_remove(const char *, const char *)
Remove a database file.
Definition remove.c:41
const char * G_mapset(void)
Get current mapset name.
Definition gis/mapset.c:31
int Rast_get_c_color(const CELL *, int *, int *, int *, struct Colors *)
Gets color from raster map (CELL)
Definition color_get.c:65
#define GRASS_EPSILON
Definition gis.h:175
#define GMAPSET_MAX
Definition gis.h:194
#define GNAME_MAX
Definition gis.h:193
double DCELL
Definition gis.h:632
int CELL
Definition gis.h:631
#define _(str)
Definition glocale.h:10
const char * name
Definition named_colr.c:6
#define strcpy
Definition parson.c:66
void Rast__write_colors(FILE *fd, struct Colors *colors)
Write map layer color table.
void Rast_write_colors(const char *name, const char *mapset, struct Colors *colors)
Write map layer color table.
#define FORMAT_STR_SZ
Definition gis.h:689
int null_set
Definition gis.h:694
unsigned char undef_blu
Definition gis.h:701
DCELL cmax
Definition gis.h:705
unsigned char null_blu
Definition gis.h:697
unsigned char undef_grn
Definition gis.h:700
unsigned char undef_red
Definition gis.h:699
struct _Color_Info_ fixed
Definition gis.h:702
struct _Color_Info_ modular
Definition gis.h:703
int version
Definition gis.h:690
int invert
Definition gis.h:692
int undef_set
Definition gis.h:698
unsigned char null_grn
Definition gis.h:696
DCELL shift
Definition gis.h:691
unsigned char null_red
Definition gis.h:695
DCELL cmin
Definition gis.h:704
struct _Color_Rule_ * prev
Definition gis.h:662
struct _Color_Rule_ * next
Definition gis.h:661
struct _Color_Value_ low high
Definition gis.h:660