eobish

annotate utils/tileproc.c @ 1:bc0996863c79

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 17 Jan 2015 18:40:49 +0200
parents
children 0baf4e98315e
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 }