eobish

view utils/tileproc.c @ 8:c0e8bbf96849

merged
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 19 Jan 2015 15:49:36 +0200
parents 465ca72c9657
children
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <math.h>
6 #include <float.h>
7 #include <errno.h>
8 #ifndef WIN32
9 #include <alloca.h>
10 #else
11 #include <malloc.h>
12 #endif
13 #include <imago2.h>
15 struct palentry {
16 float r, g, b;
17 struct palentry *next;
18 };
20 void print_usage(const char *argv0);
21 int load_palette(const char *fname);
22 int save_palette(const char *fname);
23 int proc_tile(const char *fname);
24 float find_nearest(float r, float g, float b);
26 struct palentry *palette;
27 int palsize;
28 float colscale[10] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
29 int scale_count = 0;
30 int key = -1;
32 int main(int argc, char **argv)
33 {
34 int i;
35 const char *outpalname = 0;
37 for(i=1; i<argc; i++) {
38 if(argv[i][0] == '-') {
39 switch(argv[i][1]) {
40 case 'p':
41 if(load_palette(argv[++i]) == -1) {
42 return 1;
43 }
44 break;
46 case 'P':
47 outpalname = argv[++i];
48 break;
50 case 'f':
51 {
52 int idx, maxcol;
53 if(sscanf(argv[++i], "%d=%d", &idx, &maxcol) != 2) {
54 fprintf(stderr, "-f option expects <Z>=<MAX COLOR> pairs\n");
55 return 1;
56 }
57 if(idx < 0 || idx >= 10) {
58 fprintf(stderr, "-f expects a z value from 0 to 9\n");
59 return 1;
60 }
61 colscale[idx] = (float)maxcol / 255.0;
62 if(idx >= scale_count) scale_count = idx + 1;
63 }
64 break;
66 case 'k':
67 {
68 char *endp;
69 long x = strtol(argv[++i], &endp, 10);
70 if(endp == argv[i]) {
71 fprintf(stderr, "-k must be followed by a palette index\n");
72 return 1;
73 }
74 key = x;
75 }
76 break;
78 case 'h':
79 print_usage(argv[0]);
80 return 0;
82 default:
83 fprintf(stderr, "invalid option: %s\n", argv[i]);
84 print_usage(argv[0]);
85 return 1;
86 }
87 } else {
88 if(proc_tile(argv[i]) == -1) {
89 return 1;
90 }
91 }
92 }
94 if(outpalname) {
95 if(save_palette(outpalname) == -1) {
96 fprintf(stderr, "failed to write extended palette: %s\n", outpalname);
97 return 1;
98 }
99 }
101 return 0;
102 }
104 void print_usage(const char *argv0)
105 {
106 printf("Usage: %s <options> [img1 img2 img3 ... imgN]\n", argv0);
107 printf("Options:\n");
108 printf(" -p <file> use palette from file\n");
109 printf(" -f <z>=<b> darken the image (max brightness 'b') based on the digit (z) in its filename\n");
110 printf(" -k <idx> colorkey index (preserve this color regardless of depth cues)\n");
111 printf(" -h print usage and exit\n");
112 }
114 int load_palette(const char *fname)
115 {
116 FILE *fp;
117 char buf[128];
118 struct palentry *newpal;
119 struct palentry *head = 0, *tail;
120 int nent = 0;
122 if(!(fp = fopen(fname, "r"))) {
123 fprintf(stderr, "failed to open palette file: %s: %s\n", fname, strerror(errno));
124 return -1;
125 }
127 while(fgets(buf, sizeof buf, fp)) {
128 struct palentry *pent;
129 char *endp, *line = buf;
130 int r, g, b;
132 if(!line || !*line) continue;
134 if(*line == '#') { /* hex html-like values */
135 unsigned int val = strtol(line + 1, &endp, 16);
136 if(endp == line) {
137 fprintf(stderr, "unrecognized line \"%s\" in palette file: %s\n", line, fname);
138 goto fail;
139 }
141 r = (val >> 16) & 0xff;
142 g = (val >> 8) & 0xff;
143 b = val & 0xff;
144 } else {
145 fprintf(stderr, "unrecognized line \"%s\" in palette file: %s\n", line, fname);
146 goto fail;
147 }
149 if(!(pent = malloc(sizeof *pent))) {
150 perror("failed to allocate palette entry");
151 goto fail;
152 }
153 pent->r = (float)r / 255.0;
154 pent->g = (float)g / 255.0;
155 pent->b = (float)b / 255.0;
156 pent->next = 0;
158 if(head) {
159 tail->next = pent;
160 tail = pent;
161 } else {
162 head = tail = pent;
163 }
164 nent++;
165 }
167 /* flatten */
168 if(!(newpal = malloc(nent * sizeof *newpal))) {
169 fprintf(stderr, "failed to allocate %d palette entries: %s\n", nent, strerror(errno));
170 goto fail;
171 }
172 palette = newpal;
173 palsize = nent;
175 while(head) {
176 struct palentry *ent = head;
177 head = head->next;
179 *newpal++ = *ent;
180 free(ent);
181 }
183 printf("loaded palette: %s (%d colors)\n", fname, nent);
185 fclose(fp);
186 return 0;
188 fail:
189 fclose(fp);
190 while(head) {
191 void *tmp = head;
192 head = head->next;
193 free(tmp);
194 }
195 return -1;
196 }
198 int save_palette(const char *fname)
199 {
200 FILE *fp;
201 int i, j;
202 int extsize = palsize * scale_count;
204 printf("saving extended palette: %s\n", fname);
206 if(!(fp = fopen(fname, "w"))) {
207 fprintf(stderr, "failed to save extended palette: %s: %s\n", fname, strerror(errno));
208 return -1;
209 }
211 if(extsize > 256) {
212 fprintf(stderr, "warning: extended palette size too large (%d)\n", extsize);
213 }
215 for(i=0; i<scale_count; i++) {
216 for(j=0; j<palsize; j++) {
217 int r = (int)(palette[j].r * colscale[i] * 255.0);
218 int g = (int)(palette[j].g * colscale[i] * 255.0);
219 int b = (int)(palette[j].b * colscale[i] * 255.0);
221 if(r > 255) r = 255;
222 if(g > 255) g = 255;
223 if(b > 255) b = 255;
225 fprintf(fp, "#%02x%02x%02x\n", r, g, b);
226 }
227 }
228 fclose(fp);
229 return 0;
230 }
232 int proc_tile(const char *fname)
233 {
234 int i;
235 int xsz, ysz;
236 unsigned char *pixels, *pptr;
237 char *outfname, *cptr;
238 FILE *fp;
239 const char *magic = "TILEIMAG";
240 int zidx = -1;
242 outfname = alloca(strlen(fname) + 4);
243 strcpy(outfname, fname);
244 if((cptr = strrchr(outfname, '.'))) {
245 *cptr = 0;
246 }
247 strcat(outfname, ".til");
249 cptr = outfname + strlen(outfname) - 1;
250 while(cptr >= outfname && !isdigit(*cptr)) --cptr;
251 if(cptr >= outfname) {
252 zidx = *cptr - '0';
253 }
255 printf("processing tile: %s -> %s\n", fname, outfname);
257 if(!(pixels = img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGB24))) {
258 fprintf(stderr, "failed to load source tile image: %s\n", fname);
259 return -1;
260 }
261 if(!(fp = fopen(outfname, "wb"))) {
262 fprintf(stderr, "failed to open output tile image for writing: %s: %s\n", outfname, strerror(errno));
263 img_free_pixels(pixels);
264 return -1;
265 }
266 /* write header */
267 fwrite(magic, 1, 8, fp);
268 fwrite(&xsz, sizeof xsz, 1, fp);
269 fwrite(&ysz, sizeof ysz, 1, fp);
271 pptr = pixels;
272 for(i=0; i<xsz * ysz; i++) {
273 int idx = find_nearest(pptr[0] / 255.0, pptr[1] / 255.0, pptr[2] / 255.0);
275 if(zidx > 0 && idx != key) {
276 /* shift the indices to the appropriate copy of the palette */
277 idx += zidx * palsize;
278 }
280 fputc(idx, fp);
281 pptr += 3;
282 }
283 img_free_pixels(pixels);
284 fclose(fp);
285 return 0;
286 }
288 float find_nearest(float r, float g, float b)
289 {
290 int i, res;
291 float mindist = FLT_MAX;
293 for(i=0; i<palsize; i++) {
294 float dr = r - palette[i].r;
295 float dg = g - palette[i].g;
296 float db = b - palette[i].b;
297 float dist = dr * dr + dg * dg + db * db;
299 if(dist < mindist) {
300 mindist = dist;
301 res = i;
302 }
303 }
304 return res;
305 }