/* to_pdf.c */ #define UNIX 1 /* Change to 0 if compiling on non-unix system. */ /* 8/31/99 As of now very modest. Not much implemented yet. */ /* This program translates a modest graphics language into PDF output. A statement in this language consists of individual ASCII strings separated by newlines, i.e. lines of an ASCII file. The first letter of each command identifies the command; letter may or may not require data following it. After required data, comments can be added, but these will be lost in the` output. There is also an official comment designator, %; comments that start with this character cause PDF comments to be included in the output. Text is possible in three sizes (T, x and t). Line width is given by W, window coordinates by w. `Move' and `line' by m and l. Exact specifications of the commands can be found by reading code that follows `switch' below. For example, w 0.0 0.0 6.0 6 W 7 m 3 2 start at home plate l 4 3 draw line to first base l 3 4 draw line to second base l 2 3 draw line to third base l 3 2 draw line to home plate m 4.5 3 TFirst base makes the beginnings of a baseball diamond, with first base labeled in the picture. The words following the `l' and `m' commands are comments for the convenience of the user, and will not appear in output. For explanation at greater length, see Chapter 2 of `The geometry of Computer Graphics,' by Walter Taylor, to be published in 1991 by Wadsworth-Brooks-Cole. A few commands not described there have been added here, such as C for color, N for the name of the picture, \ for escapes (i.e. the direct inclusion of PS), d for dots, and z for inserting remarks into the ps printer's output file (the log file). See the corresponding cases below. (in fact, PDF was invented after the book was written. However, the general drift is clear from the book's discussion of postscript. This in fact is a modification of the book's program that converts to .ps) When used on a unix system, the steps are as follows. On another system, such as a PC, the steps would be slightly different, of course. You do _not_ need to have the header file coords.h in the same directory. (I included the definition of point in this file.) cc -o draw thisfile.c draw < data > picture pdf picture possible bug: doesn't like a blank line at start of data wtaylor@euclid.colorado.edu 9/99 */ #include #include #if(UNIX) #include #include #endif typedef struct { double x_coord; double y_coord; } point; #define DATAFILE "data" #define ERRORFILE stderr main() { int no_input_errors = 1; int ok_to_draw_line = 0; int N,Q; char in_filename[50], out_filename[50]; char text[100]; char current_line[100]; FILE *fp_in; int fclose(); point lower_left, upper_right, p, q, ttimes(); point farthest_SW, farthest_NE; point r, s; double black=0.0, white=1.0; double dot_size; int initial_point; fp_in = stdin; strcpy(in_filename,"standard input"); lower_left.x_coord = 0.0; lower_left.y_coord = 0.0; upper_right.x_coord = 1.0; upper_right.y_coord = 1.0; farthest_NE.x_coord = -1.0E12; farthest_NE.y_coord = -1.0E12; farthest_SW.x_coord = 1.0E12; farthest_SW.y_coord = 1.0E12; begin_drawing(); N=0; while (no_input_errors) { q = p; if (N>0) { Q = fscanf(fp_in,"\n"); } Q = fscanf(fp_in,"%[^\n]",current_line); if (Q <= 0) {error_1(N,in_filename); break;} switch(current_line[0]) { case '%'/*comment*/: /* this is hardly needed any more fprintf(ERRORFILE,"Line %d treated as comment.\n",N+1) ; */ Q = sscanf(current_line,"%*c%[^\n]",text); comment_print(text); break; case '\\'/*esape*/: Q = sscanf(current_line,"\\%[^\n]",text); escape_print(text); break; case 'N'/*Name of picture*/: Q = sscanf(current_line,"N%[^\n]",text); nameprint(text); break; case 't'/*text, small*/: Q = sscanf(current_line,"t%[^\n]",text); textprint_small(text,q); break; case 'x'/*text, medium*/: Q = sscanf(current_line,"x%[^\n]",text); textprint_medium(text,q); break; case 'T'/*text, large*/: Q = sscanf(current_line,"T%[^\n]",text); textprint_large(text,q); break; case 'z'/* insert comment in log file */: Q = sscanf(current_line,"z%[^\n]",text); logprint(text); break; case 'r'/*clip region*/: Q = sscanf(current_line,"r%lf%lf%lf%lf", &r.x_coord,&r.y_coord, &s.x_coord,&s.y_coord); if (Q <= 3) {error_r0(N+1,in_filename); no_input_errors=0; break;} if ( (r.x_coord==s.x_coord) || (r.y_coord==s.y_coord)) {error_w1(N+1,in_filename); no_input_errors=0;} r.x_coord = (r.x_coord-lower_left.x_coord) / (upper_right.x_coord-lower_left.x_coord); r.y_coord = (r.y_coord-lower_left.y_coord) / (upper_right.y_coord-lower_left.y_coord); s.x_coord = (s.x_coord-lower_left.x_coord) / (upper_right.x_coord-lower_left.x_coord); s.y_coord = (s.y_coord-lower_left.y_coord) / (upper_right.y_coord-lower_left.y_coord); set_clip_region(r,s,N+1); break; case 'G'/*extremes of gray scale; black then white*/: Q = sscanf(current_line,"G%lf%lf", &black,&white); if (Q <= 1) {error_w0(N+1,in_filename); no_input_errors=0;} if (black==white) {error_w1(N+1,in_filename); no_input_errors=0;} break; case 'w'/*window*/: Q = sscanf(current_line,"w%lf%lf%lf%lf", &lower_left.x_coord,&lower_left.y_coord, &upper_right.x_coord,&upper_right.y_coord); if (Q <= 3) {error_w0(N+1,in_filename); no_input_errors=0;} if ( (lower_left.x_coord==upper_right.x_coord) || (lower_left.y_coord==upper_right.y_coord)) {error_w1(N+1,in_filename); no_input_errors=0;} break; case 'W'/*Width*/: { int width; Q = sscanf(current_line,"W%d",&width); if (Q <= 0) {error_W(N+1,in_filename); no_input_errors=0; break;} set_width(width); } break; case 'g'/*gray_level*/: { double gray_level; Q = sscanf(current_line,"g%lf",&gray_level); if (Q <= 0) {error_W(N+1,in_filename); no_input_errors=0; break;} gray_level = (gray_level - black)/(white - black); if (gray_level<=0.0) gray_level = 0.0; if (gray_level>=1.0) gray_level = 1.0; set_gray(gray_level); } break; case 'C'/*color */: { double red, green, blue; Q = sscanf(current_line,"C%lf %lf %lf", &red,&green,&blue); if (Q <= 2) {error_W(N+1,in_filename); no_input_errors=0; break;} set_colors(red,green,blue); } break; case 'm'/*move*/: ok_to_draw_line = 1; Q = sscanf(current_line,"m%lf%lf",&p.x_coord, &p.y_coord); if (Q <= 1) {error_m(N+1,in_filename); no_input_errors=0; break;} stretch(p,&farthest_SW,&farthest_NE); p.x_coord = (p.x_coord-lower_left.x_coord) / (upper_right.x_coord-lower_left.x_coord); p.y_coord = (p.y_coord-lower_left.y_coord) / (upper_right.y_coord-lower_left.y_coord); move_to(p); break; case 'l'/*line*/: if (!ok_to_draw_line){error_l1(N+1,in_filename ); no_input_errors=0; break;} Q = sscanf(current_line,"l%lf%lf",&p.x_coord, &p.y_coord); if (Q <= 1) {error_l(N+1,in_filename); no_input_errors=0; break;} stretch(p,&farthest_SW,&farthest_NE); p.x_coord = (p.x_coord-lower_left.x_coord) / (upper_right.x_coord-lower_left.x_coord); p.y_coord = (p.y_coord-lower_left.y_coord) / (upper_right.y_coord-lower_left.y_coord); makeline(p,q); break; case 'd'/*dot*/: Q = sscanf(current_line,"d%lf%lf%lf",&p.x_coord, &p.y_coord,&dot_size); if (Q < 3) {error_d(N+1,in_filename); no_input_errors=0; break;} stretch(p,&farthest_SW,&farthest_NE); p.x_coord = (p.x_coord-lower_left.x_coord) / (upper_right.x_coord-lower_left.x_coord); p.y_coord = (p.y_coord-lower_left.y_coord) / (upper_right.y_coord-lower_left.y_coord); make_dot(p,dot_size); break; case 'P': /* path (to be filled) */ initial_point = 1; break; case 'L': /* point in path */ Q = sscanf(current_line,"L%lf%lf",&p.x_coord,&p.y_coord); if (Q <= 1) {error_l(N+1,in_filename); no_input_errors=0; break;} stretch(p,&farthest_SW,&farthest_NE); p.x_coord = (p.x_coord-lower_left.x_coord) / (upper_right.x_coord-lower_left.x_coord); p.y_coord = (p.y_coord-lower_left.y_coord) / (upper_right.y_coord-lower_left.y_coord); if (initial_point) amove_to(p); else line_to(p); initial_point = 0; break; case 'q': /* terminate and fill path */ printf("f\n"); break; case 'Q': /* terminate, fill path, and stroke */ printf("b\n"); break; default: fprintf(ERRORFILE,"Data of unknown type in line "); fprintf(ERRORFILE,"%d; ignored up to newline.\n",N+1); break; } N++; } fclose(fp_in); end_drawing(); window_advice(farthest_SW,farthest_NE); } window_advice(ll,ur) point ll, ur; { double vertical, horizontal; printf("%%\n%%The minimal window command would be:\n%%\n"); printf("%%w %4.3f %4.3f %4.3f %4.3f\n", ll.x_coord, ll.y_coord, ur.x_coord, ur.y_coord); horizontal = ur.x_coord - ll.x_coord; vertical = ur.y_coord - ll.y_coord; if (horizontal > vertical) { ur.y_coord += (horizontal - vertical)/2; ll.y_coord -= (horizontal - vertical)/2; } else { ur.x_coord += (vertical - horizontal)/2; ll.x_coord -= (vertical - horizontal)/2; } printf("%%\n%%And the minimal square window command would be:\n%%\n"); printf("%%w %4.3f %4.3f %4.3f %4.3f\n", ll.x_coord, ll.y_coord, ur.x_coord, ur.y_coord); } set_gray(gray_level) double gray_level; { printf("%4.3f g\n",gray_level); } set_colors(red,green,blue) double red, green, blue; { if ( (red < 0.0) || (green < 0.0) || (blue < 0.0) || (red > 1.0) || (green > 1.0) || (blue > 1.0)) fprintf(ERRORFILE,"Warning: Color value out of range.\n"); printf("%3.3f %3.3f %3.3f rg\n",red,green,blue); } make_dot(p,dot_size) point p; double dot_size; { } set_clip_region(p,q,N) point p, q; int N; { } comment_print(text) char text[]; { printf(" %%%s\n",text); } escape_print(text) char text[]; { printf("%s",text); printf("\n"); } nameprint(text) char text[]; { point p; printf("\t%%Picture name: "); printf("%s\n",text); p.x_coord = .35; p.y_coord = -.15; move_to(p); textprint_large(text,p); } logprint(text) char text[]; { } textprint_large(text,q) char text[]; point q; { double i, j; i = (q.x_coord * 72)*8.5; j = ((q.y_coord * 8.5) + 2.5) *72; printf("BT\n /F1 18 Tf\n"); printf("1 0 0 1 %3.1f %3.1f Tm\n",i,j); printf("("); printf("%s",text); printf(")Tj\nET\n"); } textprint_medium(text,q) char text[]; point q; { double i, j; i = (q.x_coord * 72)*8.5; j = ((q.y_coord * 8.5) + 2.5) *72; printf("BT\n /F1 14 Tf\n"); printf("1 0 0 1 %3.1f %3.1f Tm\n",i,j); printf("("); printf("%s",text); printf(")Tj\nET\n"); } textprint_small(text,q) char text[]; point q; { double i, j; i = (q.x_coord * 72)*8.5; j = ((q.y_coord * 8.5) + 2.5) *72; printf("BT\n /F1 10 Tf\n"); printf("1 0 0 1 %3.1f %3.1f Tm\n",i,j); printf("("); printf("%s",text); printf(")Tj\nET\n"); } end_drawing() { printf("endstream\n"); printf("endobj\n\n"); printf("3 0 obj\n"); printf("<< \n"); printf("/ProcSet [ /PDF /Text ] \n"); printf("/Font << /F1 4 0 R >> \n"); printf(">> \n"); printf("endobj\n\n"); printf("4 0 obj\n"); printf("<< \n"); printf("/Type /Font \n"); printf("/Subtype /Type1 \n"); printf("/Name /F1 \n"); printf("/BaseFont /Helvetica \n"); printf(">> \n"); printf("endobj\n\n"); printf("5 0 obj\n"); printf("<< \n"); printf("/Type /Pages \n"); printf("/Kids [ 1 0 R ] \n"); printf("/Count 1 \n"); printf("/MediaBox [ 0 0 612 792 ] \n"); printf(">> \n"); printf("endobj\n\n"); printf("6 0 obj\n"); printf("<< \n"); printf("/Type /Catalog \n"); printf("/Pages 5 0 R \n"); printf(">> \n"); printf("endobj\n\n"); printf("trailer\n"); printf("<<\n"); printf("/Root 6 0 R \n"); printf(">>\n"); } begin_drawing() { #if(UNIX) char *getlogin(); #endif printf("%%PDF-1.2\n"); include_date_stamp(); printf("1 0 obj\n"); printf("<< \n"); printf(" /Type /Page \n"); printf(" /Parent 5 0 R \n"); printf(" /Resources 3 0 R \n"); printf(" /Contents 2 0 R \n"); printf(">> \n"); printf("endobj\n\n"); printf("2 0 obj\n"); printf("<< /Length 51 >> \n"); printf("stream\n"); /* printf(" by %s",getlogin()); */ } set_width(width) int width; { double x; x = ((double) width)*(72.0/300.0); printf("%2.1f w\n",x); } line_to(p) point p; { double i, j; i = (p.x_coord * 72)*8.5; j = ((p.y_coord * 8.5) + 2.5) *72; printf("%3.1f %3.1f l\n", i, j); } amove_to(p) point p; { double i, j; i = (p.x_coord * 72)*8.5; j = ((p.y_coord * 8.5) + 2.5) *72; printf("%3.1f %3.1f m\n", i, j); } move_to(p) point p; { double i, j; i = (p.x_coord * 72)*8.5; j = ((p.y_coord * 8.5) + 2.5) *72; /* printf("%3.1f %3.1f m\n", i, j); */ } makeline(p,q) point p, q; { double i, j, k, l; k = (p.x_coord * 72)*8.5; l = ((p.y_coord * 8.5) + 2.5) *72; i = (q.x_coord * 72)*8.5; j = ((q.y_coord * 8.5) + 2.5) *72; printf("%3.1f %3.1f m\n", i, j); printf("%3.1f %3.1f l\n", k, l); printf("S\n"); } char months[12][20] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; char days[7][20] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; include_date_stamp() { char month[20]; char day[20]; #if(UNIX) char *getlogin(); struct tm *localtime(), *tp; struct timeval tv; struct timezone tz; printf("%% This is a PDF file that was made"); printf(" by translating a\n"); printf("%% device-independent graphics file in the manner"); printf(" described in section\n"); printf("%% 2.3.1 of W. Taylor's \"The Geometry of Computer"); printf(" Graphics,\" Wadsworth &\n"); printf("%% Brooks/Cole, 1991. ISBN 0-534-17100-1\n"); printf("%%\n"); printf("%% The translation was made by %s on\n",getlogin()); gettimeofday(&tv, &tz); tp = localtime(&tv.tv_sec); printf("%%\n"); printf("%% %s, %s %d, 19%d ", days[tp->tm_wday], months[tp->tm_mon], tp->tm_mday, tp->tm_year); if (tp->tm_hour==0) printf(" %d:%d AM \n", 12 ,tp->tm_min); if (tp->tm_hour<12) printf(" %d:%d AM \n",tp->tm_hour,tp->tm_min); if (tp->tm_hour==12) printf(" %d:%d PM \n", 0 ,tp->tm_min); if (tp->tm_hour>12) printf(" %d:%d PM \n",tp->tm_hour -12,tp->tm_min); printf("%% \n"); #endif } error_1(N,in_filename) int N; char in_filename[]; { fprintf(ERRORFILE,"\nSuccessfully read "); fprintf(ERRORFILE,"%d lines of data from \"%s\"\n",N,in_filename); } error_w1(N) int N; { fprintf(ERRORFILE,"\nWindow error in line %d. Window must have "); fprintf(ERRORFILE,"non-zero",N); fprintf(ERRORFILE," width and height.\nProgram terminated.\n"); } error_r0(N) int N; { fprintf(ERRORFILE,"\nRegion error in line %d. Must give four region", N); fprintf(ERRORFILE," coordinates.\nProgram terminated.\n"); } error_w0(N) int N; { fprintf(ERRORFILE,"\nWindow error in line %d. Must give four window" ,N); fprintf(ERRORFILE," coordinates.\nProgram terminated.\n"); } error_l(N) int N; { fprintf(ERRORFILE,"\nLine error in line %d. Must give two line",N); fprintf(ERRORFILE," coordinates.\nProgram terminated.\n"); } error_l1(N) int N; { fprintf(ERRORFILE,"\nError in line %d. You cannot draw a line",N); fprintf(ERRORFILE," until you have moved at least once.\n"); fprintf(ERRORFILE,"Program terminated.\n"); } error_d(N) int N; { fprintf(ERRORFILE,"\nDot error in line %d. Must give two dot",N); fprintf(ERRORFILE," coordinates\n\t\t\tand one dot radius.\n"); fprintf(ERRORFILE,"Program terminated.\n"); } error_m(N) int N; { fprintf(ERRORFILE,"\nMove error in line %d. Must give two move",N); fprintf(ERRORFILE," coordinates.\nProgram terminated.\n"); } error_W(N) int N; { fprintf(ERRORFILE,"\nWidth error in line %d. Must give a "); fprintf(ERRORFILE,"single integral",N); fprintf(ERRORFILE," coordinate.\nProgram terminated.\n"); } stretch(p,ll,ur) point p, *ll, *ur; { if (ll->x_coord > p.x_coord) ll->x_coord = p.x_coord; if (ll->y_coord > p.y_coord) ll->y_coord = p.y_coord; if (ur->x_coord < p.x_coord) ur->x_coord = p.x_coord; if (ur->y_coord < p.y_coord) ur->y_coord = p.y_coord; }