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