GDS-Render v1.2.1
color-palette.c
Go to the documentation of this file.
1/*
2 * GDSII-Converter
3 * Copyright (C) 2019 Mario Hüttel <mario.huettel@gmx.net>
4 *
5 * This file is part of GDSII-Converter.
6 *
7 * GDSII-Converter is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * GDSII-Converter is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
18 */
19
27
29 /* Inheritance */
30 GObject parent;
31
32 /* Custom fields */
34 GdkRGBA *color_array;
36 unsigned int color_array_length;
37
38 /* Dummy bytes to ensure ABI compatibility in future versions */
39 gpointer dummy[4];
40};
41
42G_DEFINE_TYPE(ColorPalette, color_palette, G_TYPE_OBJECT)
43
44
55static int count_non_empty_lines_in_array(const char *data, size_t length)
56{
57 unsigned int idx;
58 int non_empty_lines = 0;
59 char last_char = '\n';
60
61 if (!data)
62 return -1;
63
64 /* Count each '\n' as a new line if it is not directly preceded by another '\n' */
65 for (idx = 0; idx < length && data[idx]; idx++) {
66 if (data[idx] == '\n' && last_char != '\n')
67 non_empty_lines++;
68 last_char = data[idx];
69 }
70
71 /* Count the last line in case the data does not end with a '\n' */
72 if (data[idx-1] != '\n')
73 non_empty_lines++;
74
75 return non_empty_lines;
76}
77
84static int color_palette_fill_with_resource(ColorPalette *palette, char *resource_name)
85{
86 GBytes *data;
87 char line[10];
88 int line_idx;
89 unsigned int color_idx;
90 int idx;
91 const char *char_array;
92 gsize byte_count;
93 int lines;
94 GRegex *regex;
95 GMatchInfo *mi;
96 char *match;
97
98 if (!palette || !resource_name)
99 return -1;
100
101 data = g_resources_lookup_data(resource_name, 0, NULL);
102
103 if (!data)
104 return -2;
105
106 char_array = (const char *)g_bytes_get_data(data, &byte_count);
107
108 if (!char_array || !byte_count)
109 goto ret_unref_data;
110
111 /* Get maximum lenght of color palette, assuming all entries are valid */
112 lines = count_non_empty_lines_in_array(char_array, byte_count);
113
114 if (lines <= 0)
115 goto ret_unref_data;
116
117 palette->color_array = (GdkRGBA *)malloc(sizeof(GdkRGBA) * (unsigned int)lines);
118
119 /* Setup regex for hexadecimal RGB colors like 'A0CB3F' */
120 regex = g_regex_new("^(?<red>[0-9A-Fa-f][0-9A-Fa-f])(?<green>[0-9A-Fa-f][0-9A-Fa-f])(?<blue>[0-9A-Fa-f][0-9A-Fa-f])$",
121 0, 0, NULL);
122
123 /* Reset line */
124 line_idx = 0;
125 line[0] = '\0';
126
127 /* Set color index */
128 color_idx = 0;
129
130 /* interate over lines and match */
131 for (idx = 0 ; (unsigned int)idx < byte_count; idx++) {
132 /* Fillup line. */
133 line[line_idx] = char_array[idx];
134
135 /* If end of line/string is reached, process */
136 if (line[line_idx] == '\n' || line[line_idx] == '\0') {
137 line[line_idx] = '\0';
138
139 /* Match the line */
140 g_regex_match(regex, line, 0, &mi);
141 if (g_match_info_matches(mi) && color_idx < (unsigned int)lines) {
142 match = g_match_info_fetch_named(mi, "red");
143 palette->color_array[color_idx].red =
144 (double)g_ascii_strtoll(match, NULL, 16) / 255.0;
145 g_free(match);
146 match = g_match_info_fetch_named(mi, "green");
147 palette->color_array[color_idx].green =
148 (double)g_ascii_strtoll(match, NULL, 16) / 255.0;
149 g_free(match);
150 match = g_match_info_fetch_named(mi, "blue");
151 palette->color_array[color_idx].blue =
152 (double)g_ascii_strtoll(match, NULL, 16) / 255.0;
153 g_free(match);
154
155 /* Only RGB supported so far. Fix alpha channel to 1.0 */
156 palette->color_array[color_idx].alpha = 1.0;
157
158 color_idx++;
159 }
160
161 g_match_info_free(mi);
162
163 /* End of string */
164 if (char_array[idx] == '\0')
165 break;
166
167 line_idx = 0;
168 continue;
169 }
170
171 /* increment line index. If end is reached write all bytes to the line end.
172 * Line is longer than required for parsing. This ensures, that everything works as expected
173 */
174 line_idx += ((unsigned int)line_idx < sizeof(line)-1 ? 1 : 0);
175 }
176
177 /* Data read; Shrink array in case of invalid lines */
178 palette->color_array = realloc(palette->color_array, (size_t)color_idx * sizeof(GdkRGBA));
179 palette->color_array_length = color_idx;
180
181 g_regex_unref(regex);
182ret_unref_data:
183 g_bytes_unref(data);
184
185 return 0;
186}
187
188ColorPalette *color_palette_new_from_resource(char *resource_name)
189{
190 ColorPalette *palette;
191
192 palette = GDS_RENDER_COLOR_PALETTE(g_object_new(TYPE_GDS_RENDER_COLOR_PALETTE, NULL));
193 if (palette)
194 (void)color_palette_fill_with_resource(palette, resource_name);
195
196 return palette;
197}
198
199GdkRGBA *color_palette_get_color(ColorPalette *palette, GdkRGBA *color, unsigned int index)
200{
201 GdkRGBA *c = NULL;
202
203 if (!palette)
204 goto ret_c;
205
206 if (index >= palette->color_array_length)
207 goto ret_c;
208
209 if (color)
210 c = color;
211 else
212 c = (GdkRGBA *)malloc(sizeof(GdkRGBA));
213
214 /* Copy color */
215 c->red = palette->color_array[index].red;
216 c->green = palette->color_array[index].green;
217 c->blue = palette->color_array[index].blue;
218 c->alpha = palette->color_array[index].alpha;
219ret_c:
220 return c;
221}
222
223unsigned int color_palette_get_color_count(ColorPalette *palette)
224{
225 unsigned int return_val = 0;
226
227 if (palette)
228 return_val = palette->color_array_length;
229
230 return return_val;
231}
232
233static void color_palette_dispose(GObject *gobj)
234{
235 ColorPalette *palette;
236
237 palette = GDS_RENDER_COLOR_PALETTE(gobj);
238 if (palette->color_array) {
239 palette->color_array_length = 0;
240 free(palette->color_array);
241 palette->color_array = NULL;
242 }
243
244 /* Chain up to parent class */
245 G_OBJECT_CLASS(color_palette_parent_class)->dispose(gobj);
246}
247
248static void color_palette_class_init(ColorPaletteClass *klass)
249{
250 GObjectClass *gclass;
251
252 gclass = G_OBJECT_CLASS(klass);
253 gclass->dispose = color_palette_dispose;
254}
255
256static void color_palette_init(ColorPalette *self)
257{
258 self->color_array = NULL;
259 self->color_array_length = 0;
260}
unsigned int color_palette_get_color_count(ColorPalette *palette)
Return amount of stored colors in palette.
ColorPalette * color_palette_new_from_resource(char *resource_name)
Create a new object with from a resource containing the html hex color scheme.
static int count_non_empty_lines_in_array(const char *data, size_t length)
Return the number of non empty lines in array.
Definition: color-palette.c:55
static void color_palette_dispose(GObject *gobj)
static int color_palette_fill_with_resource(ColorPalette *palette, char *resource_name)
color_palette_fill_with_resource
Definition: color-palette.c:84
GdkRGBA * color_palette_get_color(ColorPalette *palette, GdkRGBA *color, unsigned int index)
Get the n-th color in the palette identified by the index.
static void color_palette_init(ColorPalette *self)
static void color_palette_class_init(ColorPaletteClass *klass)
Class representing a color palette.
#define TYPE_GDS_RENDER_COLOR_PALETTE
Definition: color-palette.h:36
GdkRGBA * color_array
The internal array to store the colors.
Definition: color-palette.c:34
GObject parent
Definition: color-palette.c:30
unsigned int color_array_length
The length of the _ColorPalette::color_array array.
Definition: color-palette.c:36
gpointer dummy[4]
Definition: color-palette.c:39