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