1 #ifndef lint 2 static char sccsid[]="@(#)prects.c 1.1 (CWI) 87/07/16"; 3 #endif lint 4 /* 5 * read the fontdir/char.rle files from cdata output to produce the 6 * rectangular data for a font. 7 */ 8 9 #include <sys/types.h> 10 #include <sys/dir.h> 11 #include <sys/file.h> 12 #include <stdio.h> 13 #include <strings.h> 14 15 #include "../defs.h" 16 #include "huff7.h" 17 #include "huff14.h" 18 #include "Ptable.h" 19 20 extern long lseek(); 21 22 extern Word huff7[]; 23 extern Word huff14[]; 24 extern Byte Ptable[]; 25 26 /* 27 * bit map will be at most 1024 by 1024 points 28 * 29 * The right answer would be to compact the data in 30 * bytes, but I'm just going to hack this... (DD) 31 */ 32 33 #define MAXnat 1024 34 #define MAX 128 35 typedef unsigned short nat; 36 37 Byte bitmap[MAX][MAXnat], /* `real' binary data */ 38 newbitmap[MAXnat][ MAXnat]; /* expanded data in chars */ 39 Byte sqmap[MAXnat][MAXnat], 40 prmap[MAXnat][MAXnat], 41 uline[MAXnat]; 42 43 FILE *fd; 44 int eoc = 0; /* signals end of a character */ 45 46 /* 47 * storage of 3 previous scan lines plus current working scan line 48 * 6 extra points (always of) for begin of end of scanline for predict() 49 */ 50 51 Byte a[1030], b[1030], c[1030], d[1030]; 52 /* pointers to the scanline storage */ 53 Byte *sl0 = &a[3], *sl1 = &b[3], *sl2 = &c[3], *sl3 = &d[3]; 54 55 #define EVER ;; 56 57 /* 58 * Opcodes for the huffman decoder 59 */ 60 61 #define OPCODE 0300 62 #define FINAL 0 63 #define POINT 0200 64 #define SUFFIX 0100 65 66 /* 67 * address bits for pointer (huffman decode) 68 */ 69 70 #define ADDRS 077 71 #define SUFDAT 017 72 73 /* 74 * Run length value types 75 */ 76 77 #define DUMP 1 78 #define X0 2 79 #define Y0 3 80 #define LMAX 4 81 #define RUNL 5 82 83 #define Charmax 128 84 85 struct Header head; 86 struct Chars Char[Charmax]; 87 struct Rect rect; 88 89 struct Rect buf[BUFSIZ]; /* global buffer to hold rects */ 90 struct Rect *bob = buf; /* pointer to start of buffer */ 91 struct Rect *eob = &buf[BUFSIZ-1]; /* pointer to end of buffer */ 92 struct Rect *curp = buf; /* current buffer pointer */ 93 long offset; /* offset in file */ 94 95 96 /* 97 * We start with significant bit 98 */ 99 100 #define BITMASK 0100000L 101 102 #define dbprintf if(debug)printf 103 int debug = 0; 104 105 106 #define MAXFNAME 30 107 char filename[MAXFNAME]; 108 int fdo; /* file descriptor for output file */ 109 110 main(argc, argv) 111 int argc; 112 char **argv; 113 { 114 int i, j; 115 DIR *dir; 116 char outfile[BUFSIZ]; /* name for output file */ 117 struct direct *dirbuf; 118 char *file, *directory; 119 Word *type, *gethuff(); 120 int k; /* character we are on */ 121 char *p; 122 123 argv++; 124 while( --argc && *argv[0] == '-') { 125 126 switch((*argv)[1]) { 127 case 'd': 128 debug++; 129 break; 130 case 'o': 131 sprintf(outfile,"%s", (*argv)+2); 132 break; 133 default: 134 error("Unknown option %s", *argv); 135 } 136 argv++; 137 } 138 139 if(argc < 1) 140 error("No data specified"); 141 142 while(argc--) { 143 directory = rindex(*argv, '/'); 144 if( directory == (char *)0) 145 directory = *argv; 146 else 147 directory++; 148 149 if((dir = opendir(*argv)) == NULL) 150 error("Can't open directory %s", *argv); 151 argv++; 152 if(sscanf(directory, "%d-%d", &j, &i) == 0) 153 error("scanf error"); 154 type = gethuff(i); 155 if(outfile[0] == NULL) 156 sprintf(outfile,"%s.rect", directory); 157 dbprintf("Output to file %s\n", outfile ); 158 if((fdo = open(outfile,O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) 159 error("open error %s\n", outfile); 160 head.magic = MAGIC; 161 bcopy(directory, head.name,strlen(directory)); 162 headit(); 163 setchars(); 164 setoffset(); 165 for(dirbuf = readdir(dir); dirbuf != NULL; dirbuf = readdir(dir) ) { 166 if(strcmp((file = dirbuf->d_name), ".") == 0 || 167 strcmp(file, "..") == 0) 168 continue; 169 sprintf(filename,"%s/%s",directory,file); 170 p = file; 171 while(*p++) 172 ; 173 p -= 5; 174 if(strcmp(p, ".rle") != 0){ 175 fprintf(stderr, "strange file %s, skipped\n", filename); 176 continue; 177 } 178 sscanf(file, "%o", &k); 179 if(k > Charmax) { 180 fprintf(stderr,"Wierd Character %s\n", filename); 181 continue; 182 } 183 chardecode(type, k-1); 184 cleanup(); 185 } 186 flusho(); 187 setchars(); 188 } 189 } 190 191 192 /* 193 * gethuff: 194 * get the huff value from the directory name. 195 */ 196 197 Word * 198 gethuff(mcode) 199 int mcode; 200 { 201 Word *huff; 202 203 switch(mcode) { 204 case MSC1: 205 case MSC2: 206 huff = huff7; 207 break; 208 case MSC3: 209 huff = huff14; 210 break; 211 default: 212 error("Unknown master code %#o\n", mcode); 213 } 214 return huff; 215 } 216 217 218 /* 219 * chardecode: 220 * decode the encode character date in gcd of 221 * pointsize code mcode 222 */ 223 224 int X, Y, Lmax; /* the offsets */ 225 int curx, cury; 226 int endline; 227 228 chardecode(huff, charno) 229 int charno; Word *huff; 230 { 231 int runl; 232 233 (void) getbit(1); /* reset the getbit routine */ 234 235 curx = Char[charno].Relwidth = getnbits(8); /* ignore the first 8 bits */ 236 curx = X = Char[charno].XO = huffdecode(huff); 237 cury = Y = Char[charno].YO = huffdecode(huff); 238 Lmax = Char[charno].Lmax = huffdecode(huff); 239 240 /* 241 * Lmax 18 means 17 dots, so y should go from 242 * Y to Lmax -1 ???? 243 */ 244 endline = Y + Lmax - 1 ; 245 246 while(!eoc) { 247 for( cury = Y ; cury <= endline; ) { 248 runl = huffdecode(huff); 249 if(!runl) { /* End of Line */ 250 predict(cury, endline - cury, 1); 251 cury = endline; 252 break; 253 } 254 else { 255 predict(cury, runl, 0); 256 cury += runl; 257 if(cury >= endline) 258 break; 259 } 260 } 261 cury = Y ; 262 storescanline(curx, cury, endline); 263 swapscanp(); 264 curx++; 265 } 266 Char[charno].X = curx - X ; 267 Char[charno].Y = (Lmax + Y - 2) - Y; 268 Char[charno].offset = offset; 269 setbitmap(X, Y, curx, Lmax + Y - 2); 270 maxsq(); 271 prune(); 272 Char[charno].Nstructs = combi(); 273 dbprintf("The next offset is %ld\n", offset); 274 dbprintf("@ End of character data (%d)\n", charno); 275 } 276 277 278 /* 279 * huffdecode 280 * 281 * returns the runlength of the Character Generation Data 282 * using huffman decode table huff. 283 */ 284 285 huffdecode(huff) 286 Word *huff; 287 { 288 register Word data = 0; 289 register tmp; 290 register int suffix; 291 292 for(EVER) { 293 switch(data & OPCODE) { 294 case FINAL: 295 if(data == 0) { 296 tmp = (*huff | getbit(0)) & ADDRS; 297 data = *(huff + tmp); 298 if(data == 0 ) 299 return(0); 300 } else { 301 tmp = data & ~FINAL; 302 return(tmp); 303 } 304 break; 305 case POINT: 306 tmp = (data | getbit(0)) & ADDRS; 307 data = *(huff + tmp); 308 break; 309 case SUFFIX: 310 tmp = data & SUFDAT; 311 suffix = getnbits(tmp); 312 if(!suffix) 313 eoc++; 314 return(suffix); 315 default: 316 error("Unknown opcode %#o\n", data); 317 } 318 } 319 } 320 321 322 /* 323 * get the value of n bits from the gcd 324 */ 325 326 getnbits(n) 327 int n; 328 { 329 register int i; 330 register int j; 331 unsigned int value = 0; 332 333 for(i = n; i > 0; i-- ) { 334 j = getbit(0); 335 value = (value << 1) | j; 336 if( i > sizeof(value) * 8) 337 error("Overflow in getnbits(%d)\n", i); 338 } 339 return(value); 340 } 341 342 343 /* 344 * return a bit from the character generation data 345 * 346 * initialise when argument is set 347 */ 348 349 getbit(init) 350 int init; 351 { 352 static bitno; 353 static unsigned int mask; 354 static unsigned int n; 355 register int bit; 356 register int k; 357 358 if(init) { 359 bitno = 1; 360 if((fd = fopen(filename, "r")) == NULL ) 361 error("Cannot open %s", filename); 362 return 0; 363 } else { 364 if( (bitno - 1) % 16 == 0) { 365 bitno = 1; 366 if(( k = fread( (char *)&n, sizeof(Word), 1, fd)) != 1) 367 error("Read error %d", k); 368 mask = BITMASK; 369 } 370 } 371 372 bit = n & mask; 373 bitno++; 374 mask = mask >> 1; 375 if(bit) { 376 return(1); 377 } else { 378 return(0); 379 } 380 } 381 382 383 /* 384 * predict: 385 * predicts the dot on position x, y, over a runlength r. 386 * if 3th argument is set, don't generate exception point. 387 */ 388 389 #define P8192 020000 390 #define P4096 010000 391 #define P2048 004000 392 #define P1024 002000 393 #define P0512 001000 394 #define P0256 000400 395 #define P0128 000200 396 #define P0064 000100 397 #define P0032 000040 398 #define P0016 000020 399 #define P0008 000010 400 #define P0004 000004 401 #define P0002 000002 402 #define P0001 000001 403 404 #define ON 1 405 #define OFF 0 406 407 408 predict(y, r, e) 409 register int y; 410 int e, r; 411 { 412 unsigned int same = 0; 413 unsigned register int mask = 0; 414 unsigned register int state = 0; 415 unsigned register int i; 416 unsigned int prev = 0, new = 0, except = 0; 417 extern unsigned int getmask(); 418 419 i = r; 420 do { 421 state = except = prev = 0; 422 mask = getmask(y); 423 if(mask & P8192) { 424 mask ^= 017777; 425 prev = 1; 426 } 427 mask &= 017777; 428 same = getdot(mask); 429 if( i == 1 && e == 0) { /* exception point */ 430 except = 1; 431 } 432 state = except; 433 state |= prev << 1; 434 state |= same << 2; 435 switch(state & 07) { 436 case 0: 437 case 3: 438 case 5: 439 case 6: 440 new = ON; 441 break; 442 case 1: 443 case 2: 444 case 4: 445 case 7: 446 new = OFF; 447 break; 448 default: 449 error("Unexpected state %#o\n", state); 450 } 451 storedot( new, y ); 452 y++; 453 } while (--i); 454 } 455 456 /* 457 * find wether the dot should be the same or not 458 */ 459 460 #define PMASK 017774 461 #define TWOBIT 03 462 463 464 getdot(value) 465 unsigned int value; 466 { 467 register int tmp, i, j, k; 468 469 i = (value & PMASK) >> 2; 470 j = value & TWOBIT; 471 if(i > sizeof(Ptable)) 472 error("Prom adressing error"); 473 474 tmp = Ptable[i]; 475 k = (tmp >> j) & 1; 476 return k; 477 } 478 479 480 /* 481 * store point in current working area 482 */ 483 484 storedot( dot, y) 485 register unsigned int dot; 486 register int y; 487 { 488 if(y > Lmax + 2 + Y ) 489 error("Out of range in store dot, y = %d", y); 490 491 if(y == endline -1) 492 return; 493 sl0[y] = dot; 494 } 495 496 497 /* 498 * construct the predict mask for position x, y 499 */ 500 501 unsigned int 502 getmask(y) 503 register int y; 504 { 505 register unsigned int mask = 0; 506 507 if( y < 3 || y > 1029) 508 error("Out of range in getmask, y = %d\n", y); 509 510 if( sl3[y+2] ) /* PROM 1 */ 511 mask |= P0001; 512 if( sl3[y+1] ) 513 mask |= P0002; 514 if( sl3[y-1] ) /* PROM 4 */ 515 mask |= P0004; 516 if( sl3[y-2] ) /* PROM 8 */ 517 mask |= P0008; 518 if( sl2[y+3] ) /* PROM 16 */ 519 mask |= P0016; 520 if( sl2[y+1] ) /* PROM 32 */ 521 mask |= P0032; 522 if( sl2[y-1] ) /* PROM 64 */ 523 mask |= P0064; 524 if( sl2[y-3] ) /* PROM 128 */ 525 mask |= P0128; 526 if( sl1[y+2] ) /* PROM 256 */ 527 mask |= P0256; 528 if( sl1[y+1] ) /* PROM 512 */ 529 mask |= P0512; 530 if( sl1[ y ] ) /* PROM 1024 */ 531 mask |= P1024; 532 if( sl1[y-1] ) /* PROM 2048 */ 533 mask |= P2048; 534 if( sl1[y-3] ) /* PROM 4096 */ 535 mask |= P4096; 536 if( sl0[y-1] ) /* PROM 8192 */ 537 mask |= P8192; 538 return(mask); 539 } 540 541 542 /* 543 * swap the scan line buffers 544 */ 545 546 swapscanp() 547 { 548 register Byte *sav; 549 550 /* 551 * swap the buffers 552 */ 553 sav = sl3; 554 sl3 = sl2; 555 sl2 = sl1; 556 sl1 = sl0; 557 sl0 = sav; 558 559 } 560 561 562 cleanup() 563 { 564 register int i; 565 register int j; 566 567 for( i = 0; i < 1030; i++) 568 a[i] = b[i] = c[i] = d[i] = 0; 569 sl0 = &a[3]; 570 sl1 = &b[3]; 571 sl2 = &c[3]; 572 sl3 = &d[3]; 573 for( i = 0; i < MAXnat; i++) 574 for( j = 0; j < MAXnat; j++) { 575 newbitmap[j][i] = 0; 576 sqmap[j][i] = 0; 577 prmap[j][i] = 0; 578 uline[j] = 0; 579 } 580 for( i = 0; i < MAXnat; i++) 581 for (j = 0; j < MAX; j++) 582 bitmap[j][i] = 0; 583 eoc = 0; 584 (void) fclose(fd); 585 } 586 587 588 /* 589 * store the curent scan line in the bitmap 590 * 591 * bit clumsy, we could just as well dump everyscan line each time 592 * but, as said before, we don't know what to do with the bitmap... 593 * 594 */ 595 596 storescanline(x, y, toy) 597 register int x, y, toy; 598 { 599 register int m, n, i; 600 601 m = x / 8; 602 n = x % 8; 603 if(m > MAX) 604 error("bit map overflow for x (%d)\n", m); 605 606 if(toy >= MAXnat) 607 error("Bitmap overflow"); 608 for( i = y; i < toy; i++) 609 if(sl0[i]) 610 bitmap[m][i] |= (1 << n); 611 } 612 613 short width, height; 614 615 #define For_v for(v=0; v < height; v++) 616 #define For_h for(h=0; h < width; h++) 617 618 619 /* 620 * print the bit map 621 */ 622 623 setbitmap(fromx, fromy, tox, toy) 624 int fromx, fromy, tox, toy; 625 { 626 register int m, n; 627 register int x, y; 628 nat v, h; 629 630 width = tox - fromx; 631 height = toy - fromy; 632 if (width > MAXnat || height > MAXnat) { 633 error("*** X or Y is too large (%d %d)\n", width, height); 634 } 635 636 dbprintf("# Rectangle map of character %s\n", filename); 637 dbprintf("%% X %d Y %d\n", width, height); 638 639 for(v= 0, y = toy - 1; y >= fromy; v++, y--) { 640 for( h=0, x = fromx; x < tox; h++, x++) { 641 m = x / 8; 642 n = x % 8; 643 if((bitmap[m][y] >> n ) & 1) 644 newbitmap[v][h] = 1; 645 else 646 newbitmap[v][h] = 0; 647 } 648 } 649 } 650 651 652 653 maxsq() 654 { 655 register nat v, h, m; 656 nat uleft, up, left; 657 For_h 658 uline[h]= 0; 659 For_v { 660 uleft= left= 0; 661 For_h { 662 up= uline[h]; 663 if (newbitmap[v][h]) { 664 m= uleft; 665 if (up < m) m= up; 666 if (left < m) m= left; 667 sqmap[v][h]= ++m; 668 } else 669 sqmap[v][h]= m= 0; 670 uleft= up; 671 uline[h]= left= m; 672 } 673 sqmap[v][h]= 0; 674 } 675 } 676 677 678 prune() 679 { 680 register nat v, h, m; 681 nat vv, hh; 682 For_v { 683 For_h { 684 m= sqmap[v][h]; 685 for (vv= v; m && vv <= v+1 && vv < height; vv++) 686 for (hh= h; m && hh <= h+1 && hh < width; hh++) 687 if (sqmap[vv][hh] > m) m= 0; 688 prmap[v][h]= m; 689 } 690 } 691 } 692 693 694 combi() 695 { 696 register nat v, h, m, p=0, hh; 697 int rects = 0; /* track number of structures written */ 698 699 For_v { 700 p=m= 0; 701 for (h= 0; h <= width; h++) { 702 if (h == width || prmap[v][h] != m) { 703 /* Don't pay attention to "singletons" (h-p == 1) */ 704 if (m && h-p > 1) { 705 rects++; 706 rect.yO = v-m+1; 707 rect.y = m; 708 rect.xO = p-m+1; 709 rect.x = h-1-p+m; 710 oput(rect); 711 dbprintf("> V@%3d|%3d*H@%3d|%3d\n", v-m+1, m, p-m+1, h-1-p+m); 712 /* Mark squares as accounted for */ 713 for (hh= p; hh < h; hh++) sqmap[v][hh]= 0; 714 } 715 if (h < width) m= prmap[v][p= h]; 716 } 717 } 718 } 719 for (h = 0; h <= width; h++) { 720 p=m= 0; 721 for (v= 0; v <= height; v++) { 722 if (v == height || prmap[v][h] != m) { 723 /* Pay attention to unaccounted-for "singletons" */ 724 if (m && (v-p > 1 || sqmap[v-1][h])) { 725 rects++; 726 rect.yO = p-m+1; 727 rect.y = v-1-p+m; 728 rect.xO = h-m+1; 729 rect.x = m; 730 oput(rect); 731 dbprintf("> V@%3d|%3d*H@%3d|%3d\n", p-m+1, v-1-p+m, h-m+1, m); 732 } 733 if (v < height) m= prmap[p= v][h]; 734 } 735 } 736 } 737 dbprintf("<\n"); 738 dbprintf("The Nstructs should be %d\n", rects); 739 return(rects); 740 } 741 742 headit() 743 { 744 if(lseek(fdo, (long)0, 0) == -1) 745 error("seek error in head routine"); 746 if(write(fdo, (char *) &head, sizeof(struct Header)) != sizeof(struct Header)) 747 error("write error in head routine"); 748 } 749 setchars() 750 { 751 if(lseek(fdo, (long)(sizeof(struct Header)), 0) == -1) 752 error("seek error in setchars routine"); 753 if (write(fdo, (char *)Char, Charmax * sizeof(struct Chars)) != Charmax * sizeof(struct Chars)) 754 error("Write error in setchars routine"); 755 } 756 757 758 /* output a rect struct */ 759 760 oput(r) 761 struct Rect r; 762 { 763 *curp++ = r; 764 if(curp > eob) { 765 flusho(); 766 curp = bob; 767 } 768 offset += sizeof(struct Rect); 769 } 770 771 /* flush the buffer holding the rectangles */ 772 773 flusho() 774 { 775 776 if ( write(fdo, (char *)bob, (int)(curp - bob) * sizeof(struct Rect)) != 777 (int)(curp - bob)*sizeof(struct Rect)) 778 error("Write error in flusho routine"); 779 } 780 781 setoffset() 782 { 783 offset = sizeof(struct Header) + Charmax * sizeof(struct Chars); 784 } 785