1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
|
/****************************************************************************
*
* Copyright(c) 2002-2008, John Forkosh Associates, Inc. All rights reserved.
* http://www.forkosh.com mailto: john@forkosh.com
* --------------------------------------------------------------------------
* This file is part of mimeTeX, which is free software. You may redistribute
* and/or modify it under the terms of the GNU General Public License,
* version 3 or later, as published by the Free Software Foundation.
* MimeTeX is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, not even the implied warranty of MERCHANTABILITY.
* See the GNU General Public License for specific details.
* By using mimeTeX, you warrant that you have read, understood and
* agreed to these terms and conditions, and that you possess the legal
* right and ability to enter into this agreement and to use mimeTeX
* in accordance with it.
* Your mimetex.zip distribution file should contain the file COPYING,
* an ascii text copy of the GNU General Public License, version 3.
* If not, point your browser to http://www.gnu.org/licenses/
* or write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
* --------------------------------------------------------------------------
*
* Program: gfuntype [-g gformat] [-u isnoname] [-m msglevel]
* [-n fontname] [infile [outfile]]
*
* Purpose: Parses output from gftype -i
* and writes pixel bitmap data of the characters
* in a format suitable for a C header file, etc.
*
* --------------------------------------------------------------------------
*
* Command-line Arguments:
* --- args can be in any order ---
* infile name of input file
* (defaults to stdin if no filenames given)
* outfile name of output file
* (defaults to stdout if <2 filenames given)
* -g gformat gformat=1(default) for bitmap representation,
* or 2,3 for 8-bit,4-bit .gf-like compression,
* or 0 to choose smallest format.
* Add 10 (gformat=10,12,13,14) to embed scan
* line repeat counts in format.
* -u isnoname isnoname=1(default) to output symbols not
* defined/named in mimetex.h, or 0 to omit them
* -m msglevel verbose if msglevel>=9 (vv if >=99)
* -n fontname string used for fontname
* (defaults to noname)
*
* Exits: 0=success, 1=some error
*
* Notes: o To compile
* cc gfuntype.c mimetex.c -lm -o gfuntype
* needs mimetex.c and mimetex.h
*
* Source: gfuntype.c
*
* --------------------------------------------------------------------------
* Revision History:
* 09/22/02 J.Forkosh Installation.
* 10/11/05 J.Forkosh .gf-style format options added.
* 09/06/08 J.Forkosh mimeTeX version 1.70 released.
*
****************************************************************************/
/* --------------------------------------------------------------------------
standard headers, program parameters, global data and macros
-------------------------------------------------------------------------- */
/* --- standard headers --- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* --- application headers --- */
/* #define SIGNEDCHAR */
#include "mimetex.h"
/* --- parameters either -D defined on cc line, or defaulted here --- */
#ifndef MSGLEVEL
#define MSGLEVEL 0
#endif
#ifndef GFORMAT
#define GFORMAT 1
#endif
#ifndef ISREPEAT
#define ISREPEAT 1
#endif
/* --- message level (verbose test) --- */
static int msglevel = MSGLEVEL; /* verbose if msglevel >= 9 */
static FILE *msgfp; /* verbose output goes here */
/* --- output file format --- */
static int isnoname = 1; /* true to output unnamed symbols */
static char *noname = "(noname)"; /* char name used if lookup fails */
static int gformat = GFORMAT; /* 1=bitmap, 2=.gf-like */
static int isrepeat = ISREPEAT; /* true to store line repeat counts*/
/* extern int imageformat; */ /* as per gformat, 1=bitmap,2=.gf */
/* --- miscellaneous other data --- */
#define CORNER_STUB ".<--" /* start of upper,lower-left line */
#define BLANKCHAR_STUB "character is entirely blank" /* signals blank char */
#define TYPECAST "(pixbyte *)" /* typecast for pixmap string */
/* ==========================================================================
* Function: main() for gfuntype.c
* Purpose: interprets command-line args, etc
* --------------------------------------------------------------------------
* Command-Line Arguments:
* See above
* --------------------------------------------------------------------------
* Returns: 0=success, 1=some error
* --------------------------------------------------------------------------
* Notes: o
* ======================================================================= */
/* --- entry point --- */
int main ( int argc, char *argv[] )
{
/* --------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
int argnum = 0; /* argv[] index for command-line args */
int inarg=0, outarg=0; /* argv[] indexes for infile, outfile */
int iserror = 1; /* error signal */
int charnum, /* character number (nextchar->charnum) */
nchars = 0; /* #chars in font */
char fontname[99] = "noname", /* font name */
*getcharname(); /* get character name from its number */
FILE /* *fopen(),*/ *infp=stdin, *outfp=stdout; /* init file pointers */
chardef *getnextchar(), *nextchar, /* read and parse next char in infp */
*fontdef[256]; /* chars stored using charnum as index */
int cstruct_chardef(); /* emit C struct for a character map */
int type_raster(); /* display debugging output */
char *copyright = /* copyright, gnu/gpl notice */
"+-----------------------------------------------------------------------+\n"
"|gfuntype ver 1.00, Copyright(c) 2002-2003, John Forkosh Associates, Inc|\n"
"+-----------------------------------------------------------------------+\n"
"| gfuntype is free software licensed to you under terms of the GNU/GPL, |\n"
"| and comes with absolutely no warranty whatsoever. |\n"
"+-----------------------------------------------------------------------+";
/* --------------------------------------------------------------------------
interpret command-line arguments
-------------------------------------------------------------------------- */
while ( argc > ++argnum ) /* check for flags and filenames */
if ( *argv[argnum] == '-' ) /* got some '-' flag */
{
char flag = tolower(*(argv[argnum]+1)); /* char following '-' */
argnum++; /* arg following flag is usually its value */
switch ( flag ) /* see what user wants to tell us */
{
/* --- no usage for clueless users yet --- */
default: exit(iserror); /* exit quietly for unrecognized input */
/* --- adjustable program parameters (not checking input) --- */
case 'g': gformat = atoi(argv[argnum]);
isrepeat = (gformat>=10?1:0);
gformat = gformat%10; break;
case 'u': isnoname = atoi(argv[argnum]); break;
case 'm': msglevel = atoi(argv[argnum]); break;
case 'n': strcpy(fontname,argv[argnum]); break;
} /* --- end-of-switch() --- */
} /* --- end-of-if(*argv[]=='-') --- */
else /* this arg not a -flag, so it must be... */
if ( inarg == 0 ) /* no infile arg yet */
inarg = argnum; /* so use this one */
else /* we already have an infile arg */
if ( outarg == 0 ) /* but no outfile arg yet */
outarg = argnum; /* so use this one */
/* --- set verbose file ptr --- */
msgfp = (outarg>0? stdout : stderr); /* use stdout or stderr */
/* --- emit copyright, gnu/gpl notice --- */
fprintf(msgfp,"%s\n",copyright); /* display copyright, gnu/gpl info */
/* --- display input args if verbose output --- */
if ( msglevel >= 9 ) /* verbose output requested */
fprintf(msgfp,"gfuntype> infile=%s outfile=%s, fontname=%s format=%d.%d\n",
(inarg>0?argv[inarg]:"stdin"), (outarg>0?argv[outarg]:"stdout"),
fontname, gformat,isrepeat);
/* --------------------------------------------------------------------------
initialization
-------------------------------------------------------------------------- */
/* --- initialize font[] array --- */
for ( charnum=0; charnum<256; charnum++ ) /*for each possible char in font*/
fontdef[charnum] = (chardef *)NULL; /* char doesn't exist yet */
/* --- open input file (if necessary) --- */
if ( inarg > 0 ) /* input from file, not from stdin */
if ( (infp = fopen(argv[inarg],"r")) == NULL ) /*try to open input file*/
{ fprintf(msgfp,"gfuntype> can't open %s for read\n",argv[inarg]);
goto end_of_job; } /* report error and quit */
/* --- set format for mimetex.c functions --- */
if ( gformat<0 || gformat>3 ) gformat=1; /* sanity check */
/* if ( gformat == 1 ) imageformat = 1; */ /* force bitmap format */
/* else gformat = imageformat = 2; */ /* or force .gf format */
/* --------------------------------------------------------------------------
process input file
-------------------------------------------------------------------------- */
while ( (nextchar=getnextchar(infp)) != NULL ) /* get each char in file */
{
/* --- display character info --- */
if ( msglevel >= 9 ) /* verbose output requested */
fprintf(msgfp,"gfuntype> Char#%3d, loc %4d: ul=(%d,%d) ll=(%d,%d)\n",
nextchar->charnum, nextchar->location,
nextchar->topleftcol,nextchar->toprow,
nextchar->botleftcol,nextchar->botrow);
if ( msglevel >= 19 ) /* if a bit more verbose */
type_raster(&(nextchar->image),msgfp); /*display ascii image of raster*/
/* --- store character in font */
charnum = nextchar->charnum; /* get char number of char in font */
if ( charnum>=0 && charnum<=255 ) /* check for valid range */
fontdef[charnum] = nextchar; /* store char in font */
} /* --- end-of-while(charnum>0) --- */
/* --------------------------------------------------------------------------
generate output file
-------------------------------------------------------------------------- */
/* --- open output file (if necessary) --- */
if ( outarg > 0 ) /* output to a file, not to stdout */
if ( (outfp = fopen(argv[outarg],"w")) == NULL ) /*try to open output file*/
{ fprintf(msgfp,"gfuntype> can't open %s for write\n",argv[outarg]);
goto end_of_job; } /* report error and quit */
/* --- header lines --- */
fprintf(outfp,"/%c --- fontdef for %s --- %c/\n", '*',fontname,'*');
fprintf(outfp,"static\tchardef %c%s[] =\n {\n", ' ',fontname);
/* --- write characters comprising font --- */
for ( charnum=0; charnum<256; charnum++ ) /*for each possible char in font*/
if ( fontdef[charnum] != (chardef *)NULL ) /*check if char exists in font*/
{ char *charname = getcharname(fontname,charnum);
if ( charname!=NULL || isnoname ) { /* char defined or want undefined */
if ( ++nchars > 1 ) /* bump count */
fprintf(outfp,",\n"); /* and terminate preceding chardef */
fprintf(outfp," /%c --- pixel bitmap for %s char#%d %s --- %c/\n",
'*',fontname,charnum,(charname==NULL?noname:charname),'*');
cstruct_chardef(fontdef[charnum],outfp,6); } /*emit chardef struct*/
else
if(0)fprintf(outfp,"NULL"); /* no character in this position */
} /* --- end-of-if(fontdef[]!=NULL) --- */
else
if(0)fprintf(outfp,"NULL"); /* no character in this position */
/* --- write trailer chardef and closing brace --- */
fprintf(outfp,",\n"); /* finish up last map from loop */
fprintf(outfp," /%c --- trailer --- %c/\n",'*','*'); /* trailer... */
fprintf(outfp," { -99, -999, 0,0,0,0, { 0,0,0,0, %s\"\\0\" } }\n",
TYPECAST);
fprintf(outfp," } ;\n"); /* terminating }; for fontdef */
/* --------------------------------------------------------------------------
end-of-job
-------------------------------------------------------------------------- */
/* --- reset error status for okay exit --- */
iserror = 0;
/* --- close files (if they're open and not stdin/out) --- */
end_of_job:
if ( infp!=NULL && infp!=stdin ) fclose( infp);
if ( outfp!=NULL && outfp!=stdout ) fclose(outfp);
exit ( iserror );
} /* --- end-of-function main() --- */
/* ==========================================================================
* Function: getnextchar ( fp )
* Purpose: Reads and parses the next character definition on fp,
* and returns a new chardef struct describing that character.
* --------------------------------------------------------------------------
* Arguments: fp (I) FILE * to input file
* (containing output from gftype -i)
* Returns: ( chardef * ) ptr to chardef struct describing character,
* or NULL for eof or any error
* --------------------------------------------------------------------------
* Notes: o fp is left so the next line read from it will be
* the one following the final .<-- line.
* ======================================================================= */
/* --- entry point --- */
chardef *getnextchar ( FILE *fp )
{
/* --------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
chardef *new_chardef(), *nextchar=(chardef *)NULL; /*ptr returned to caller*/
int delete_chardef(); /* free allocated memory if error */
int findnextchar(), charnum,location; /* get header line for next char */
int rasterizechar(); /* ascii image --> raster pixmap */
int parsestat=(-999), parsecorner(); /* get col,row from ".<--" line */
char *readaline(); /* read next line from fp */
/* --------------------------------------------------------------------------
initialization
-------------------------------------------------------------------------- */
while ( parsestat == (-999) ) { /* flush entirely blank characters */
/* --- find and interpret header line for next character --- */
charnum = findnextchar(fp,&location); /* read and parse header line */
if ( charnum < 0 ) goto error; /* eof or error, no more chars */
/* --- allocate a new chardef struct and begin populating it --- */
if ( nextchar == (chardef *)NULL ) /* haven't allocated chardef yet */
if ( (nextchar=new_chardef()) /* allocate a new chardef */
== (chardef *)NULL ) goto error; /* and quit if we failed */
nextchar->charnum = charnum; /* store charnum in struct */
nextchar->location = location; /* and location */
/* --- get upper-left corner line --- */
parsestat = parsecorner(readaline(fp), /* parse corner line */
&(nextchar->toprow),&(nextchar->topleftcol)); /* row and col from line */
} /* --- end-of-while(parsestat) --- */
if ( !parsestat ) goto error; /* quit if parsecorner() failed */
/* --------------------------------------------------------------------------
interpret character image (and parse terminating corner line)
-------------------------------------------------------------------------- */
/* --- read ascii character image and interpret as integer bitmap --- */
if ( rasterizechar(fp,&nextchar->image) != 1 ) /* parse image of char */
goto error; /* and quit if failed */
/* --- get lower-left corner line --- */
if ( !parsecorner(readaline(NULL), /* reread and parse corner line */
&(nextchar->botrow),&(nextchar->botleftcol)) ) /* row and col from line */
goto error; /* and quit if failed */
/* --------------------------------------------------------------------------
done
-------------------------------------------------------------------------- */
goto end_of_job; /* skip error return if successful */
error:
if ( nextchar != (chardef *)NULL ) /* have an allocated chardef */
delete_chardef(nextchar); /* so deallocate it */
nextchar = (chardef *)NULL; /* and reset ptr to null for error */
end_of_job:
return ( nextchar ); /* back with chardef or null */
} /* --- end-of-function getnextchar() --- */
/* ==========================================================================
* Function: getcharname ( fontname, charnum )
* Purpose: Looks up charnum for the family specified by fontname
* and returns the corresponding charname.
* --------------------------------------------------------------------------
* Arguments: fontname (I) char * containing fontname for font family
* (from -n switch on command line)
* charnum (I) int containing the character number
* whose corresponding name is wanted.
* Returns: ( char * ) ptr to character name
* or NULL if charnum not found in table
* --------------------------------------------------------------------------
* Notes: o
* ======================================================================= */
/* --- entry point --- */
char *getcharname ( char *fontname, int charnum )
{
/* --------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
/* --- recognized font family names and our corresponding numbers --- */
static char *fnames[] = /*font name from -n switch on command line*/
{ "cmr","cmmib","cmmi","cmsy","cmex","bbold","rsfs",
"stmary","cyr", NULL };
static int fnums[] = /* corresponding mimetex fontfamily number*/
{ CMR10,CMMIB10,CMMI10,CMSY10,CMEX10,BBOLD10,RSFS10,
STMARY10, CYR10, -1 };
static int offsets[] = /* symtable[ichar].charnum = charnum-offset*/
{ 0, 0, 0, 0, 0, 0, 65,
0, 0, -1 };
/* --- other local declarations --- */
char *charname = NULL; /* character name returned to caller */
char flower[99] = "noname"; /* lowercase caller's fontname */
int ifamily = 0, /* fnames[] (and fnums[],offsets[]) index */
offset = 0, /* offsets[ifamily] */
ichar = 0; /* loop index */
/* --------------------------------------------------------------------------
lowercase caller's fontname and look it up in fnames[]
-------------------------------------------------------------------------- */
/* --- lowercase caller's fontname --- */
for ( ichar=0; *fontname!='\000'; ichar++,fontname++ )/*lowercase each char*/
flower[ichar] = (isalpha(*fontname)? tolower(*fontname) : *fontname);
flower[ichar] = '\000'; /* null-terminate lowercase fontname */
if ( strlen(flower) < 2 ) goto end_of_job; /* no lookup match possible */
/* --- look up lowercase fontname in our fnames[] table --- */
for ( ifamily=0; ;ifamily++ ) /* check fnames[] for flower */
if ( fnames[ifamily] == NULL ) goto end_of_job; /* quit at end-of-table */
else if ( strstr(flower,fnames[ifamily]) != NULL ) break; /* found it */
offset = offsets[ifamily]; /* symtable[ichar].charnum = charnum-offset*/
ifamily = fnums[ifamily]; /* xlate index to font family number */
/* --------------------------------------------------------------------------
now look up name for caller's charnum in ifamily, and return it to caller
-------------------------------------------------------------------------- */
/* --- search symtable[] for charnum in ifamily --- */
for ( ichar=0; ;ichar++ ) /*search symtable[] for charnum in ifamily*/
if ( symtable[ichar].symbol == NULL ) goto end_of_job; /* end-of-table */
else
if ( symtable[ichar].family == ifamily /* found desired family */
&& symtable[ichar].handler == NULL ) /* and char isn't a "dummy" */
if ( symtable[ichar].charnum == charnum-offset ) break; /*got charnum*/
/* --- return corresponding charname to caller --- */
charname = symtable[ichar].symbol; /* pointer to symbol name in table */
end_of_job:
if ( charname==NULL && isnoname ) /* want unnamed/undefined chars */
charname = noname; /* so replace null return with noname */
return ( charname );
} /* --- end-of-function getcharname() --- */
/* ==========================================================================
* Function: findnextchar ( fp, location )
* Purpose: Finds next "beginning of char" line in fp
* and returns the character number,
* and (optionally) location if arg provided.
* --------------------------------------------------------------------------
* Arguments: fp (I) FILE * to input file
* (containing output from gftype -i)
* location (O) int * returning "location" of character
* (or pass NULL and it won't be returned)
* Returns: ( int ) character number,
* or -1 for eof or any error
* --------------------------------------------------------------------------
* Notes: o fp is left so the next line read from it will be
* the one following the "beginning of char" line
* ======================================================================= */
/* --- entry point --- */
int findnextchar ( FILE *fp, int *location )
{
/* --------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
static char keyword[99]="beginning of char "; /*signals start of next char*/
char *readaline(), *line; /* read next line from fp */
char *strstr(), *strchr(), *delim; /* search line for substring, char */
char token[99]; /* token extracted from line */
int charnum = (-1); /* character number returned to caller */
/* --------------------------------------------------------------------------
keep reading lines until eof or keyword found
-------------------------------------------------------------------------- */
while ( (line=readaline(fp)) != NULL ) /* read lines until eof */
{
if ( msglevel >= 999 ) /* very, very verbose output requested */
fprintf(msgfp,"nextchar> line = %s\n",line);
if ( (delim=strstr(line,keyword)) != NULL ) /* found keyword on line */
{
/* --- get character number from line --- */
strcpy(token,delim+strlen(keyword)); /* char num follows keyword */
charnum = atoi(token); /* interpret token as integer charnum */
/* --- get location at beginning of line --- */
if ( location != (int *)NULL ) /* caller wants location returned */
if ( (delim=strchr(line,':')) != NULL ) /* location precedes colon */
{ *delim = '\000'; /* terminate line after location */
*location = atoi(line); } /* interpret location as integer */
break; /* back to caller with charnum */
} /* --- end-of-if(delim!=NULL) --- */
} /* --- end-of-while(line!=NULL) --- */
return ( charnum ); /* back to caller with char number or -1 */
} /* --- end-of-function findnextchar() --- */
/* ==========================================================================
* Function: rasterizechar ( fp, rp )
* Purpose: Reads and parses subsequent lines from fp
* (until a terminating ".<--" line),
* representing the ascii image of the character in fp,
* and returns the results in raster struct rp
* --------------------------------------------------------------------------
* Arguments: fp (I) FILE * to input file
* (containing output from gftype -i)
* positioned immediately after top .<-- line,
* ready to read first line of ascii image
* rp (O) raster * returning the rasterized
* character represented on fp as an ascii image
* Returns: ( int ) 1=okay, or 0=eof or any error
* --------------------------------------------------------------------------
* Notes: o fp is left so the last line (already) read from it
* contains the terminating .<-- corner information
* (readaline(NULL) will reread this last line)
* o char images on fp can be no wider than 31 pixels
* ======================================================================= */
/* --- entry point --- */
int rasterizechar ( FILE *fp, raster *image )
{
/* --------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
char *readaline(), *line; /* read next scan line for char from fp */
unsigned char bitvec[1024][128]; /* scan lines parsed up to 1024x1024 bits */
int bitcmp(); /* compare bit strings */
int height = 0, /* #scan lines in fp comprising char */
width = 0; /* #chars on longest scan line */
int iscan, /* bitvec[] index */
ibit; /* bit along scan (i.e., 0...width-1) */
int isokay = 0; /* returned status, init for failure */
/* --- bitmap and .gf-formatted image info (we'll choose smallest) --- */
int iformat = gformat; /*0=best, 1=bitmap, 2=8-bit.gf, 3=4-bit.gf*/
unsigned char gfpixcount[2][65536]; /* .gf black/white flips (max=64K) */
int npixcounts[2] = {9999999,9999999}; /* #counts for 8-bit,4-bit .gf */
int nbytes1=9999999,nbytes2=9999999,nbytes3=9999999;/*#bytes for format*/
/* --------------------------------------------------------------------------
read lines till ".<--" terminator, and construct one vector[] int per line
-------------------------------------------------------------------------- */
memset(bitvec,0,128*1024); /* zero-fill bitvec[] */
while ( (line=readaline(fp)) != NULL ) /* read lines until eof */
{
/* --- allocations and declarations --- */
int icol, ncols=strlen(line); /* line[] column index, #cols in line[] */
/* --- check for end-of-char (when we encounter corner line) --- */
if ( memcmp(line,CORNER_STUB,strlen(CORNER_STUB)) == 0 ) /* corner line */
break; /* so done with loop */
/* --- parse line (encode asterisks comprising character image) --- */
memset(bitvec[height],0,128); /* first zero out all bits */
for ( icol=0; icol<ncols; icol++ ) /* now check line[] for asterisks */
if ( line[icol] == '*' ) /* we want to set this bit */
{ setlongbit(bitvec[height],icol); /* set bit */
if ( icol >= width ) width=icol+1; } /* and check for new width */
height++; /* bump character height */
} /* --- end-of-while(line!=NULL) --- */
if ( height<1 || width<1 ) /* some problem parsing character */
goto end_of_job; /* so quit */
/* --------------------------------------------------------------------------
init image values
-------------------------------------------------------------------------- */
if ( image->pixmap != NULL ) /* hmm, somebody already allocated memory */
free((void *)image->pixmap); /* so just free it */
image->width = width; /* set image width within raster struct */
image->height = height; /* and height */
image->format = gformat; /* set format (will be reset below) */
image->pixsz = 1; /* #bits per pixel (or #counts in .gf fmt) */
if ( gformat==0 || gformat==1 ) /* bitmap representation allowed */
{ nbytes1 = pixmapsz(image); /* #bytes needed for bitmap */
iformat = 1; } /* default to bitmap format */
/* --------------------------------------------------------------------------
perform .gf-like compression on image in bitvec
-------------------------------------------------------------------------- */
if ( gformat == 0 /* choose optimal/smallest respresentation */
|| gformat==2 || gformat==3 ) /* .gf-like compressed representation */
{
/* --- try both 8-bits/count and 4-bits/count for best compression --- */
int maxbitcount[2] = {254,14}; /* don't count too much in one byte */
int repeatcmds[2] = {255,15}; /* opcode for repeat/duplicate count */
int minbytes = 0; /* #bytes needed for smallest format */
for ( iformat=2; iformat<=3; iformat++ ) { /* 2=8-bit packing, 3=4-bit */
int gfbitcount = 0, /* count of consecutive gfbitval's */
gfbitval = 0, /* begin with count of leading 0's */
pixcount = 0; /* #packed bytes (#black/white flips) */
unsigned char *gfcount = gfpixcount[iformat-2]; /*counts for this format*/
if ( gformat!=0 && gformat!=iformat ) /* this format not allowed */
continue; /* so just skip it */
for ( iscan=0; iscan<height; iscan++ ) /* for each integer in bitvec[] */
{
int bitval = 0; /* current actual pixel value */
int nrepeats=0, nextreps=0; /* #duplicate lines below current,next line*/
/* --- check for repeated/duplicate scan lines --- */
if ( isrepeat /* we're storing scan line repeat counts */
&& iscan < height-1 ) { /* current scan line isn't the last line */
/* --- count repeats --- */
int jscan = iscan; /* compare current scan with lines below it*/
while ( ++jscan < height ) { /* until last scan line */
if (nrepeats == jscan-iscan-1) /*no intervening non-identical lines*/
if ( bitcmp(bitvec[iscan],bitvec[jscan],width) == 0 ) /* identical */
nrepeats++; /* so bump repeat count */
if ( jscan > iscan+1 ) /* we're below next line */
if (nextreps == jscan-iscan-2) /*no intervening non-identical lines*/
if ( bitcmp(bitvec[iscan+1],bitvec[jscan],width) == 0 )/*identical*/
nextreps++; } /* so bump next lline repeat count */
/* --- set repeat command and count --- */
if ( nrepeats > 0 ) { /* found repeated lines below current */
int maxrepeats = maxbitcount[iformat-2]; /*max count/repeats per byte*/
if ( nrepeats > maxrepeats ) nrepeats=maxrepeats; /* don't exceed max */
{setbyfmt(iformat,gfcount,pixcount,repeatcmds[iformat-2]);} /*set cmd*/
{setbyfmt(iformat,gfcount,pixcount+1,nrepeats);} /* set #repeats */
pixcount += 2; } /* don't bump pixcount within macros */
} /* --- end-of-if(isrepeat) --- */
/* --- set bit counts for current scan line --- */
for ( ibit=0; ibit<width; ibit++ ) /* for all bits in this scanline */
{
bitval = getlongbit(bitvec[iscan],ibit); /* check actual pixel value */
if ( bitval != gfbitval ) { /* black-to-white edge (or vice versa) */
{setbyfmt(iformat,gfcount,pixcount,gfbitcount);} /*set byte or nibble*/
pixcount++; /* don't bump pixcount within macro */
gfbitcount = 0; /* reset consecutive bit count */
gfbitval = 1-gfbitval; } /* flip bit to be counted */
else /* check count if continuing with same val */
if ( gfbitcount >= maxbitcount[iformat-2] ) { /* max count per byte */
{setbyfmt(iformat,gfcount,pixcount,gfbitcount);} /*set byte or nibble*/
clearbyfmt(iformat,gfcount,pixcount+1); /*followed by dummy 0 count*/
pixcount += 2; /* don't bump pixcount within macros */
gfbitcount = 0; } /* reset consecutive bit count */
if ( bitval == gfbitval ) /* same bit val as preceding, or first new */
gfbitcount++; /* so just count another pixel */
} /* --- end-of-for(ibit) --- */
/* --- adjust for repeated scan lines --- */
iscan += nrepeats; /* skip repeated/duplicate scan lines */
if ( nrepeats>0 || nextreps>0 ) /* emit count to align on full scan */
if ( iscan < height-1 ) /* have another scan line below this one */
if ( gfbitcount > 0 ) { /* should always have some final count */
{setbyfmt(iformat,gfcount,pixcount,gfbitcount);} /*set byte or nibble*/
pixcount++; /* don't bump pixcount within macro */
gfbitcount = 0; /* reset consecutive bit count */
if ( bitval == getlongbit(bitvec[iscan+1],0) ) { /* same bit value */
clearbyfmt(iformat,gfcount,pixcount); /*so we need a dummy 0 count*/
pixcount++; } /* don't bump pixcount within macros */
else /* bitval flips at start of next line */
gfbitval = 1-gfbitval; /* so flip bit to be counted */
} /* --- end-of-if(nrepeats...gfbitcount>0) --- */
} /* --- end-of-for(iscan) --- */
/* --- store final count --- */
if ( gfbitcount > 0 ) { /* have a final count */
{setbyfmt(iformat,gfcount,pixcount,gfbitcount);} /*set byte or nibble*/
pixcount++; } /* don't bump pixcount within macro */
else /* ended exactly after maxbitcount? */
if ( getbyfmt(iformat,gfcount,pixcount-1) == 0 )/*have dummy 0 trailer?*/
pixcount--; /* remove unneeded dummy trailer */
/* --- save count to choose smallest --- */
npixcounts[iformat-2] = pixcount; /* save count */
} /* --- end-of-for(iformat) --- */
/* --- check for optimal/smallest format --- */
nbytes2=npixcounts[0]; nbytes3=(1+npixcounts[1])/2; /* #bytes for count */
iformat = (nbytes2<nbytes3? 2:3); /* choose smallest format */
minbytes = (iformat==2?nbytes2:nbytes3); /* #bytes for smallest format */
if ( gformat == 0 ) /* bitmap representation also permitted */
if ( nbytes1 <= minbytes ) /* and it's the optimal/smallest format */
iformat = 1; /* so flip format */
/* --- move results to returned image --- */
if ( iformat != 1 ) { /* using a .gf format */
if ( (image->pixmap = (unsigned char *)malloc(minbytes)) /* alloc pixmap */
== NULL ) goto end_of_job; /* quit if failed to allocate pixmap */
memcpy(image->pixmap,gfpixcount[iformat-2],minbytes); /*copy local counts*/
image->format = iformat; /* signal byte counts or nibble counts */
image->pixsz = npixcounts[iformat-2]; /*#counts in pixmap for gformat=2,3*/
} /* --- end-of-if(iformat!=1) --- */
} /* --- end-of-if(gformat==2) --- */
/* --------------------------------------------------------------------------
copy each integer in bitvec[] to raster pixmap, bit by bit
-------------------------------------------------------------------------- */
if ( iformat == 1 ) /* bit-by-bit representation of image */
{
int ipixel = 0; /* pixmap index */
/* --- first allocate image raster pixmap for character --- */
if ( (image->pixmap = (unsigned char *)malloc(pixmapsz(image)))
== NULL ) goto end_of_job; /* quit if failed to allocate pixmap */
image->format = iformat; /* reset format */
/* --- now store bit image in allocated raster --- */
for ( iscan=0; iscan<height; iscan++ ) /* for each integer in bitvec[] */
for ( ibit=0; ibit<width; ibit++ ) /* for all bits in this scanline */
{
if ( getlongbit(bitvec[iscan],ibit) != 0 ) /* check current scan pixel */
{ setlongbit(image->pixmap,ipixel); }
else /*turn off corresponding raster bit*/
{ unsetlongbit(image->pixmap,ipixel); }
ipixel++; /* bump image raster pixel */
} /* --- end-of-for(iscan,ibit) --- */
} /* --- end-of-if(gformat==1) --- */
/* --------------------------------------------------------------------------
done
-------------------------------------------------------------------------- */
isokay = 1; /* reset flag for success */
end_of_job:
return ( isokay ); /* back with 1=success, 0=failure */
} /* --- end-of-function rasterizechar() --- */
/* ==========================================================================
* Function: parsecorner ( line, row, col )
* Purpose: Parses a "pixel corner" line (upper left or lower left)
* and returns the (col,row) information on it as integers.
* --------------------------------------------------------------------------
* Arguments: line (I) char * to input line containing
* ".<--This pixel's..." to be parsed
* row (O) int * returning the (,row)
* col (O) int * returning the (col,)
* Returns: ( int ) 1 if successful, or 0 for any error
* --------------------------------------------------------------------------
* Notes: o
* ======================================================================= */
/* --- entry point --- */
int parsecorner ( char *line, int *row, int *col )
{
/* --------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
int isokay = 0; /* success/fail flag, init for failure */
char field[99], *delim; /*(col,row) field and ptr to various delims*/
/* --------------------------------------------------------------------------
extract (col,row) field from line, and interpret col and row as integers
-------------------------------------------------------------------------- */
/* --- first, check beginning of line --- */
if ( line == (char *)NULL ) goto end_of_job; /* no line supplied by caller */
/* --- check for blank line --- */
if ( strstr(line,BLANKCHAR_STUB) != NULL ) /* got entirely blank character */
return ( -999 ); /* so return special -999 signal */
/* --- check for corner --- */
if ( memcmp(line,CORNER_STUB,strlen(CORNER_STUB)) != 0 ) /*not valid corner*/
goto end_of_job; /* so quit */
/* --- extract col,row field from line --- */
if ( (delim=strchr(line,'(')) == NULL ) goto end_of_job; /*find open paren*/
strncpy(field,delim+1,10); /* extract next 10 chars */
field[10] = '\000'; /* and null-terminate field */
if ( (delim=strchr(field,')')) == NULL ) goto end_of_job; /*find close paren*/
*delim = '\000'; /* terminate field at close paren */
/* --- interpret col,row as integers --- */
if ( (delim=strchr(field,',')) == NULL ) goto end_of_job; /* find comma */
*delim = '\000'; /* break field into col and row */
if ( col != (int *)NULL ) /* caller gave us ptr for col */
*col = atoi(field); /* so return it to him */
if ( row != (int *)NULL ) /* caller gave us ptr for row */
*row = atoi(delim+1); /* so return it to him */
/* --------------------------------------------------------------------------
done
-------------------------------------------------------------------------- */
isokay = 1; /* reset flag for success */
end_of_job:
return ( isokay ); /* back with success/fail flag */
} /* --- end-of-function parsecorner() --- */
/* ==========================================================================
* Function: readaline ( fp )
* Purpose: Reads a line from fp, strips terminating newline,
* and returns ptr to internal buffer
* --------------------------------------------------------------------------
* Arguments: fp (I) FILE * to input file to be read.
* If null, returns line previously read.
* Returns: ( char * ) internal buffer containing line read,
* or NULL for eof or error.
* --------------------------------------------------------------------------
* Notes: o fp is left on the line following the returned line
* ======================================================================= */
/* --- entry point --- */
char *readaline ( FILE *fp )
{
/* --------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
static char buffer[2048]; /* static buffer returned to caller */
char *fgets(), *bufptr=buffer; /* read line from fp */
char *strchr(), *delim; /* remove terminating newline */
/* --------------------------------------------------------------------------
Read line and strip trailing newline
-------------------------------------------------------------------------- */
if ( fp != NULL ) /*if null, return previous line read*/
if ( (bufptr=fgets(buffer,2047,fp)) /* read next line from fp */
!= NULL ) /* and check that we succeeded */
{
if ( (delim=strchr(bufptr,'\n')) /* look for terminating newline */
!= NULL ) /* and check that we found it */
*delim = '\000'; /* truncate line at newline */
} /* --- end-of-if(fgets()!=NULL) --- */
return ( bufptr ); /*back to caller with buffer or null*/
} /* --- end-of-function readaline() --- */
/* ==========================================================================
* Function: bitcmp ( bs1, bs2, n )
* Purpose: compares the first n bits of two strings
* --------------------------------------------------------------------------
* Arguments: bs1 (I) unsigned char * to first bit string
* bs2 (I) unsigned char * to second bit string
* n (I) int containing #bits to compare
* Returns: ( int ) 0 if first n bits are identical
* -1 if first unmatching bit of bs1 is 0
* +1 if first unmatching bit of bs2 id 0
* --------------------------------------------------------------------------
* Notes: o
* ======================================================================= */
/* --- entry point --- */
int bitcmp ( unsigned char *bs1, unsigned char *bs2, int n )
{
/* --------------------------------------------------------------------------
Allocations and Declarations
-------------------------------------------------------------------------- */
int icmp = 0; /* returned to caller */
int nbytes = n/8, /* #full bytes we can compare with memcmp()*/
nbits = n%8, ibit=0; /* #trailing bits in last byte, index */
/* --------------------------------------------------------------------------
compare leading bytes, then trailing bits
-------------------------------------------------------------------------- */
if ( nbytes > 0 ) icmp = memcmp(bs1,bs2,nbytes); /* compare leading bytes */
if ( icmp == 0 ) /* leading bytes identical */
if ( nbits > 0 ) /* and we have trailing bits */
for ( ibit=0; ibit<nbits; ibit++ ) /* check each bit */
{ icmp = (int)get1bit(bs1[nbytes],ibit) - (int)get1bit(bs2[nbytes],ibit);
if ( icmp != 0 ) break; } /* done at first unmatched bit */
return ( icmp ); /* back to caller with -1,0,+1 */
} /* --- end-of-function bitcmp() --- */
/* --- end-of-file gfuntype.c --- */
|