1*17919Sslatteng /*	scalech.c	1.6	85/02/04
215628Sslatteng  *
315679Sslatteng  * Font scaling for character format fonts.
415679Sslatteng  *
517885Sslatteng  *	Use:	scalech  [ -s# ]  [ charfile1 ]  > charfile2
615628Sslatteng  *
715628Sslatteng  *		Takes input from charfile1 (which must be in the format
817885Sslatteng  *	written by any of the xxx2ch programs), scales by # (default = 50%)
917885Sslatteng  *	and writes to stdout.  If charfile1 is missing, stdin is read.  The
1017885Sslatteng  *	-s flag sets the scaling factor to # (which is a percentage REDUCTION:
1117885Sslatteng  *	scalech can't make fonts bigger)
1215628Sslatteng  */
1315628Sslatteng 
1415628Sslatteng #include <stdio.h>
1515628Sslatteng 
1615628Sslatteng 
1717885Sslatteng #define MAXLINE		300
1817885Sslatteng #define MAXHEIGHT	300
1915628Sslatteng #define SCALE		50
2015628Sslatteng 
2117885Sslatteng 					/* don't ask, really */
2215679Sslatteng int	width, length, vdest, hdest, code;
2315806Sslatteng int	refv, refh, spot, start, Bduring, Wduring;
24*17919Sslatteng int	notfirsttime, build, refvdest, refhdest, destwidth;
2515628Sslatteng 
26*17919Sslatteng int	scale = SCALE;		/* percentage to scale by (in 100's) */
27*17919Sslatteng int	hscale;			/* half scale value:  used in computations */
2815628Sslatteng FILE *	filep;
2915806Sslatteng char	ibuff[MAXHEIGHT][MAXLINE], ebuff[MAXLINE];
3015628Sslatteng 
3115806Sslatteng unsigned char lastline[MAXLINE];	/* last printed line */
3215806Sslatteng unsigned char Black[2][MAXLINE];	/* arrays to figure new */
3315806Sslatteng unsigned char WtoB[2][MAXLINE];		/* scaled line based on */
3415806Sslatteng unsigned char BtoW[2][MAXLINE];		/* pixels within lines */
3515806Sslatteng unsigned char White[2][MAXLINE];
3615628Sslatteng 
3715679Sslatteng 
main(argc,argv)3815628Sslatteng main(argc,argv)
3915628Sslatteng int argc;
4015628Sslatteng char **argv;
4115628Sslatteng {
4215628Sslatteng     register int i;
4315628Sslatteng     register int j;
4415628Sslatteng     register char *chp;
4515628Sslatteng     float par;
4615628Sslatteng 
4715628Sslatteng     while (argc > 1 && argv[1][0] == '-') {
4815628Sslatteng 	switch(argv[1][1]) {
4915628Sslatteng 	case 's':
5015628Sslatteng 		scale = atoi (&(argv[1][2]));
5115628Sslatteng 		break;
5215628Sslatteng 	default:
5315628Sslatteng 		error("%s, unknown option flag", argv[1]);
5415628Sslatteng 	}
5515628Sslatteng 	argc--; argv++;
5615628Sslatteng     }
5715628Sslatteng 
5815628Sslatteng     if (argc == 2) {
5915628Sslatteng 	if ((filep = fopen (argv[1], "r")) == NULL)
6015628Sslatteng 	    error("can't open file \"%s\"", argv[1]);
6115628Sslatteng     } else filep = stdin;
6215628Sslatteng 
63*17919Sslatteng     hscale = scale / 2;
6415628Sslatteng     fgets(ibuff, MAXLINE, filep);
6516381Sslatteng     if (strcmp(ibuff, "fontheader\n"))
6615628Sslatteng 	error("not a character font file");
6716381Sslatteng     printf("fontheader\n");
6815628Sslatteng 
6915628Sslatteng     while (fgets(ibuff, MAXLINE, filep) != NULL) {
7015628Sslatteng 	if (index(ibuff, '\n') == 0)
7115628Sslatteng 	    error("input line too long");
7215628Sslatteng 
7315806Sslatteng 	if (ibuff[0][0] != ':') {
7415628Sslatteng 	    sscanf (ibuff, "%s %f", ebuff, &par);
7515628Sslatteng 	    if (strcmp(ebuff, "mag") == 0)
7617885Sslatteng 		printf("mag %d\n", (int) (par * scale / 100.0 + 0.1));
7715628Sslatteng 	    else if (strcmp(ebuff, "linesp") == 0)
7817885Sslatteng 		printf("linesp %.2f\n", par * scale / 100.0 + 0.001);
7915628Sslatteng 	    else if (strcmp(ebuff, "wordsp") == 0)
8017885Sslatteng 		printf("wordsp %.2f\n", par * scale / 100.0 + 0.001);
8115628Sslatteng 	    else
8215628Sslatteng 		printf("%s", ibuff);
8315628Sslatteng 	} else {
8415628Sslatteng 	    if (sscanf (ibuff, ":%d, width = %f", &code, &par) != 2)
8515628Sslatteng 		error("bad glyph header, %s", ibuff);
8615628Sslatteng 	    printf(":%d, width = %.2f\n", code, (par * scale) / 100.0 + 0.001);
8715628Sslatteng 
8815628Sslatteng 	    if (fgets(ibuff, MAXLINE, filep) == NULL)
8915628Sslatteng 		error("unexpected end of input");
9015806Sslatteng 	    width = strlen(&(ibuff[0][0])) - 1;
9115806Sslatteng 						/* first read in whole glyph */
9215806Sslatteng 	    refh = -1;				/* and put in ibuff */
9315806Sslatteng 	    for (length = 0; *(chp = &(ibuff[length][0])) != '\n'; length++) {
94*17919Sslatteng 		for (j = 0; j <= width; j++, chp++) {
9515806Sslatteng 		    switch (*chp) {
9615806Sslatteng 			case '@':
9715806Sslatteng 			case '*':
9815806Sslatteng 				*chp = 1;
9915806Sslatteng 				break;
10015806Sslatteng 			case '.':
101*17919Sslatteng 			case '\n':
102*17919Sslatteng 			case '\r':
10315806Sslatteng 				*chp = 0;
10415806Sslatteng 				break;
10515806Sslatteng 			case 'x':
10615806Sslatteng 				*chp = 0;
10715806Sslatteng 				goto mark;
10815806Sslatteng 			case 'X':
10915806Sslatteng 				*chp = 1;
11015806Sslatteng 		mark:		if (refh >= 0)
11115806Sslatteng 				    error ("glyph %d - two reference points",
11215806Sslatteng 									code);
113*17919Sslatteng 				refh = j;
11415806Sslatteng 				refv = length;
11515806Sslatteng 				break;
11615806Sslatteng 			default:
11715806Sslatteng 				error("illegal character '%c' in map.", *chp);
11815806Sslatteng 		    }
11915806Sslatteng 		}
12015806Sslatteng 		if (fgets(&(ibuff[length + 1][0]), MAXLINE, filep) == NULL)
12115806Sslatteng 			error("unexpected end of input");
12215806Sslatteng 	    }
12315806Sslatteng 	    if (refh < 0) error("No position point in glyph %d", code);
12415628Sslatteng 
12515806Sslatteng 
126*17919Sslatteng 	    refvdest = (refv * scale + hscale) / 100;
127*17919Sslatteng 	    refhdest = (refh * scale - hscale) / 100 + (refh ? 2 : 1);
128*17919Sslatteng 	    destwidth = refhdest + ((width - refh) * scale - hscale) / 100;
12915806Sslatteng 	    vdest = 0;
13015806Sslatteng 	    notfirsttime = 0;
131*17919Sslatteng 	    build = 0;
13215806Sslatteng 	    for (j = 0; j <= width; j++)
133*17919Sslatteng 		Black[build][j] = BtoW[build][j] = WtoB[build][j] =
134*17919Sslatteng 		    White[build][j] = lastline[j] = 0;
13515806Sslatteng 
13615806Sslatteng 	    for (i = 0; i < length; i++) {
13715806Sslatteng 		chp = &(ibuff[i][0]);
13815806Sslatteng 		hdest = 1;
13915679Sslatteng 		start = 0;
14015679Sslatteng 		Bduring = 0;
14115679Sslatteng 		Wduring = 0;
14215806Sslatteng 		White[build][0]++;
143*17919Sslatteng 		for (j = 0; j <= width; j++, chp++) {
144*17919Sslatteng 		    code = ((j-refh)*scale+hscale)/100+refhdest-((j<refh)?1:0);
14515806Sslatteng 		    if (hdest != code) {
14615806Sslatteng 			if ((start && !Wduring) ||
14715806Sslatteng 			    ((!start)&& Bduring &&!spot)) Black[build][hdest]++;
14815806Sslatteng 			if (start && !spot) BtoW[build][hdest]++;
14915806Sslatteng 			if ((!start) && spot) WtoB[build][hdest]++;
15015806Sslatteng 			if (((!start) && !Bduring) ||
15115806Sslatteng 			    (start && Wduring && spot)) White[build][hdest]++;
15215679Sslatteng 
15315806Sslatteng 			hdest = code;
15415679Sslatteng 			start = spot;
15515679Sslatteng 			Bduring = 0;
15615679Sslatteng 			Wduring = 0;
15715679Sslatteng 		    }
15815806Sslatteng 
15915806Sslatteng 		    spot = *chp;
16015679Sslatteng 		    Bduring |= spot;
16115679Sslatteng 		    Wduring |= !spot;
16215628Sslatteng 		} /* for j */
16315679Sslatteng 
16415806Sslatteng 		if ((start && !Wduring)
16515806Sslatteng 		    || ((!start) && Bduring)) Black[build][hdest]++;
16615806Sslatteng 		if (start) BtoW[build][hdest]++;
16715806Sslatteng 		if ((!start) && !Bduring) White[build][hdest]++;
168*17919Sslatteng 				/* look at what line we're gonna build for NEXT
169*17919Sslatteng 				   and if that's different than what we WERE
170*17919Sslatteng 				   building for, output the line BEFORE that */
171*17919Sslatteng 		code = refvdest+((i>=refv)?1:0)-((refv-(i+1))*scale+hscale)/100;
17215806Sslatteng 		if (code != vdest || i == (length - 1)) {
17315806Sslatteng 		    if (notfirsttime)
174*17919Sslatteng 			outline(vdest == (refvdest + 1));
17515806Sslatteng 		    else
17615806Sslatteng 			notfirsttime = 1;
17715806Sslatteng 		    vdest = code;
17815628Sslatteng 
17915806Sslatteng 		    build = !build;
18015679Sslatteng 		    for (j = 0; j <= width; j++)
18115806Sslatteng 			Black[build][j] = BtoW[build][j] =
18215806Sslatteng 				WtoB[build][j] = White[build][j] = 0;
18315628Sslatteng 		}
18415806Sslatteng 	    } /* for i */
18515806Sslatteng 
18615806Sslatteng 	    for (j = 0; j <= width; j++) White[build][j] = 1;
187*17919Sslatteng 	    outline(refv == length - 1);	/* output last line - ref */
188*17919Sslatteng 	    putchar('\n');			/* point only if it's on the */
189*17919Sslatteng 	} /* else */				/* last line of the block */
19015628Sslatteng     } /* while */
191*17919Sslatteng     exit(0);
19215628Sslatteng }
19315628Sslatteng 
19417885Sslatteng 
195*17919Sslatteng #define	upleft	(lastline[j-1])
196*17919Sslatteng #define	up	(lastline[j])
197*17919Sslatteng #define	upright	(lastline[j+1])
198*17919Sslatteng 
19917885Sslatteng /*----------------------------------------------------------------------------*
20017885Sslatteng  | Routine:	outline (baseline)
20117885Sslatteng  |
20217885Sslatteng  | Results:	outputs a row of dots, based on gobs of information gathered
20317885Sslatteng  |		in the main program.  If "baseline" is set, then this line
20417885Sslatteng  |		should have the reference point on it.
20517885Sslatteng  |
20617885Sslatteng  | Bugs:	this method smells
20717885Sslatteng  *----------------------------------------------------------------------------*/
20817885Sslatteng 
outline(baseline)20917885Sslatteng outline(baseline)
21017885Sslatteng int baseline;
21115806Sslatteng {
21215806Sslatteng 	register int set;
21315806Sslatteng 	register int output = !build;
21415806Sslatteng 	register int j;
215*17919Sslatteng 	register int left = 0;
216*17919Sslatteng 	int right, down, downright, downleft;
21715628Sslatteng 
218*17919Sslatteng 	for (j = 1; j <= destwidth; j++) {
21915806Sslatteng 					/* decide whether to put out a '.' */
22015806Sslatteng 					/* or '@' spot for pixel j */
221*17919Sslatteng 	    right = Black[output][j+1] || WtoB[output][j+1];
222*17919Sslatteng 	    downleft = Black[build][j-1] || WtoB[build][j-1];
223*17919Sslatteng 	    down = Black[build][j] || WtoB[build][j];
224*17919Sslatteng 	    downright = Black[build][j+1] || WtoB[build][j+1];
225*17919Sslatteng 
226*17919Sslatteng 	    set = ((!BtoW[output][j]) << 3) | ((!WtoB[output][j]) << 2) |
22715806Sslatteng 			((!White[output][j]) << 1) | !Black[output][j];
228*17919Sslatteng 	    switch (set) {
22915806Sslatteng 		case 14:	/* all black */
23015806Sslatteng 		case 11:	/* all white->black */
23115806Sslatteng 		case 10:	/* black and white->black */
23215806Sslatteng 		case  2:	/* everything but all white */
23315806Sslatteng 		    set = 1;
23415806Sslatteng 		    break;
23515806Sslatteng 
23615806Sslatteng 		case 13:	/* all white */
23715806Sslatteng 		case  7:	/* all black->white */
23815806Sslatteng 		case  5:	/* white and black->white */
239*17919Sslatteng 		case  1:	/* everything but all black */
24015806Sslatteng 		    set = 0;
24115806Sslatteng 		    break;
24215806Sslatteng 
243*17919Sslatteng 		case 12:	/* black and white */
24415806Sslatteng 		case  8:	/* black and white and white->black */
24515806Sslatteng 		case  4:	/* black and white and black->white */
246*17919Sslatteng 		    if (down)
24715806Sslatteng 			set = !lastline[j];
24815806Sslatteng 		    else
24915806Sslatteng 			set = 1;
25015806Sslatteng 		    break;
25115806Sslatteng 
25215806Sslatteng 		case  6:	/* black and black->white */
253*17919Sslatteng 		    if (right && upright && downright && (down || up))
25415806Sslatteng 			set = 0;
25515806Sslatteng 		    else
25615806Sslatteng 			set = 1;
25715806Sslatteng 		    break;
25815806Sslatteng 
25915806Sslatteng 		case  9:	/* white and white->black */
260*17919Sslatteng 		    if ((up && upright) || (down && downright) || left || right)
26115806Sslatteng 			set = 1;
26215806Sslatteng 		    else
26315806Sslatteng 			set = 0;
26415806Sslatteng 		    break;
26515806Sslatteng 
26615806Sslatteng 		case 15:	/* none of them */
26715806Sslatteng 		case  3:	/* black->white and white->black */
26815806Sslatteng 		case  0:	/* everything */
269*17919Sslatteng 		    if((up+down+right+left+upright+downleft+upleft+downright)>4)
27015806Sslatteng 			set = 0;
27115806Sslatteng 		    else
27215806Sslatteng 			set = 1;
27315806Sslatteng 		    break;
27415806Sslatteng 		}
27515806Sslatteng 
27615806Sslatteng 		if (set)  {
277*17919Sslatteng 		    if (!baseline || j != refhdest)
27815806Sslatteng 			putchar('@');
27915806Sslatteng 		    else
28015806Sslatteng 			putchar('X');
28115806Sslatteng 		} else {
282*17919Sslatteng 		    if (!baseline || j != refhdest)
28315806Sslatteng 			putchar('.');
28415806Sslatteng 		    else
28515806Sslatteng 			putchar('x');
28615806Sslatteng 		}
287*17919Sslatteng 		lastline[j-1] = left;
288*17919Sslatteng 		left = set;
28915806Sslatteng 	}
290*17919Sslatteng 	lastline[j-1] = left;
29115806Sslatteng 	putchar('\n');
29215806Sslatteng }
29315806Sslatteng 
29417885Sslatteng 
29517885Sslatteng /*----------------------------------------------------------------------------*
29617885Sslatteng  | Routine:	error (format_string, argument1, argument2.... )
29717885Sslatteng  |
29817885Sslatteng  | Results:	fprints a message to standard error, then exits with error
29917885Sslatteng  |		code 1.
30017885Sslatteng  |
30117885Sslatteng  | Side Efct:	This routine does NOT return
30217885Sslatteng  *----------------------------------------------------------------------------*/
30317885Sslatteng 
30415628Sslatteng /*VARARGS1*/
error(string,a1,a2,a3,a4)30515628Sslatteng error(string, a1, a2, a3, a4)
30615628Sslatteng char *string;
30715628Sslatteng {
30815806Sslatteng 	fprintf(stderr, "scalech: ");
30915628Sslatteng 	fprintf(stderr, string, a1, a2, a3, a4);
31015628Sslatteng 	fprintf(stderr, "\n");
31117885Sslatteng 	exit (1);
31217885Sslatteng }
313