| 1 | #include <stdio.h> |
| 2 | |
| 3 | #define MAXCOLORS 256 |
| 4 | #define COLS_PER_LINE 7 |
| 5 | #define NUMS_PER_LINE 16 |
| 6 | |
| 7 | extern unsigned char *ReadGifBitmap(); |
| 8 | |
| 9 | struct ebmhdr { |
| 10 | char magic[12]; |
| 11 | unsigned int width, height; |
| 12 | int num_colors; |
| 13 | }; |
| 14 | struct rgb_color { |
| 15 | unsigned int red, green, blue; |
| 16 | int pix_len; |
| 17 | }; |
| 18 | |
| 19 | |
| 20 | |
| 21 | /* |
| 22 | * dscan is a quick replacement for: |
| 23 | * |
| 24 | * fscanf (fp, "%d", &ip); |
| 25 | */ |
| 26 | dscan(fp, ip) |
| 27 | FILE *fp; |
| 28 | int *ip; |
| 29 | { |
| 30 | |
| 31 | register int v = 0; |
| 32 | register int n = 0; |
| 33 | int done = 0; |
| 34 | static int nerrors; |
| 35 | |
| 36 | while (!done) { |
| 37 | register int i; |
| 38 | i = getc(fp); |
| 39 | if (i < 0) { |
| 40 | *ip = v; |
| 41 | fprintf(stderr, "dscanf: EOF"); |
| 42 | if (nerrors++ > 2) |
| 43 | return (-1); |
| 44 | else if (nerrors++ > 4) |
| 45 | exit(-1); |
| 46 | return (n); |
| 47 | } |
| 48 | i &= 0xFF; |
| 49 | switch (i) { |
| 50 | case '0': |
| 51 | case '1': |
| 52 | case '2': |
| 53 | case '3': |
| 54 | case '4': |
| 55 | case '5': |
| 56 | case '6': |
| 57 | case '7': |
| 58 | case '8': |
| 59 | case '9': |
| 60 | v = i - '0' + (v * 10); |
| 61 | n++; |
| 62 | break; |
| 63 | case '\n': |
| 64 | case '\r': |
| 65 | case ' ': |
| 66 | case '\t': |
| 67 | if (n) { |
| 68 | *ip = v; |
| 69 | done = 1; |
| 70 | } |
| 71 | break; |
| 72 | default: |
| 73 | fprintf(stderr, "dscanf: non numeric character (0x%x) '%c'\n", i, i); |
| 74 | if (nerrors++ > 4) |
| 75 | exit(-1); |
| 76 | return (-1); |
| 77 | |
| 78 | } |
| 79 | } |
| 80 | return (n); |
| 81 | } |
| 82 | |
| 83 | |
| 84 | |
| 85 | unsigned char * |
| 86 | ReadEbmBitmap(fp, w, h, colrs) |
| 87 | FILE *fp; |
| 88 | int *w, *h; |
| 89 | struct rgb_color *colrs; |
| 90 | { |
| 91 | int i, temp, scale; |
| 92 | unsigned int bmap_size; |
| 93 | int *ptr[3]; |
| 94 | int red, green, blue; |
| 95 | char line[1024]; |
| 96 | unsigned char *bit_data; |
| 97 | unsigned char *bitp; |
| 98 | |
| 99 | bit_data = NULL; |
| 100 | *w = 0; |
| 101 | *h = 0; |
| 102 | |
| 103 | if ((fscanf(fp, "%12s %d %d %d\n", line, w, h, &scale) == 4) && |
| 104 | (strcmp(line, "xstitch_data") == 0)) { |
| 105 | for (i = 0; i < 3; i++) { |
| 106 | fscanf(fp, "%s", line); |
| 107 | if (strcmp(line, "red") == 0) { |
| 108 | ptr[i] = &red; |
| 109 | } else if (strcmp(line, "green") == 0) { |
| 110 | ptr[i] = &green; |
| 111 | } else if (strcmp(line, "blue") == 0) { |
| 112 | ptr[i] = &blue; |
| 113 | } else { |
| 114 | fprintf(stderr, "File has improper format\n"); |
| 115 | return ((unsigned char *) NULL); |
| 116 | } |
| 117 | } |
| 118 | fscanf(fp, "[^\n]\n"); |
| 119 | for (i = 0; i < scale; i++) { |
| 120 | line[0] = '\0'; |
| 121 | if (fscanf(fp, "%d %d %d%[^\n]\n", ptr[0], ptr[1], ptr[2], line) < 3) { |
| 122 | fprintf(stderr, "Bad color data #%d\n", i); |
| 123 | } |
| 124 | colrs[i].red = red; |
| 125 | colrs[i].green = green; |
| 126 | colrs[i].blue = blue; |
| 127 | } |
| 128 | |
| 129 | bmap_size = (*w) * (*h); |
| 130 | bit_data = (unsigned char *) malloc(bmap_size); |
| 131 | if (bit_data == NULL) { |
| 132 | fprintf(stderr, "Cannot allocate space for bitmap\n"); |
| 133 | } |
| 134 | bitp = bit_data; |
| 135 | for (i = 0; i < bmap_size; i++) { |
| 136 | if (dscan(fp, &temp) == -1) |
| 137 | break; |
| 138 | if (temp > (scale - 1)) |
| 139 | temp = 0; |
| 140 | *bitp = (unsigned char) temp; |
| 141 | bitp++; |
| 142 | } |
| 143 | } else { |
| 144 | return ((unsigned char *) NULL); |
| 145 | } |
| 146 | return (bit_data); |
| 147 | } |
| 148 | |
| 149 | |
| 150 | |
| 151 | int |
| 152 | swapint(in) |
| 153 | int in; |
| 154 | { |
| 155 | int out; |
| 156 | |
| 157 | out = 0; |
| 158 | out = out | ((in >> 24) & 0xff); |
| 159 | out = out | ((in >> 8) & 0xff00); |
| 160 | out = out | ((in << 8) & 0xff0000); |
| 161 | out = out | ((in << 24) & 0xff000000); |
| 162 | return (out); |
| 163 | } |
| 164 | |
| 165 | |
| 166 | |
| 167 | unsigned char * |
| 168 | ReadCompactEbmBitmap(fp, w, h, colrs) |
| 169 | FILE *fp; |
| 170 | int *w, *h; |
| 171 | struct rgb_color *colrs; |
| 172 | { |
| 173 | int i, scale; |
| 174 | unsigned int bmap_size; |
| 175 | char pix_file[1024]; |
| 176 | unsigned char *bit_data; |
| 177 | unsigned char *bitp; |
| 178 | struct ebmhdr Hdr; |
| 179 | struct rgb_color color_data; |
| 180 | int doswap; |
| 181 | |
| 182 | doswap = 0; |
| 183 | bit_data = NULL; |
| 184 | *w = 0; |
| 185 | *h = 0; |
| 186 | |
| 187 | fread(&Hdr, sizeof(struct ebmhdr), 1, fp); |
| 188 | if (strcmp(Hdr.magic, "xstitch") == 0) { |
| 189 | /* |
| 190 | * a horrible hack to deal with different byte ordering on |
| 191 | * different machines. Is based on assumption of only 2 |
| 192 | * possible byte orderings, and never more than 256 colors. |
| 193 | */ |
| 194 | if (Hdr.num_colors > 256) { |
| 195 | doswap = 1; |
| 196 | Hdr.width = swapint(Hdr.width); |
| 197 | Hdr.height = swapint(Hdr.height); |
| 198 | Hdr.num_colors = swapint(Hdr.num_colors); |
| 199 | } |
| 200 | *w = Hdr.width; |
| 201 | *h = Hdr.height; |
| 202 | scale = Hdr.num_colors; |
| 203 | for (i = 0; i < Hdr.num_colors; i++) { |
| 204 | fread(&colrs[i], sizeof(struct rgb_color), 1, fp); |
| 205 | if (doswap) { |
| 206 | colrs[i].red = swapint(colrs[i].red); |
| 207 | colrs[i].green = swapint(colrs[i].green); |
| 208 | colrs[i].blue = swapint(colrs[i].blue); |
| 209 | colrs[i].pix_len = swapint(colrs[i].pix_len); |
| 210 | } |
| 211 | if (colrs[i].pix_len != 0) { |
| 212 | if (colrs[i].pix_len > 1023) { |
| 213 | fprintf(stderr, "bad pattern\n"); |
| 214 | return ((unsigned char *) NULL); |
| 215 | } |
| 216 | fread(pix_file, sizeof(char), colrs[i].pix_len, fp); |
| 217 | } |
| 218 | } |
| 219 | |
| 220 | bmap_size = (*w) * (*h); |
| 221 | bit_data = (unsigned char *) malloc(bmap_size); |
| 222 | if (bit_data == NULL) { |
| 223 | fprintf(stderr, "Cannot allocate space for bitmap\n"); |
| 224 | } |
| 225 | fread(bit_data, sizeof(unsigned char), ((*w) * (*h)), fp); |
| 226 | |
| 227 | bitp = bit_data; |
| 228 | for (i = 0; i < bmap_size; i++) { |
| 229 | if ((int) *bitp > (scale - 1)) |
| 230 | *bitp = (unsigned char) 0; |
| 231 | bitp++; |
| 232 | } |
| 233 | } else { |
| 234 | return ((unsigned char *) NULL); |
| 235 | } |
| 236 | return (bit_data); |
| 237 | } |
| 238 | |
| 239 | |
| 240 | struct rgb_color |
| 241 | * |
| 242 | MapColors(data1, colrs1, data2, colrs2, width, height, Cnt) |
| 243 | unsigned char *data1; |
| 244 | struct rgb_color *colrs1; |
| 245 | unsigned char *data2; |
| 246 | struct rgb_color *colrs2; |
| 247 | int width, height; |
| 248 | int *Cnt; |
| 249 | { |
| 250 | int i, j; |
| 251 | int fcnt, indx; |
| 252 | int Mapping[MAXCOLORS]; |
| 253 | unsigned char *ptr; |
| 254 | struct rgb_color *fcolrs; |
| 255 | |
| 256 | fcolrs = (struct rgb_color *) malloc((MAXCOLORS + 1) * sizeof(struct rgb_color)); |
| 257 | |
| 258 | fcnt = 0; |
| 259 | ptr = data1; |
| 260 | for (i = 0; i < (width * height); i++) { |
| 261 | indx = (int) *ptr; |
| 262 | for (j = 0; j < fcnt; j++) { |
| 263 | if ((fcolrs[j].red == colrs1[indx].red) && |
| 264 | (fcolrs[j].green == colrs1[indx].green) && |
| 265 | (fcolrs[j].blue == colrs1[indx].blue)) { |
| 266 | break; |
| 267 | } |
| 268 | } |
| 269 | if (j == fcnt) { |
| 270 | fcolrs[j].red = colrs1[indx].red; |
| 271 | fcolrs[j].green = colrs1[indx].green; |
| 272 | fcolrs[j].blue = colrs1[indx].blue; |
| 273 | Mapping[indx] = j; |
| 274 | fcnt++; |
| 275 | if (fcnt > MAXCOLORS) { |
| 276 | fprintf(stderr, "Error: cannot use more than %d colors in your fish\n", |
| 277 | MAXCOLORS); |
| 278 | exit(1); |
| 279 | } |
| 280 | } |
| 281 | ptr++; |
| 282 | } |
| 283 | ptr = data1; |
| 284 | for (i = 0; i < (width * height); i++) { |
| 285 | indx = (int) *ptr; |
| 286 | *ptr = (unsigned char) (Mapping[indx]); |
| 287 | ptr++; |
| 288 | } |
| 289 | |
| 290 | ptr = data2; |
| 291 | for (i = 0; i < (width * height); i++) { |
| 292 | indx = (int) *ptr; |
| 293 | for (j = 0; j < fcnt; j++) { |
| 294 | if ((fcolrs[j].red == colrs2[indx].red) && |
| 295 | (fcolrs[j].green == colrs2[indx].green) && |
| 296 | (fcolrs[j].blue == colrs2[indx].blue)) { |
| 297 | break; |
| 298 | } |
| 299 | } |
| 300 | if (j == fcnt) { |
| 301 | fcolrs[j].red = colrs2[indx].red; |
| 302 | fcolrs[j].green = colrs2[indx].green; |
| 303 | fcolrs[j].blue = colrs2[indx].blue; |
| 304 | Mapping[indx] = j; |
| 305 | fcnt++; |
| 306 | if (fcnt > MAXCOLORS) { |
| 307 | fprintf(stderr, "Error: cannot use more than %d colors in your fish\n", |
| 308 | MAXCOLORS); |
| 309 | exit(1); |
| 310 | } |
| 311 | } |
| 312 | ptr++; |
| 313 | } |
| 314 | ptr = data2; |
| 315 | for (i = 0; i < (width * height); i++) { |
| 316 | indx = (int) *ptr; |
| 317 | *ptr = (unsigned char) (Mapping[indx]); |
| 318 | ptr++; |
| 319 | } |
| 320 | |
| 321 | for (i = 0; i < fcnt; i++) { |
| 322 | fcolrs[i].red = fcolrs[i].red * 256; |
| 323 | fcolrs[i].green = fcolrs[i].green * 256; |
| 324 | fcolrs[i].blue = fcolrs[i].blue * 256; |
| 325 | } |
| 326 | for (i = fcnt; i < 16; i++) { |
| 327 | fcolrs[i].red = 0; |
| 328 | fcolrs[i].green = 0; |
| 329 | fcolrs[i].blue = 0; |
| 330 | } |
| 331 | |
| 332 | if (fcnt < 16) { |
| 333 | fcnt = 16; |
| 334 | } |
| 335 | *Cnt = fcnt; |
| 336 | return (fcolrs); |
| 337 | } |
| 338 | |
| 339 | |
| 340 | |
| 341 | main(argc, argv) |
| 342 | int argc; |
| 343 | char *argv[]; |
| 344 | { |
| 345 | FILE *ifd; |
| 346 | FILE *ofd; |
| 347 | int i, cnt, fcnt; |
| 348 | struct rgb_color colrs1[MAXCOLORS]; |
| 349 | struct rgb_color colrs2[MAXCOLORS]; |
| 350 | struct rgb_color *fcolrs; |
| 351 | unsigned char *data1, *data2; |
| 352 | int width1, height1, width2, height2; |
| 353 | char outfile[256]; |
| 354 | char *outname; |
| 355 | int num_cnt; |
| 356 | |
| 357 | if (argc < 3) { |
| 358 | fprintf(stderr, "Usage: %s <fish1> <fish2> [<outprefix>]\n", argv[0]); |
| 359 | exit(1); |
| 360 | } |
| 361 | |
| 362 | ifd = fopen(argv[1], "r"); |
| 363 | if (ifd == NULL) { |
| 364 | fprintf(stderr, "Error: cannot open (%s) for read\n", argv[1]); |
| 365 | exit(1); |
| 366 | } |
| 367 | |
| 368 | data1 = ReadCompactEbmBitmap(ifd, &width1, &height1, colrs1); |
| 369 | if (data1 == NULL) { |
| 370 | rewind(ifd); |
| 371 | data1 = ReadEbmBitmap(ifd, &width1, &height1, colrs1); |
| 372 | } |
| 373 | if (data1 == NULL) { |
| 374 | rewind(ifd); |
| 375 | data1 = ReadGifBitmap(ifd, &width1, &height1, colrs1); |
| 376 | } |
| 377 | fclose(ifd); |
| 378 | |
| 379 | if (data1 == NULL) { |
| 380 | fprintf(stderr, "Error: (%s) has unknown format\n", argv[1]); |
| 381 | exit(1); |
| 382 | } |
| 383 | |
| 384 | ifd = fopen(argv[2], "r"); |
| 385 | if (ifd == NULL) { |
| 386 | fprintf(stderr, "Error: cannot open (%s) for read\n", argv[2]); |
| 387 | exit(1); |
| 388 | } |
| 389 | |
| 390 | data2 = ReadCompactEbmBitmap(ifd, &width2, &height2, colrs2); |
| 391 | if (data2 == NULL) { |
| 392 | rewind(ifd); |
| 393 | data2 = ReadEbmBitmap(ifd, &width2, &height2, colrs2); |
| 394 | } |
| 395 | if (data2 == NULL) { |
| 396 | rewind(ifd); |
| 397 | data2 = ReadGifBitmap(ifd, &width2, &height2, colrs2); |
| 398 | } |
| 399 | fclose(ifd); |
| 400 | |
| 401 | if (data2 == NULL) { |
| 402 | fprintf(stderr, "Error: (%s) has unknown format\n", argv[2]); |
| 403 | exit(1); |
| 404 | } |
| 405 | |
| 406 | |
| 407 | if ((width1 != width2) || (height1 != height2)) { |
| 408 | fprintf(stderr, "Error: fish must have same dimensions\n"); |
| 409 | exit(1); |
| 410 | } |
| 411 | |
| 412 | fcolrs = MapColors(data1, colrs1, data2, colrs2, width1, height1, &fcnt); |
| 413 | |
| 414 | if (data1[0] != data2[0]) { |
| 415 | fprintf(stderr, "Error: fish must have same backgrounds\n"); |
| 416 | exit(1); |
| 417 | } |
| 418 | |
| 419 | if (argc >= 4) { |
| 420 | outname = argv[3]; |
| 421 | } else { |
| 422 | cnt = 0; |
| 423 | while ((argv[1][cnt] == argv[2][cnt]) && (argv[1][cnt] != '.') && (argv[2][cnt] != '.')) { |
| 424 | cnt++; |
| 425 | } |
| 426 | if (cnt == 0) { |
| 427 | fprintf(stderr, "Error: files need common prefix\n"); |
| 428 | exit(1); |
| 429 | } |
| 430 | outname = (char *) malloc(cnt + 1); |
| 431 | strncpy(outname, argv[1], cnt); |
| 432 | outname[cnt] = '\0'; |
| 433 | } |
| 434 | sprintf(outfile, "%s.h", outname); |
| 435 | |
| 436 | ofd = fopen(outfile, "w"); |
| 437 | if (ofd == NULL) { |
| 438 | fprintf(stderr, "Error: cannot open (%s) for writing\n", outfile); |
| 439 | exit(1); |
| 440 | } |
| 441 | |
| 442 | fprintf(ofd, "#define %s_width\t\t%d\n", outname, width1); |
| 443 | fprintf(ofd, "#define %s_height\t\t%d\n", outname, height1); |
| 444 | fprintf(ofd, "#define %s_colors\t\t%d\n", outname, fcnt); |
| 445 | fprintf(ofd, "#define %s_back\t\t%d\n", outname, (int) data1[0]); |
| 446 | fprintf(ofd, "int\t%s_reds[] = {", outname); |
| 447 | num_cnt = 0; |
| 448 | for (i = 0; i < fcnt; i++) { |
| 449 | if (i == (fcnt - 1)) { |
| 450 | fprintf(ofd, "%d};\n", fcolrs[i].red); |
| 451 | } else { |
| 452 | fprintf(ofd, "%d, ", fcolrs[i].red); |
| 453 | if (++num_cnt >= COLS_PER_LINE) { |
| 454 | fprintf(ofd, "\n"); |
| 455 | num_cnt = 0; |
| 456 | } |
| 457 | } |
| 458 | } |
| 459 | fprintf(ofd, "int\t%s_greens[] = {", outname); |
| 460 | num_cnt = 0; |
| 461 | for (i = 0; i < fcnt; i++) { |
| 462 | if (i == (fcnt - 1)) { |
| 463 | fprintf(ofd, "%d};\n", fcolrs[i].green); |
| 464 | } else { |
| 465 | fprintf(ofd, "%d, ", fcolrs[i].green); |
| 466 | if (++num_cnt >= COLS_PER_LINE) { |
| 467 | fprintf(ofd, "\n"); |
| 468 | num_cnt = 0; |
| 469 | } |
| 470 | } |
| 471 | } |
| 472 | fprintf(ofd, "int\t%s_blues[] = {", outname); |
| 473 | num_cnt = 0; |
| 474 | for (i = 0; i < fcnt; i++) { |
| 475 | if (i == (fcnt - 1)) { |
| 476 | fprintf(ofd, "%d};\n", fcolrs[i].blue); |
| 477 | } else { |
| 478 | fprintf(ofd, "%d, ", fcolrs[i].blue); |
| 479 | if (++num_cnt >= COLS_PER_LINE) { |
| 480 | fprintf(ofd, "\n"); |
| 481 | num_cnt = 0; |
| 482 | } |
| 483 | } |
| 484 | } |
| 485 | fprintf(ofd, "unsigned char\t%s_rasterA[] = {\n", outname); |
| 486 | num_cnt = 0; |
| 487 | for (i = 0; i < (width1 * height1); i++) { |
| 488 | fprintf(ofd, "0x%02x,", data1[i]); |
| 489 | if (++num_cnt >= NUMS_PER_LINE) { |
| 490 | fprintf(ofd, "\n"); |
| 491 | num_cnt = 0; |
| 492 | } |
| 493 | } |
| 494 | fprintf(ofd, "};\n"); |
| 495 | fprintf(ofd, "unsigned char\t%s_rasterB[] = {\n", outname); |
| 496 | num_cnt = 0; |
| 497 | for (i = 0; i < (width1 * height1); i++) { |
| 498 | fprintf(ofd, "0x%02x,", data2[i]); |
| 499 | if (++num_cnt >= NUMS_PER_LINE) { |
| 500 | fprintf(ofd, "\n"); |
| 501 | num_cnt = 0; |
| 502 | } |
| 503 | } |
| 504 | fprintf(ofd, "};\n"); |
| 505 | |
| 506 | fclose(ofd); |
| 507 | |
| 508 | exit(0); |
| 509 | } |