|
- /**************************************************************************
- This ugly, sparsely-commented program is the source for text2pdf version
- 1.1. It should be ANSI-conforming and compile on most platforms. You'll
- need to change LF_EXTRA to 1 for machines which write 2 characters for \n.
- These include PCs, of course.
-
- You may distribute the source or compiled versions free of charge. You may
- not alter the source in any way other than those mentioned above without
- the permission of the author, Phil Smith <phil@bagobytes.co.uk>.
-
- Please send any comments to the author.
-
- Copyright (c) Phil Smith, 1996
-
- REVISION HISTORY
-
- Version 1.1
- 11 Oct 96 Added handling of form-feed characters, removed need for tmp file,
- put reference to resources in each page (avoid bug in Acrobat),
- changed date format to PDF-1.1 standard.
- 12 Jun 96 Added check to avoid blank last page
- 12 Jun 96 Added LINE_END def to get round platform-specific \r, \n etc.
- 18 Mar 96 Added ISOLatin1Encoding option
- **************************************************************************/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
-
- #ifndef SEEK_SET
- #define SEEK_SET 0
- #endif
-
- #define LF_EXTRA 0 /* how many extra characters are written for \n */
- /* change to 1 for PCs (where \n => <CR><LF>) */
-
- #define LINE_END '\015' /* CR used in xref table */
- #define FF 12 /* formfeed character (^L) */
-
- char *appname = "text2pdf v1.1";
- char *progname = "text2pdf";
-
- FILE *infile;
- int pageNo = 0;
- int pageObs[500];
- int curObj = 5; /* object number being or last written */
- long locations[1000];
-
- char font[256];
- char *defaultFont = "Courier";
- int ISOEnc = 0;
- int doFFs = 1;
- int tab = 8;
- int pointSize = 10;
- int vertSpace = 12;
- int lines = 0;
- int cols = 80; /* max chars per output line */
- int columns = 1; /* number of columns */
-
- /* Default paper is Letter size, as in distiller */
- int pageHeight = 792;
- int pageWidth = 612;
-
- unsigned char buf[1024];
- unsigned long fpos = 0;
-
- void writestr(char *str) {
- /* Everything written to the PDF file goes through this function. */
- /* This means we can keep track of the file position without using */
- /* ftell on a real (tmp) file. However, PCs write out 2 characters */
- /* for \n, so we need this ugly loop to keep fpos correct */
-
- fpos += strlen(str);
- while (*str) {
- if (*str == '\n') fpos += LF_EXTRA;
- putchar(*str++);
- }
- }
-
-
- void WriteHeader(char *title){
-
- struct tm *ltime;
- time_t clock;
- char datestring[30];
-
- time(&clock);
- ltime = localtime(&clock);
-
- strftime(datestring, 30, "D:%Y%m%d%H%M%S", ltime);
-
- writestr("%PDF-1.1\n");
- locations[1] = fpos;
- writestr("1 0 obj\n");
- writestr("<<\n");
- sprintf(buf, "/CreationDate (%s)\n", datestring); writestr(buf);
- sprintf(buf, "/Producer (%s (\\251 Phil Smith, 1996))\n", appname); writestr(buf);
- if (title) {sprintf(buf, "/Title (%s)\n", title); writestr(buf);}
- writestr(">>\n");
- writestr("endobj\n");
-
- locations[2] = fpos;
- writestr("2 0 obj\n");
- writestr("<<\n");
- writestr("/Type /Catalog\n");
- writestr("/Pages 3 0 R\n");
- writestr(">>\n");
- writestr("endobj\n");
-
- locations[4] = fpos;
- writestr("4 0 obj\n");
- writestr("<<\n");
- writestr("/Type /Font\n");
- writestr("/Subtype /Type1\n");
- writestr("/Name /F1\n");
- sprintf(buf, "/BaseFont %s\n", font); writestr(buf);
- if (ISOEnc) {
- writestr("/Encoding <<\n");
- writestr("/Differences [ 0 /.notdef /.notdef /.notdef /.notdef\n");
- writestr("/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
- writestr("/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
- writestr("/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
- writestr("/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
- writestr("/.notdef /.notdef /.notdef /.notdef /space /exclam\n");
- writestr("/quotedbl /numbersign /dollar /percent /ampersand\n");
- writestr("/quoteright /parenleft /parenright /asterisk /plus /comma\n");
- writestr("/hyphen /period /slash /zero /one /two /three /four /five\n");
- writestr("/six /seven /eight /nine /colon /semicolon /less /equal\n");
- writestr("/greater /question /at /A /B /C /D /E /F /G /H /I /J /K /L\n");
- writestr("/M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft\n");
- writestr("/backslash /bracketright /asciicircum /underscore\n");
- writestr("/quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p\n");
- writestr("/q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright\n");
- writestr("/asciitilde /.notdef /.notdef /.notdef /.notdef /.notdef\n");
- writestr("/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
- writestr("/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n");
- writestr("/dotlessi /grave /acute /circumflex /tilde /macron /breve\n");
- writestr("/dotaccent /dieresis /.notdef /ring /cedilla /.notdef\n");
- writestr("/hungarumlaut /ogonek /caron /space /exclamdown /cent\n");
- writestr("/sterling /currency /yen /brokenbar /section /dieresis\n");
- writestr("/copyright /ordfeminine /guillemotleft /logicalnot /hyphen\n");
- writestr("/registered /macron /degree /plusminus /twosuperior\n");
- writestr("/threesuperior /acute /mu /paragraph /periodcentered\n");
- writestr("/cedilla /onesuperior /ordmasculine /guillemotright\n");
- writestr("/onequarter /onehalf /threequarters /questiondown /Agrave\n");
- writestr("/Aacute /Acircumflex /Atilde /Adieresis /Aring /AE\n");
- writestr("/Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave\n");
- writestr("/Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve\n");
- writestr("/Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash\n");
- writestr("/Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn\n");
- writestr("/germandbls /agrave /aacute /acircumflex /atilde /adieresis\n");
- writestr("/aring /ae /ccedilla /egrave /eacute /ecircumflex\n");
- writestr("/edieresis /igrave /iacute /icircumflex /idieresis /eth\n");
- writestr("/ntilde /ograve /oacute /ocircumflex /otilde /odieresis\n");
- writestr("/divide /oslash /ugrave /uacute /ucircumflex /udieresis\n");
- writestr("/yacute /thorn /ydieresis ]\n");
- writestr(">>\n");
- }
-
- writestr(">>\n");
- writestr("endobj\n");
-
- locations[5] = fpos;
- writestr("5 0 obj\n");
- writestr("<<\n");
- writestr(" /Font << /F1 4 0 R >>\n");
- writestr(" /ProcSet [ /PDF /Text ]\n");
- writestr(">>\n");
- writestr("endobj\n");
- }
-
- long StartPage(){
- long strmPos;
-
- locations[++curObj] = fpos;
- pageObs[++pageNo] = curObj;
- sprintf(buf, "%d 0 obj\n", curObj); writestr(buf);
- writestr("<<\n");
- writestr("/Type /Page\n");
- writestr("/Parent 3 0 R\n");
- writestr("/Resources 5 0 R\n");
- sprintf(buf, "/Contents %d 0 R\n", ++curObj); writestr(buf);
- writestr(">>\n");
- writestr("endobj\n");
-
- locations[curObj] = fpos;
- sprintf(buf, "%d 0 obj\n", curObj); writestr(buf);
- writestr("<<\n");
- sprintf(buf, "/Length %d 0 R\n", curObj + 1); writestr(buf);
- writestr(">>\n");
- writestr("stream\n");
- strmPos = fpos;
-
- writestr("BT\n");
- sprintf(buf, "/F1 %d Tf\n", pointSize); writestr(buf);
- sprintf(buf, "1 0 0 1 50 %d Tm\n", pageHeight - 40); writestr(buf);
- sprintf(buf, "%d TL\n", vertSpace); writestr(buf);
-
- return strmPos;
- }
-
- void EndPage(long streamStart){
- long streamEnd;
-
- writestr("ET\n");
- streamEnd = fpos;
- writestr("endstream\n");
- writestr("endobj\n");
-
- locations[++curObj] = fpos;
- sprintf(buf, "%d 0 obj\n", curObj); writestr(buf);
- sprintf(buf, "%lu\n", streamEnd - streamStart); writestr(buf);
- writestr("endobj\n");
- }
-
- void WritePages(){
- int atEOF = 0;
- int atFF;
- int atBOP;
- long beginstream;
- int lineNo, charNo;
- int ch, column;
- int padding, i;
-
- while (!atEOF) {
- beginstream = StartPage();
- column = 1;
- while (column++ <= columns) {
- atFF = 0;
- atBOP = 0;
- lineNo = 0;
- while (lineNo++ < lines && !atEOF && !atFF) {
- writestr("(");
- charNo = 0;
- while (charNo++<cols &&
- (ch = getc(infile))!=EOF &&
- !(ch==FF && doFFs) &&
- ch!='\n') {
- if (ch >= 32 && ch <= 127) {
- if (ch == '(' || ch == ')' || ch == '\\') writestr("\\");
- sprintf(buf, "%c", (char)ch); writestr(buf);
- } else {
- if (ch == 9) {
- padding = tab - ((charNo - 1) % tab);
- for (i = 1; i <= padding; i++) writestr(" ");
- charNo += (padding - 1);
- } else {
- if (ch != FF) {
- /* write \xxx form for dodgy character */
- sprintf(buf, "\\%.3o", ch); writestr(buf);
- } else {
- /* don't print anything for a FF */
- charNo--;
- }
- }
- }
- }
- writestr(")'\n");
-
- /* messy stuff to handle formfeeds. Yuk! */
- if (ch == EOF) atEOF = 1;
- if (ch == FF) atFF = 1;
- if (lineNo == lines) atBOP = 1;
- if (atBOP) {
- ch = getc(infile);
- if (ch == FF) ch = getc(infile);
- if (ch == EOF) atEOF = 1;
- else ungetc(ch, infile);
- }
- else if (atFF) {
- ch = getc(infile);
- if (ch == EOF) atEOF = 1;
- else ungetc(ch, infile);
- }
- }
-
- if (column <= columns) {
- sprintf(buf, "1 0 0 1 %d %d Tm\n",
- (pageWidth / 2) + 25, pageHeight - 40);
- writestr(buf);
- }
- }
- EndPage(beginstream);
- }
- }
-
- void WriteRest(){
- long xref;
- int i;
-
- locations[3] = fpos;
- writestr("3 0 obj\n");
- writestr("<<\n");
- writestr("/Type /Pages\n");
- sprintf(buf, "/Count %d\n", pageNo); writestr(buf);
- sprintf(buf, "/MediaBox [ 0 0 %d %d ]\n", pageWidth, pageHeight); writestr(buf);
- writestr("/Kids [ ");
- for (i = 1; i <= pageNo; i++) {sprintf(buf, "%d 0 R ", pageObs[i]); writestr(buf);}
- writestr("]\n");
- writestr(">>\n");
- writestr("endobj\n");
-
- xref = fpos;
- writestr("xref\n");
- sprintf(buf, "0 %d\n", curObj + 1); writestr(buf);
- /* note that \n is translated by writestr */
- sprintf(buf, "0000000000 65535 f %c", LINE_END); writestr(buf);
- for (i = 1; i <= curObj; i++) {
- sprintf(buf, "%.10ld 00000 n %c", locations[i], LINE_END);
- writestr(buf);
- }
-
- writestr("trailer\n");
- writestr("<<\n");
- sprintf(buf, "/Size %d\n", curObj + 1); writestr(buf);
- writestr("/Root 2 0 R\n");
- writestr("/Info 1 0 R\n");
- writestr(">>\n");
-
- writestr("startxref\n");
- sprintf(buf, "%ld\n", xref); writestr(buf);
- writestr("%%EOF\n");
- }
-
-
- void ShowHelp(){
-
- printf("\n%s [options] [filename]\n\n", progname);
- printf(" %s makes a 7-bit clean PDF file (version 1.1) from any input file.\n", progname);
- printf(" It reads from standard input or a named file, and writes the PDF file\n");
- printf(" to standard output.\n");
- printf("\n There are various options as follows:\n\n");
- printf(" -h\t\tshow this message\n");
- printf(" -f<font>\tuse PostScript <font> (must be in standard 14, default: Courier)\n");
- printf(" -I\t\tuse ISOLatin1Encoding\n");
- printf(" -s<size>\tuse font at given pointsize (default %d)\n", pointSize);
- printf(" -v<dist>\tuse given line spacing (default %d points)\n", vertSpace);
- printf(" -l<lines>\tlines per page (default 60, determined automatically\n\t\tif unspecified)\n");
- printf(" -c<chars>\tmaximum characters per line (default 80)\n");
- printf(" -t<spaces>\tspaces per tab character (default 8)\n");
- printf(" -F\t\tignore formfeed characters (^L)\n");
- printf(" -A4\t\tuse A4 paper (default Letter)\n");
- printf(" -A3\t\tuse A3 paper (default Letter)\n");
- printf(" -x<width>\tindependent paper width in points\n");
- printf(" -y<height>\tindependent paper height in points\n");
- printf(" -2\t\tformat in 2 columns\n");
- printf(" -L\t\tlandscape mode\n");
- printf("\n Note that where one variable is implied by two options, the second option\n takes precedence for that variable. (e.g. -A4 -y500)\n");
- printf(" In landscape mode, page width and height are simply swapped over before\n formatting, no matter how or when they were defined.\n");
- printf("\n%s (c) Phil Smith, 1996\n", appname);
- }
-
- int main(int argc, char **argv){
- int i = 1;
- int tmp, landscape = 0;
- char *ifilename = NULL;
-
- strcpy(font, "/");
- strcat(font, defaultFont);
- infile = stdin; /* default */
-
- while (i < argc) {
- if (*argv[i] != '-') { /* input filename */
- ifilename = argv[i];
- if (!(infile = fopen(ifilename, "r"))) {
- fprintf(stderr, "%s: couldn't open input file `%s'\n", progname, ifilename);
- exit(0);
- }
- } else {
- switch (*++argv[i]) {
- case 'h':
- ShowHelp();
- exit(0);
- case 'f':
- strcpy(font, "/");
- strcat(font, ++argv[i]);
- break;
- case 'I':
- ISOEnc = 1;
- break;
- case 'F':
- doFFs = 0;
- break;
- case 's':
- pointSize = atoi(++argv[i]);
- if (pointSize < 1) pointSize = 1;
- break;
- case 'v':
- vertSpace = atoi(++argv[i]);
- if (vertSpace < 1) vertSpace = 1;
- break;
- case 'l':
- lines = atoi(++argv[i]);
- if (lines < 1) lines = 1;
- break;
- case 'c':
- cols = atoi(++argv[i]);
- if (cols < 4) cols = 4;
- break;
- case '2':
- columns = 2;
- break;
- case 't':
- tab = atoi(++argv[i]);
- if (tab < 1) tab = 1;
- break;
- case 'A':
- switch (*++argv[i]) {
- case '3':
- pageWidth = 842;
- pageHeight = 1190;
- break;
- case '4':
- pageWidth = 595;
- pageHeight = 842;
- break;
- default:
- fprintf(stderr, "%s: ignoring unknown paper size: A%s\n", progname, argv[i]);
- }
- break;
- case 'x':
- pageWidth = atoi(++argv[i]);
- if (pageWidth < 72) pageWidth = 72;
- break;
- case 'y':
- pageHeight = atoi(++argv[i]);
- if (pageHeight < 72) pageHeight = 72;
- break;
- case 'L':
- landscape = 1;
- break;
- default:
- fprintf(stderr, "%s: ignoring invalid switch: -%s\n", progname, argv[i]);
- }
- }
- i++;
- }
-
- if (landscape) {
- tmp = pageHeight;
- pageHeight = pageWidth;
- pageWidth = tmp;
- }
-
- if (lines == 0) lines = (pageHeight - 72) / vertSpace;
- if (lines < 1) lines = 1;
- /* happens to give 60 as default */
-
- WriteHeader(ifilename);
- WritePages();
- WriteRest();
-
- return 0;
- }
|