eobish

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