00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <stdlib.h>
00011 #include <errno.h>
00012 #include <string.h>
00013 #include <math.h>
00014
00015 #include "greymap.h"
00016
00017 #define INTBITS (8*sizeof(int))
00018
00019 #define mod(a,n) ((a)>=(n) ? (a)%(n) : (a)>=0 ? (a) : (n)-1-(-1-(a))%(n))
00020
00021 static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic);
00022 static int gm_readbody_bmp(FILE *f, greymap_t **gmp);
00023
00024
00025
00026
00027
00028
00029 greymap_t *gm_new(int w, int h) {
00030 greymap_t *gm;
00031 int errno_save;
00032
00033 gm = (greymap_t *) malloc(sizeof(greymap_t));
00034 if (!gm) {
00035 return NULL;
00036 }
00037 gm->w = w;
00038 gm->h = h;
00039 gm->map = (signed short int *) malloc(w*h*sizeof(signed short int));
00040 if (!gm->map) {
00041 errno_save = errno;
00042 free(gm);
00043 errno = errno_save;
00044 return NULL;
00045 }
00046 return gm;
00047 }
00048
00049
00050 void gm_free(greymap_t *gm) {
00051 if (gm) {
00052 free(gm->map);
00053 }
00054 free(gm);
00055 }
00056
00057
00058 greymap_t *gm_dup(greymap_t *gm) {
00059 greymap_t *gm1 = gm_new(gm->w, gm->h);
00060 if (!gm1) {
00061 return NULL;
00062 }
00063 memcpy(gm1->map, gm->map, gm->w*gm->h*2);
00064 return gm1;
00065 }
00066
00067
00068 void gm_clear(greymap_t *gm, int b) {
00069 int i;
00070
00071 if (b==0) {
00072 memset(gm->map, 0, gm->w*gm->h*2);
00073 } else {
00074 for (i=0; i<gm->w*gm->h; i++) {
00075 gm->map[i] = b;
00076 }
00077 }
00078 }
00079
00080
00081
00082
00083
00084
00085 static int fgetc_ws(FILE *f) {
00086 int c;
00087
00088 while (1) {
00089 c = fgetc(f);
00090 if (c=='#') {
00091 while (1) {
00092 c = fgetc(f);
00093 if (c=='\n' || c==EOF) {
00094 break;
00095 }
00096 }
00097 }
00098
00099 if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=12) {
00100 return c;
00101 }
00102 }
00103 }
00104
00105
00106
00107
00108
00109
00110 static int readnum(FILE *f) {
00111 int c;
00112 int acc;
00113
00114
00115 while (1) {
00116 c = fgetc_ws(f);
00117 if (c==EOF) {
00118 return -1;
00119 }
00120 if (c>='0' && c<='9') {
00121 break;
00122 }
00123 }
00124
00125
00126 acc = c-'0';
00127 while (1) {
00128 c = fgetc(f);
00129 if (c==EOF) {
00130 break;
00131 }
00132 if (c<'0' || c>'9') {
00133 ungetc(c, f);
00134 break;
00135 }
00136 acc *= 10;
00137 acc += c-'0';
00138 }
00139 return acc;
00140 }
00141
00142
00143
00144
00145 static int readbit(FILE *f) {
00146 int c;
00147
00148
00149 while (1) {
00150 c = fgetc_ws(f);
00151 if (c==EOF) {
00152 return -1;
00153 }
00154 if (c>='0' && c<='1') {
00155 break;
00156 }
00157 }
00158
00159 return c-'0';
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 char *gm_read_error = NULL;
00173
00174 int gm_read(FILE *f, greymap_t **gmp) {
00175 int magic[2];
00176
00177
00178
00179
00180
00181
00182 magic[0] = fgetc_ws(f);
00183 if (magic[0] == EOF) {
00184
00185 return -3;
00186 }
00187 magic[1] = fgetc(f);
00188 if (magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6') {
00189 return gm_readbody_pnm(f, gmp, magic[1]);
00190 }
00191 if (magic[0] == 'B' && magic[1] == 'M') {
00192 return gm_readbody_bmp(f, gmp);
00193 }
00194 return -4;
00195 }
00196
00197
00198
00199
00200
00201 static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
00202 greymap_t *gm;
00203 int x, y, i, j, b, b1, sum;
00204 int bpr;
00205 int w, h, max;
00206
00207 gm = NULL;
00208
00209 w = readnum(f);
00210 if (w<0) {
00211 goto format_error;
00212 }
00213
00214 h = readnum(f);
00215 if (h<0) {
00216 goto format_error;
00217 }
00218
00219
00220 gm = gm_new(w, h);
00221 if (!gm) {
00222 return -1;
00223 }
00224
00225
00226 gm_clear(gm, 0);
00227
00228 switch (magic) {
00229 default:
00230
00231 goto format_error;
00232
00233 case '1':
00234
00235
00236 for (y=h-1; y>=0; y--) {
00237 for (x=0; x<w; x++) {
00238 b = readbit(f);
00239 if (b<0) {
00240 goto eof;
00241 }
00242 GM_UPUT(gm, x, y, b ? 0 : 255);
00243 }
00244 }
00245 break;
00246
00247 case '2':
00248
00249
00250 max = readnum(f);
00251 if (max<1) {
00252 goto format_error;
00253 }
00254
00255 for (y=h-1; y>=0; y--) {
00256 for (x=0; x<w; x++) {
00257 b = readnum(f);
00258 if (b<0) {
00259 goto eof;
00260 }
00261 GM_UPUT(gm, x, y, b*255/max);
00262 }
00263 }
00264 break;
00265
00266 case '3':
00267
00268
00269 max = readnum(f);
00270 if (max<1) {
00271 goto format_error;
00272 }
00273
00274 for (y=h-1; y>=0; y--) {
00275 for (x=0; x<w; x++) {
00276 sum = 0;
00277 for (i=0; i<3; i++) {
00278 b = readnum(f);
00279 if (b<0) {
00280 goto eof;
00281 }
00282 sum += b;
00283 }
00284 GM_UPUT(gm, x, y, sum*(255/3)/max);
00285 }
00286 }
00287 break;
00288
00289 case '4':
00290
00291
00292 b = fgetc(f);
00293 if (b==EOF) {
00294 goto format_error;
00295 }
00296
00297 bpr = (w+7)/8;
00298
00299 for (y=h-1; y>=0; y--) {
00300 for (i=0; i<bpr; i++) {
00301 b = fgetc(f);
00302 if (b==EOF) {
00303 goto eof;
00304 }
00305 for (j=0; j<8; j++) {
00306 GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? 0 : 255);
00307 }
00308 }
00309 }
00310 break;
00311
00312 case '5':
00313
00314
00315 max = readnum(f);
00316 if (max<1) {
00317 goto format_error;
00318 }
00319
00320 b = fgetc(f);
00321 if (b==EOF) {
00322 goto format_error;
00323 }
00324
00325 for (y=h-1; y>=0; y--) {
00326 for (x=0; x<w; x++) {
00327 b = fgetc(f);
00328 if (b==EOF)
00329 goto eof;
00330 if (max>=256) {
00331 b <<= 8;
00332 b1 = fgetc(f);
00333 if (b1==EOF)
00334 goto eof;
00335 b |= b1;
00336 }
00337 GM_UPUT(gm, x, y, b*255/max);
00338 }
00339 }
00340 break;
00341
00342 case '6':
00343
00344
00345 max = readnum(f);
00346 if (max<1) {
00347 goto format_error;
00348 }
00349
00350 b = fgetc(f);
00351 if (b==EOF) {
00352 goto format_error;
00353 }
00354
00355 for (y=h-1; y>=0; y--) {
00356 for (x=0; x<w; x++) {
00357 sum = 0;
00358 for (i=0; i<3; i++) {
00359 b = fgetc(f);
00360 if (b==EOF) {
00361 goto eof;
00362 }
00363 if (max>=256) {
00364 b <<= 8;
00365 b1 = fgetc(f);
00366 if (b1==EOF)
00367 goto eof;
00368 b |= b1;
00369 }
00370 sum += b;
00371 }
00372 GM_UPUT(gm, x, y, sum*(255/3)/max);
00373 }
00374 }
00375 break;
00376 }
00377
00378 *gmp = gm;
00379 return 0;
00380
00381 eof:
00382 *gmp = gm;
00383 return 1;
00384
00385 format_error:
00386 gm_free(gm);
00387 if (magic == '1' || magic == '4') {
00388 gm_read_error = "invalid pbm file";
00389 } else if (magic == '2' || magic == '5') {
00390 gm_read_error = "invalid pgm file";
00391 } else {
00392 gm_read_error = "invalid ppm file";
00393 }
00394 return -2;
00395 }
00396
00397
00398
00399
00400 struct bmp_info_s {
00401 unsigned int FileSize;
00402 unsigned int reserved;
00403 unsigned int DataOffset;
00404 unsigned int InfoSize;
00405 unsigned int w;
00406 unsigned int h;
00407 unsigned int Planes;
00408 unsigned int bits;
00409 unsigned int comp;
00410 unsigned int ImageSize;
00411 unsigned int XpixelsPerM;
00412 unsigned int YpixelsPerM;
00413 unsigned int ncolors;
00414 unsigned int ColorsImportant;
00415 unsigned int ctbits;
00416 };
00417 typedef struct bmp_info_s bmp_info_t;
00418
00419
00420
00421 static int bmp_count = 0;
00422 static int bmp_pos = 0;
00423
00424
00425
00426 static int bmp_readint(FILE *f, int n, unsigned int *p) {
00427 int i;
00428 unsigned int sum = 0;
00429 int b;
00430
00431 for (i=0; i<n; i++) {
00432 b = fgetc(f);
00433 if (b==EOF) {
00434 return 1;
00435 }
00436 sum += b << (8*i);
00437 }
00438 bmp_count += n;
00439 bmp_pos += n;
00440 *p = sum;
00441 return 0;
00442 }
00443
00444
00445 static void bmp_pad_reset(void) {
00446 bmp_count = 0;
00447 }
00448
00449
00450
00451 static int bmp_pad(FILE *f) {
00452 int c, i, b;
00453
00454 c = (-bmp_count) & 3;
00455 for (i=0; i<c; i++) {
00456 b = fgetc(f);
00457 if (b==EOF) {
00458 return 1;
00459 }
00460 }
00461 bmp_pos += c;
00462 bmp_count = 0;
00463 return 0;
00464 }
00465
00466
00467 static int bmp_forward(FILE *f, int pos) {
00468 int b;
00469
00470 while (bmp_pos < pos) {
00471 b = fgetc(f);
00472 if (b==EOF) {
00473 return 1;
00474 }
00475 bmp_pos++;
00476 bmp_count++;
00477 }
00478 return 0;
00479 }
00480
00481 #define TRY(x) if (x) goto try_error
00482 #define TRY_EOF(x) if (x) goto eof
00483
00484
00485
00486
00487
00488
00489
00490
00491 static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
00492 bmp_info_t bmpinfo;
00493 int *coltable;
00494 unsigned int b, c;
00495 unsigned int i, j;
00496 greymap_t *gm;
00497 unsigned int x, y;
00498 int col[2];
00499 unsigned int bitbuf;
00500 unsigned int n;
00501
00502 gm_read_error = NULL;
00503 gm = NULL;
00504 coltable = NULL;
00505
00506 bmp_pos = 2;
00507
00508
00509 TRY(bmp_readint(f, 4, &bmpinfo.FileSize));
00510 TRY(bmp_readint(f, 4, &bmpinfo.reserved));
00511 TRY(bmp_readint(f, 4, &bmpinfo.DataOffset));
00512
00513
00514 TRY(bmp_readint(f, 4, &bmpinfo.InfoSize));
00515 if (bmpinfo.InfoSize == 40 || bmpinfo.InfoSize == 64) {
00516
00517 bmpinfo.ctbits = 32;
00518 TRY(bmp_readint(f, 4, &bmpinfo.w));
00519 TRY(bmp_readint(f, 4, &bmpinfo.h));
00520 TRY(bmp_readint(f, 2, &bmpinfo.Planes));
00521 TRY(bmp_readint(f, 2, &bmpinfo.bits));
00522 TRY(bmp_readint(f, 4, &bmpinfo.comp));
00523 TRY(bmp_readint(f, 4, &bmpinfo.ImageSize));
00524 TRY(bmp_readint(f, 4, &bmpinfo.XpixelsPerM));
00525 TRY(bmp_readint(f, 4, &bmpinfo.YpixelsPerM));
00526 TRY(bmp_readint(f, 4, &bmpinfo.ncolors));
00527 TRY(bmp_readint(f, 4, &bmpinfo.ColorsImportant));
00528 } else if (bmpinfo.InfoSize == 12) {
00529
00530 bmpinfo.ctbits = 24;
00531 TRY(bmp_readint(f, 2, &bmpinfo.w));
00532 TRY(bmp_readint(f, 2, &bmpinfo.h));
00533 TRY(bmp_readint(f, 2, &bmpinfo.Planes));
00534 TRY(bmp_readint(f, 2, &bmpinfo.bits));
00535 bmpinfo.comp = 0;
00536 bmpinfo.ncolors = 0;
00537 } else {
00538 goto format_error;
00539 }
00540
00541
00542 TRY(bmp_forward(f, 14+bmpinfo.InfoSize));
00543
00544 if (bmpinfo.Planes != 1) {
00545 gm_read_error = "cannot handle bmp planes";
00546 goto format_error;
00547 }
00548
00549 if (bmpinfo.ncolors == 0) {
00550 bmpinfo.ncolors = 1 << bmpinfo.bits;
00551 }
00552
00553
00554 if (bmpinfo.bits <= 8) {
00555 coltable = (int *) malloc(bmpinfo.ncolors * sizeof(int));
00556 if (!coltable) {
00557 goto std_error;
00558 }
00559
00560
00561 for (i=0; i<bmpinfo.ncolors; i++) {
00562 TRY(bmp_readint(f, bmpinfo.ctbits/8, &c));
00563 c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
00564 coltable[i] = c/3;
00565 }
00566 }
00567
00568
00569 if (bmpinfo.InfoSize != 12) {
00570 TRY(bmp_forward(f, bmpinfo.DataOffset));
00571 }
00572
00573
00574 gm = gm_new(bmpinfo.w, bmpinfo.h);
00575 if (!gm) {
00576 goto std_error;
00577 }
00578
00579
00580 gm_clear(gm, 0);
00581
00582 switch (bmpinfo.bits + 0x100*bmpinfo.comp) {
00583
00584 default:
00585 goto format_error;
00586 break;
00587
00588 case 0x001:
00589
00590
00591 for (y=0; y<bmpinfo.h; y++) {
00592 bmp_pad_reset();
00593 for (i=0; 8*i<bmpinfo.w; i++) {
00594 TRY_EOF(bmp_readint(f, 1, &b));
00595 for (j=0; j<8; j++) {
00596 GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? coltable[1] : coltable[0]);
00597 }
00598 }
00599 TRY(bmp_pad(f));
00600 }
00601 break;
00602
00603 case 0x002:
00604 case 0x003:
00605 case 0x004:
00606 case 0x005:
00607 case 0x006:
00608 case 0x007:
00609 case 0x008:
00610 for (y=0; y<bmpinfo.h; y++) {
00611 bmp_pad_reset();
00612 bitbuf = 0;
00613 n = 0;
00614 for (x=0; x<bmpinfo.w; x++) {
00615 if (n < bmpinfo.bits) {
00616 TRY_EOF(bmp_readint(f, 1, &b));
00617 bitbuf |= b << (INTBITS - 8 - n);
00618 n += 8;
00619 }
00620 b = bitbuf >> (INTBITS - bmpinfo.bits);
00621 bitbuf <<= bmpinfo.bits;
00622 n -= bmpinfo.bits;
00623 GM_UPUT(gm, x, y, coltable[b]);
00624 }
00625 TRY(bmp_pad(f));
00626 }
00627 break;
00628
00629 case 0x010:
00630
00631
00632 gm_read_error = "cannot handle bmp 16-bit coding";
00633 goto format_error;
00634 break;
00635
00636 case 0x018:
00637 case 0x020:
00638 for (y=0; y<bmpinfo.h; y++) {
00639 bmp_pad_reset();
00640 for (x=0; x<bmpinfo.w; x++) {
00641 TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
00642 c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
00643 GM_UPUT(gm, x, y, c/3);
00644 }
00645 TRY(bmp_pad(f));
00646 }
00647 break;
00648
00649 case 0x204:
00650 x = 0;
00651 y = 0;
00652 while (1) {
00653 TRY_EOF(bmp_readint(f, 1, &b));
00654 TRY_EOF(bmp_readint(f, 1, &c));
00655 if (b>0) {
00656
00657 col[0] = coltable[(c>>4) & 0xf];
00658 col[1] = coltable[c & 0xf];
00659 for (i=0; i<b && x<bmpinfo.w; i++) {
00660 if (x>=bmpinfo.w) {
00661 x=0;
00662 y++;
00663 }
00664 if (y>=bmpinfo.h) {
00665 break;
00666 }
00667 GM_UPUT(gm, x, y, col[i&1]);
00668 x++;
00669 }
00670 } else if (c == 0) {
00671
00672 y++;
00673 x = 0;
00674 } else if (c == 1) {
00675
00676 break;
00677 } else if (c == 2) {
00678
00679 TRY_EOF(bmp_readint(f, 1, &b));
00680 TRY_EOF(bmp_readint(f, 1, &c));
00681 x += b;
00682 y += c;
00683 } else {
00684
00685 for (i=0; i<c; i++) {
00686 if ((i&1)==0) {
00687 TRY_EOF(bmp_readint(f, 1, &b));
00688 }
00689 if (x>=bmpinfo.w) {
00690 x=0;
00691 y++;
00692 }
00693 if (y>=bmpinfo.h) {
00694 break;
00695 }
00696 GM_PUT(gm, x, y, coltable[(b>>(4-4*(i&1))) & 0xf]);
00697 x++;
00698 }
00699 if ((c+1) & 2) {
00700
00701 TRY_EOF(bmp_readint(f, 1, &b));
00702 }
00703 }
00704 }
00705 break;
00706
00707 case 0x108:
00708 x = 0;
00709 y = 0;
00710 while (1) {
00711 TRY_EOF(bmp_readint(f, 1, &b));
00712 TRY_EOF(bmp_readint(f, 1, &c));
00713 if (b>0) {
00714
00715 for (i=0; i<b; i++) {
00716 if (x>=bmpinfo.w) {
00717 x=0;
00718 y++;
00719 }
00720 if (y>=bmpinfo.h) {
00721 break;
00722 }
00723 GM_UPUT(gm, x, y, coltable[c]);
00724 x++;
00725 }
00726 } else if (c == 0) {
00727
00728 y++;
00729 x = 0;
00730 } else if (c == 1) {
00731
00732 break;
00733 } else if (c == 2) {
00734
00735 TRY_EOF(bmp_readint(f, 1, &b));
00736 TRY_EOF(bmp_readint(f, 1, &c));
00737 x += b;
00738 y += c;
00739 } else {
00740
00741 for (i=0; i<c; i++) {
00742 TRY_EOF(bmp_readint(f, 1, &b));
00743 if (x>=bmpinfo.w) {
00744 x=0;
00745 y++;
00746 }
00747 if (y>=bmpinfo.h) {
00748 break;
00749 }
00750 GM_PUT(gm, x, y, coltable[b]);
00751 x++;
00752 }
00753 if (c & 1) {
00754
00755 TRY_EOF(bmp_readint(f, 1, &b));
00756 }
00757 }
00758 }
00759 break;
00760
00761 }
00762
00763
00764
00765 bmp_forward(f, bmpinfo.FileSize);
00766
00767 free(coltable);
00768 *gmp = gm;
00769 return 0;
00770
00771 eof:
00772 free(coltable);
00773 *gmp = gm;
00774 return 1;
00775
00776 format_error:
00777 try_error:
00778 free(coltable);
00779 free(gm);
00780 if (!gm_read_error) {
00781 gm_read_error = "invalid bmp file";
00782 }
00783 return -2;
00784
00785 std_error:
00786 free(coltable);
00787 free(gm);
00788 return -1;
00789 }
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799 int gm_writepgm(FILE *f, greymap_t *gm, char *comment, int raw, int mode, double gamma) {
00800 int x, y, v;
00801 int gammatable[256];
00802
00803
00804 if (gamma != 1.0) {
00805 gammatable[0] = 0;
00806 for (v=1; v<256; v++) {
00807 gammatable[v] = (int)(255 * exp(log(v/255.0)/gamma) + 0.5);
00808 }
00809 } else {
00810 for (v=0; v<256; v++) {
00811 gammatable[v] = v;
00812 }
00813 }
00814
00815 fprintf(f, raw ? "P5\n" : "P2\n");
00816 if (comment && *comment) {
00817 fprintf(f, "# %s\n", comment);
00818 }
00819 fprintf(f, "%d %d 255\n", gm->w, gm->h);
00820 for (y=gm->h-1; y>=0; y--) {
00821 for (x=0; x<gm->w; x++) {
00822 v = GM_UGET(gm, x, y);
00823 if (mode == GM_MODE_NONZERO) {
00824 if (v > 255) {
00825 v = 510 - v;
00826 }
00827 if (v < 0) {
00828 v = 0;
00829 }
00830 } else if (mode == GM_MODE_ODD) {
00831 v = mod(v, 510);
00832 if (v > 255) {
00833 v = 510 - v;
00834 }
00835 } else if (mode == GM_MODE_POSITIVE) {
00836 if (v < 0) {
00837 v = 0;
00838 } else if (v > 255) {
00839 v = 255;
00840 }
00841 } else if (mode == GM_MODE_NEGATIVE) {
00842 v = 510 - v;
00843 if (v < 0) {
00844 v = 0;
00845 } else if (v > 255) {
00846 v = 255;
00847 }
00848 }
00849 v = gammatable[v];
00850
00851 if (raw) {
00852 fputc(v, f);
00853 } else {
00854 fprintf(f, x == gm->w-1 ? "%d\n" : "%d ", v);
00855 }
00856 }
00857 }
00858 return 0;
00859 }
00860
00861
00862
00863
00864
00865 int gm_print(FILE *f, greymap_t *gm) {
00866 int x, y;
00867 int xx, yy;
00868 int d, t;
00869 int sw, sh;
00870
00871 sw = gm->w < 79 ? gm->w : 79;
00872 sh = gm->w < 79 ? gm->h : gm->h*sw*44/(79*gm->w);
00873
00874 for (yy=sh-1; yy>=0; yy--) {
00875 for (xx=0; xx<sw; xx++) {
00876 d=0;
00877 t=0;
00878 for (x=xx*gm->w/sw; x<(xx+1)*gm->w/sw; x++) {
00879 for (y=yy*gm->h/sh; y<(yy+1)*gm->h/sh; y++) {
00880 d += GM_GET(gm, x, y);
00881 t += 256;
00882 }
00883 }
00884 fputc("*#=- "[5*d/t], f);
00885 }
00886 fputc('\n', f);
00887 }
00888 return 0;
00889 }