rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@0
|
3 #include <string.h>
|
nuclear@0
|
4 #include <math.h>
|
nuclear@0
|
5 #include <float.h>
|
nuclear@0
|
6 #include <errno.h>
|
nuclear@0
|
7 #ifndef WIN32
|
nuclear@0
|
8 #include <alloca.h>
|
nuclear@0
|
9 #else
|
nuclear@0
|
10 #include <malloc.h>
|
nuclear@0
|
11 #endif
|
nuclear@0
|
12 #include <imago2.h>
|
nuclear@0
|
13
|
nuclear@0
|
14 struct palentry {
|
nuclear@0
|
15 float r, g, b;
|
nuclear@0
|
16 struct palentry *next;
|
nuclear@0
|
17 };
|
nuclear@0
|
18
|
nuclear@0
|
19 int load_palette(const char *fname);
|
nuclear@0
|
20 int proc_tile(const char *fname);
|
nuclear@0
|
21 float find_nearest(float r, float g, float b);
|
nuclear@0
|
22
|
nuclear@0
|
23 struct palentry *palette;
|
nuclear@0
|
24 int palsize;
|
nuclear@0
|
25
|
nuclear@0
|
26 int main(int argc, char **argv)
|
nuclear@0
|
27 {
|
nuclear@0
|
28 int i;
|
nuclear@0
|
29
|
nuclear@0
|
30 for(i=1; i<argc; i++) {
|
nuclear@0
|
31 if(argv[i][0] == '-') {
|
nuclear@0
|
32 switch(argv[i][1]) {
|
nuclear@0
|
33 case 'p':
|
nuclear@0
|
34 if(load_palette(argv[++i]) == -1) {
|
nuclear@0
|
35 return 1;
|
nuclear@0
|
36 }
|
nuclear@0
|
37 break;
|
nuclear@0
|
38
|
nuclear@0
|
39 default:
|
nuclear@0
|
40 fprintf(stderr, "invalid option: %s\n", argv[i]);
|
nuclear@0
|
41 return 1;
|
nuclear@0
|
42 }
|
nuclear@0
|
43 } else {
|
nuclear@0
|
44 if(proc_tile(argv[i]) == -1) {
|
nuclear@0
|
45 return 1;
|
nuclear@0
|
46 }
|
nuclear@0
|
47 }
|
nuclear@0
|
48 }
|
nuclear@0
|
49 return 0;
|
nuclear@0
|
50 }
|
nuclear@0
|
51
|
nuclear@0
|
52 int load_palette(const char *fname)
|
nuclear@0
|
53 {
|
nuclear@0
|
54 FILE *fp;
|
nuclear@0
|
55 char buf[128];
|
nuclear@0
|
56 struct palentry *newpal;
|
nuclear@0
|
57 struct palentry *head = 0, *tail;
|
nuclear@0
|
58 int nent = 0;
|
nuclear@0
|
59
|
nuclear@0
|
60 if(!(fp = fopen(fname, "r"))) {
|
nuclear@0
|
61 fprintf(stderr, "failed to open palette file: %s: %s\n", fname, strerror(errno));
|
nuclear@0
|
62 return -1;
|
nuclear@0
|
63 }
|
nuclear@0
|
64
|
nuclear@0
|
65 while(fgets(buf, sizeof buf, fp)) {
|
nuclear@0
|
66 struct palentry *pent;
|
nuclear@0
|
67 char *endp, *line = buf;
|
nuclear@0
|
68 int r, g, b;
|
nuclear@0
|
69
|
nuclear@0
|
70 if(!line || !*line) continue;
|
nuclear@0
|
71
|
nuclear@0
|
72 if(*line == '#') { /* hex html-like values */
|
nuclear@0
|
73 unsigned int val = strtol(line + 1, &endp, 16);
|
nuclear@0
|
74 if(endp == line) {
|
nuclear@0
|
75 fprintf(stderr, "unrecognized line \"%s\" in palette file: %s\n", line, fname);
|
nuclear@0
|
76 goto fail;
|
nuclear@0
|
77 }
|
nuclear@0
|
78
|
nuclear@0
|
79 r = (val >> 16) & 0xff;
|
nuclear@0
|
80 g = (val >> 8) & 0xff;
|
nuclear@0
|
81 b = val & 0xff;
|
nuclear@0
|
82 } else {
|
nuclear@0
|
83 fprintf(stderr, "unrecognized line \"%s\" in palette file: %s\n", line, fname);
|
nuclear@0
|
84 goto fail;
|
nuclear@0
|
85 }
|
nuclear@0
|
86
|
nuclear@0
|
87 if(!(pent = malloc(sizeof *pent))) {
|
nuclear@0
|
88 perror("failed to allocate palette entry");
|
nuclear@0
|
89 goto fail;
|
nuclear@0
|
90 }
|
nuclear@0
|
91 pent->r = (float)r / 255.0;
|
nuclear@0
|
92 pent->g = (float)g / 255.0;
|
nuclear@0
|
93 pent->b = (float)b / 255.0;
|
nuclear@0
|
94 pent->next = 0;
|
nuclear@0
|
95
|
nuclear@0
|
96 if(head) {
|
nuclear@0
|
97 tail->next = pent;
|
nuclear@0
|
98 tail = pent;
|
nuclear@0
|
99 } else {
|
nuclear@0
|
100 head = tail = pent;
|
nuclear@0
|
101 }
|
nuclear@0
|
102 nent++;
|
nuclear@0
|
103 }
|
nuclear@0
|
104
|
nuclear@0
|
105 /* flatten */
|
nuclear@0
|
106 if(!(newpal = malloc(nent * sizeof *newpal))) {
|
nuclear@0
|
107 fprintf(stderr, "failed to allocate %d palette entries: %s\n", nent, strerror(errno));
|
nuclear@0
|
108 goto fail;
|
nuclear@0
|
109 }
|
nuclear@0
|
110 palette = newpal;
|
nuclear@0
|
111 palsize = nent;
|
nuclear@0
|
112
|
nuclear@0
|
113 while(head) {
|
nuclear@0
|
114 struct palentry *ent = head;
|
nuclear@0
|
115 head = head->next;
|
nuclear@0
|
116
|
nuclear@0
|
117 *newpal++ = *ent;
|
nuclear@0
|
118 free(ent);
|
nuclear@0
|
119 }
|
nuclear@0
|
120
|
nuclear@0
|
121 printf("loaded palette: %s (%d colors)\n", fname, nent);
|
nuclear@0
|
122
|
nuclear@0
|
123 fclose(fp);
|
nuclear@0
|
124 return 0;
|
nuclear@0
|
125
|
nuclear@0
|
126 fail:
|
nuclear@0
|
127 fclose(fp);
|
nuclear@0
|
128 while(head) {
|
nuclear@0
|
129 void *tmp = head;
|
nuclear@0
|
130 head = head->next;
|
nuclear@0
|
131 free(tmp);
|
nuclear@0
|
132 }
|
nuclear@0
|
133 return -1;
|
nuclear@0
|
134 }
|
nuclear@0
|
135
|
nuclear@0
|
136 int proc_tile(const char *fname)
|
nuclear@0
|
137 {
|
nuclear@0
|
138 int i;
|
nuclear@0
|
139 int xsz, ysz;
|
nuclear@0
|
140 unsigned char *pixels, *pptr;
|
nuclear@0
|
141 char *outfname, *cptr;
|
nuclear@0
|
142 FILE *fp;
|
nuclear@0
|
143 const char *magic = "TILEIMAG";
|
nuclear@0
|
144
|
nuclear@0
|
145 outfname = alloca(strlen(fname) + 4);
|
nuclear@0
|
146 strcpy(outfname, fname);
|
nuclear@0
|
147 if((cptr = strrchr(outfname, '.'))) {
|
nuclear@0
|
148 *cptr = 0;
|
nuclear@0
|
149 }
|
nuclear@0
|
150 strcat(outfname, ".til");
|
nuclear@0
|
151
|
nuclear@0
|
152 printf("processing tile: %s -> %s\n", fname, outfname);
|
nuclear@0
|
153
|
nuclear@0
|
154 if(!(pixels = img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGB24))) {
|
nuclear@0
|
155 fprintf(stderr, "failed to load source tile image: %s\n", fname);
|
nuclear@0
|
156 return -1;
|
nuclear@0
|
157 }
|
nuclear@0
|
158 if(!(fp = fopen(outfname, "wb"))) {
|
nuclear@0
|
159 fprintf(stderr, "failed to open output tile image for writing: %s: %s\n", outfname, strerror(errno));
|
nuclear@0
|
160 img_free_pixels(pixels);
|
nuclear@0
|
161 return -1;
|
nuclear@0
|
162 }
|
nuclear@0
|
163 /* write header */
|
nuclear@0
|
164 fwrite(magic, 1, 8, fp);
|
nuclear@0
|
165 fwrite(&xsz, sizeof xsz, 1, fp);
|
nuclear@0
|
166 fwrite(&ysz, sizeof ysz, 1, fp);
|
nuclear@0
|
167
|
nuclear@0
|
168 pptr = pixels;
|
nuclear@0
|
169 for(i=0; i<xsz * ysz; i++) {
|
nuclear@0
|
170 int idx = find_nearest(pptr[0] / 255.0, pptr[1] / 255.0, pptr[2] / 255.0);
|
nuclear@0
|
171 fputc(idx, fp);
|
nuclear@0
|
172 pptr += 3;
|
nuclear@0
|
173 }
|
nuclear@0
|
174 img_free_pixels(pixels);
|
nuclear@0
|
175 fclose(fp);
|
nuclear@0
|
176 return 0;
|
nuclear@0
|
177 }
|
nuclear@0
|
178
|
nuclear@0
|
179 float find_nearest(float r, float g, float b)
|
nuclear@0
|
180 {
|
nuclear@0
|
181 int i, res;
|
nuclear@0
|
182 float mindist = FLT_MAX;
|
nuclear@0
|
183
|
nuclear@0
|
184 for(i=0; i<palsize; i++) {
|
nuclear@0
|
185 float dr = r - palette[i].r;
|
nuclear@0
|
186 float dg = g - palette[i].g;
|
nuclear@0
|
187 float db = b - palette[i].b;
|
nuclear@0
|
188 float dist = dr * dr + dg * dg + db * db;
|
nuclear@0
|
189
|
nuclear@0
|
190 if(dist < mindist) {
|
nuclear@0
|
191 mindist = dist;
|
nuclear@0
|
192 res = i;
|
nuclear@0
|
193 }
|
nuclear@0
|
194 }
|
nuclear@0
|
195 return res;
|
nuclear@0
|
196 }
|