/* to_pdf.c Rewritten to Ansi-compliant code by Nick Demos, Fall 00 verified 12/00 */ /* Note: If this is saved with a .cpp extension it will compile as C++ Code. The net effect of this is at best negligible, since the code in the file is C code and C++ is a superset of C. Under C++ I can't get UNIX 1 to compile, so if you want the unix features, you should compile with cc or gcc. */ #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 #include #if(UNIX) #include #include #endif #define DATAFILE "data" #define ERRORFILE stderr /* ****************************** Structs ******************************* */ typedef struct _tag_point { double x_coord; double y_coord; } point; /* ***************************** Prototypes ***************************** */ void end_drawing(void); void textprint_small(char text[], point q); void textprint_medium(char text[], point q); void textprint_large(char text[], point q); void logprint(char text[]); void nameprint(char text[]); void escape_print(char text[]); void comment_print(char text[]); void set_clip_region(point p, point q, int N); void make_dot(point p, double dot_size); void set_colors(double red, double green, double blue); void set_gray(double gray_level); void window_advice(point ll, point ur); void begin_drawing(void); void set_width(int width); void line_to(point p); void amove_to(point p); void move_to(point p); void makeline(point p, point q); void include_date_stamp(); void error_1(int N, char in_filename[]); void error_w1(int N); void error_r0(int N); void error_w0(int N); void error_l(int N); void error_l1(int N); void error_d(int N); void error_m(int N); void error_W(int N); void stretch(point p, point *ll, point *ur); void scalepoint_to_window(point *p, point ll, point ur); /* ******************************** Main ********************************/ void main(void) { 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; point lower_left, upper_right, p, q; point farthest_SW, farthest_NE; point r, s; double black = 0.0, white = 1.0; double dot_size; int initial_point; fp_in = stdin; /* Sets the input stream file pointer to 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 '\\'/*escape*/: 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); no_input_errors = 0; break; } if((r.x_coord == s.x_coord) || (r.y_coord == s.y_coord)){ error_w1(N + 1); no_input_errors = 0; } scalepoint_to_window(&r, lower_left, upper_right); scalepoint_to_window(&s, lower_left, upper_right); 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); no_input_errors = 0; } if(black == white){ error_w1(N + 1); 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); 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); no_input_errors = 0; } break; case 'W'/*Width*/: { int width; Q = sscanf(current_line, "W%d", &width); if(Q <= 0){ error_W(N + 1); 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); 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); 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); no_input_errors = 0; break; } stretch(p, &farthest_SW, &farthest_NE); scalepoint_to_window(&p, lower_left, upper_right); move_to(p); break; case 'l'/*line*/: if(!ok_to_draw_line){ error_l1(N + 1); 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); no_input_errors = 0; break; } stretch(p, &farthest_SW, &farthest_NE); scalepoint_to_window(&p, lower_left, upper_right); 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); no_input_errors = 0; break; } stretch(p, &farthest_SW, &farthest_NE); scalepoint_to_window(&p, lower_left, upper_right); 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); no_input_errors = 0; break; } stretch(p, &farthest_SW, &farthest_NE); scalepoint_to_window(&p, lower_left, upper_right); 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; }/* End of switch(current_line[0]) */ N++; }/* End of while(no_input_errors) */ end_drawing(); window_advice(farthest_SW, farthest_NE); }/* End of main() */ /* ***************************** Functions *****************************/ void window_advice(point ll, point 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); } void set_gray(double gray_level) { printf("%4.3f g\n", gray_level); } void set_colors(double red, double green, double 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); } void make_dot(point p, double dot_size) { } void set_clip_region(point p, point q, int N) { } void comment_print(char text[]) { printf(" %%%s\n", text); } void escape_print(char text[]) { printf("%s", text); printf("\n"); } void nameprint(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); } void logprint(char text[]) { } void textprint_large(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"); } void textprint_medium(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"); } void textprint_small(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"); } void end_drawing(void) { 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"); } void begin_drawing(void) { #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()); */ } void set_width(int width) { double x; x = (double)width * (72.0 / 300.0); printf("%2.1f w\n", x); } void line_to(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); } void amove_to(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); } void move_to(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); */ } void makeline(point p, point 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"}; void include_date_stamp() { #if(UNIX) char month[20]; char day[20]; 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, %d ", days[tp->tm_wday], months[tp->tm_mon], tp->tm_mday, 1900+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 } void error_1(int N, char in_filename[]) { fprintf(ERRORFILE, "\nSuccessfully read "); fprintf(ERRORFILE, "%d lines of data from \"%s\"\n", N, in_filename); } void error_w1(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"); } void error_r0(int N) { fprintf(ERRORFILE, "\nRegion error in line %d. Must give four region", N); fprintf(ERRORFILE, " coordinates.\nProgram terminated.\n"); } void error_w0(int N) { fprintf(ERRORFILE, "\nWindow error in line %d. Must give four window", N); fprintf(ERRORFILE, " coordinates.\nProgram terminated.\n"); } void error_l(int N) { fprintf(ERRORFILE, "\nLine error in line %d. Must give two line", N); fprintf(ERRORFILE, " coordinates.\nProgram terminated.\n"); } void error_l1(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"); } void error_d(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"); } void error_m(int N) { fprintf(ERRORFILE, "\nMove error in line %d. Must give two move", N); fprintf(ERRORFILE, " coordinates.\nProgram terminated.\n"); } void error_W(int N) { fprintf(ERRORFILE, "\nWidth error in line %d. Must give a "); fprintf(ERRORFILE, "single integral", N); fprintf(ERRORFILE, " coordinate.\nProgram terminated.\n"); } void stretch(point p, point *ll, point *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; } void scalepoint_to_window(point *p, point ll, point ur) { p->x_coord = (p->x_coord - ll.x_coord) / (ur.x_coord - ll.x_coord); p->y_coord = (p->y_coord - ll.y_coord) / (ur.y_coord - ll.y_coord); }