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