fax2ps.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /* $Id: fax2ps.c,v 1.27 2011-04-02 19:30:20 bfriesen Exp $" */
  2. /*
  3. * Copyright (c) 1991-1997 Sam Leffler
  4. * Copyright (c) 1991-1997 Silicon Graphics, Inc.
  5. *
  6. * Permission to use, copy, modify, distribute, and sell this software and
  7. * its documentation for any purpose is hereby granted without fee, provided
  8. * that (i) the above copyright notices and this permission notice appear in
  9. * all copies of the software and related documentation, and (ii) the names of
  10. * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11. * publicity relating to the software without the specific, prior written
  12. * permission of Sam Leffler and Silicon Graphics.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
  15. * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
  16. * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  17. *
  18. * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19. * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20. * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21. * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
  22. * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  23. * OF THIS SOFTWARE.
  24. */
  25. #include "tif_config.h"
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <math.h>
  30. #include <time.h>
  31. #ifdef HAVE_UNISTD_H
  32. # include <unistd.h>
  33. #endif
  34. #ifdef HAVE_FCNTL_H
  35. # include <fcntl.h>
  36. #endif
  37. #ifdef HAVE_IO_H
  38. # include <io.h>
  39. #endif
  40. #ifdef NEED_LIBPORT
  41. # include "libport.h"
  42. #endif
  43. #include "tiffio.h"
  44. float defxres = 204.; /* default x resolution (pixels/inch) */
  45. float defyres = 98.; /* default y resolution (lines/inch) */
  46. const float half = 0.5;
  47. const float points = 72.0;
  48. float pageWidth = 0; /* image page width (inches) */
  49. float pageHeight = 0; /* image page length (inches) */
  50. int scaleToPage = 0; /* if true, scale raster to page dimensions */
  51. int totalPages = 0; /* total # pages printed */
  52. int row; /* current output row */
  53. int maxline = 512; /* max output line of PostScript */
  54. /*
  55. * Turn a bit-mapped scanline into the appropriate sequence
  56. * of PostScript characters to be rendered.
  57. *
  58. * Original version written by Bret D. Whissel,
  59. * Florida State University Meteorology Department
  60. * March 13-15, 1995.
  61. */
  62. static void
  63. printruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx)
  64. {
  65. static struct {
  66. char white, black;
  67. unsigned short width;
  68. } WBarr[] = {
  69. { 'd', 'n', 512 }, { 'e', 'o', 256 }, { 'f', 'p', 128 },
  70. { 'g', 'q', 64 }, { 'h', 'r', 32 }, { 'i', 's', 16 },
  71. { 'j', 't', 8 }, { 'k', 'u', 4 }, { 'l', 'v', 2 },
  72. { 'm', 'w', 1 }
  73. };
  74. static char* svalue =
  75. " !\"#$&'*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abc";
  76. int colormode = 1; /* 0 for white, 1 for black */
  77. uint32 runlength = 0;
  78. int n = maxline;
  79. uint32 x = 0;
  80. int l;
  81. (void) buf;
  82. printf("%d m(", row++);
  83. while (runs < erun) {
  84. if (runlength <= 0) {
  85. colormode ^= 1;
  86. runlength = *runs++;
  87. if (x+runlength > lastx)
  88. runlength = runs[-1] = lastx-x;
  89. x += runlength;
  90. if (!colormode && runs == erun)
  91. break; /* don't bother printing the final white run */
  92. }
  93. /*
  94. * If a runlength is greater than 6 pixels, then spit out
  95. * black or white characters until the runlength drops to
  96. * 6 or less. Once a runlength is <= 6, then combine black
  97. * and white runlengths until a 6-pixel pattern is obtained.
  98. * Then write out the special character. Six-pixel patterns
  99. * were selected since 64 patterns is the largest power of
  100. * two less than the 92 "easily printable" PostScript
  101. * characters (i.e., no escape codes or octal chars).
  102. */
  103. l = 0;
  104. while (runlength > 6) { /* Run is greater than six... */
  105. if (runlength >= WBarr[l].width) {
  106. if (n == 0) {
  107. putchar('\n');
  108. n = maxline;
  109. }
  110. putchar(colormode ? WBarr[l].black : WBarr[l].white), n--;
  111. runlength -= WBarr[l].width;
  112. } else
  113. l++;
  114. }
  115. while (runlength > 0 && runlength <= 6) {
  116. uint32 bitsleft = 6;
  117. int t = 0;
  118. while (bitsleft) {
  119. if (runlength <= bitsleft) {
  120. if (colormode)
  121. t |= ((1 << runlength)-1) << (bitsleft-runlength);
  122. bitsleft -= runlength;
  123. runlength = 0;
  124. if (bitsleft) {
  125. if (runs >= erun)
  126. break;
  127. colormode ^= 1;
  128. runlength = *runs++;
  129. if (x+runlength > lastx)
  130. runlength = runs[-1] = lastx-x;
  131. x += runlength;
  132. }
  133. } else { /* runlength exceeds bits left */
  134. if (colormode)
  135. t |= ((1 << bitsleft)-1);
  136. runlength -= bitsleft;
  137. bitsleft = 0;
  138. }
  139. }
  140. if (n == 0) {
  141. putchar('\n');
  142. n = maxline;
  143. }
  144. putchar(svalue[t]), n--;
  145. }
  146. }
  147. printf(")s\n");
  148. }
  149. /*
  150. * Create a special PostScript font for printing FAX documents. By taking
  151. * advantage of the font-cacheing mechanism, a substantial speed-up in
  152. * rendering time is realized.
  153. */
  154. static void
  155. emitFont(FILE* fd)
  156. {
  157. static const char* fontPrologue[] = {
  158. "/newfont 10 dict def newfont begin /FontType 3 def /FontMatrix [1",
  159. "0 0 1 0 0] def /FontBBox [0 0 512 1] def /Encoding 256 array def",
  160. "0 1 31{Encoding exch /255 put}for 120 1 255{Encoding exch /255",
  161. "put}for Encoding 37 /255 put Encoding 40 /255 put Encoding 41 /255",
  162. "put Encoding 92 /255 put /count 0 def /ls{Encoding exch count 3",
  163. "string cvs cvn put /count count 1 add def}def 32 1 36{ls}for",
  164. "38 1 39{ls}for 42 1 91{ls}for 93 1 99{ls}for /count 100",
  165. "def 100 1 119{ls}for /CharDict 5 dict def CharDict begin /white",
  166. "{dup 255 eq{pop}{1 dict begin 100 sub neg 512 exch bitshift",
  167. "/cw exch def cw 0 0 0 cw 1 setcachedevice end}ifelse}def /black",
  168. "{dup 255 eq{pop}{1 dict begin 110 sub neg 512 exch bitshift",
  169. "/cw exch def cw 0 0 0 cw 1 setcachedevice 0 0 moveto cw 0 rlineto",
  170. "0 1 rlineto cw neg 0 rlineto closepath fill end}ifelse}def /numbuild",
  171. "{dup 255 eq{pop}{6 0 0 0 6 1 setcachedevice 0 1 5{0 moveto",
  172. "dup 32 and 32 eq{1 0 rlineto 0 1 rlineto -1 0 rlineto closepath",
  173. "fill newpath}if 1 bitshift}for pop}ifelse}def /.notdef {}",
  174. "def /255 {}def end /BuildChar{exch begin dup 110 ge{Encoding",
  175. "exch get 3 string cvs cvi CharDict /black get}{dup 100 ge {Encoding",
  176. "exch get 3 string cvs cvi CharDict /white get}{Encoding exch get",
  177. "3 string cvs cvi CharDict /numbuild get}ifelse}ifelse exec end",
  178. "}def end /Bitfont newfont definefont 1 scalefont setfont",
  179. NULL
  180. };
  181. int i;
  182. for (i = 0; fontPrologue[i] != NULL; i++)
  183. fprintf(fd, "%s\n", fontPrologue[i]);
  184. }
  185. void
  186. printTIF(TIFF* tif, uint16 pageNumber)
  187. {
  188. uint32 w, h;
  189. uint16 unit, compression;
  190. float xres, yres, scale = 1.0;
  191. tstrip_t s, ns;
  192. time_t creation_time;
  193. TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
  194. TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
  195. if (!TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression)
  196. || compression < COMPRESSION_CCITTRLE
  197. || compression > COMPRESSION_CCITT_T6)
  198. return;
  199. if (!TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres) || !xres) {
  200. TIFFWarning(TIFFFileName(tif),
  201. "No x-resolution, assuming %g dpi", defxres);
  202. xres = defxres;
  203. }
  204. if (!TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres) || !yres) {
  205. TIFFWarning(TIFFFileName(tif),
  206. "No y-resolution, assuming %g lpi", defyres);
  207. yres = defyres; /* XXX */
  208. }
  209. if (TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &unit) &&
  210. unit == RESUNIT_CENTIMETER) {
  211. xres *= 2.54F;
  212. yres *= 2.54F;
  213. }
  214. if (pageWidth == 0)
  215. pageWidth = w / xres;
  216. if (pageHeight == 0)
  217. pageHeight = h / yres;
  218. printf("%%!PS-Adobe-3.0\n");
  219. printf("%%%%Creator: fax2ps\n");
  220. #ifdef notdef
  221. printf("%%%%Title: %s\n", file);
  222. #endif
  223. creation_time = time(0);
  224. printf("%%%%CreationDate: %s", ctime(&creation_time));
  225. printf("%%%%Origin: 0 0\n");
  226. printf("%%%%BoundingBox: 0 0 %u %u\n",
  227. (int)(pageWidth * points), (int)(pageHeight * points)); /* XXX */
  228. printf("%%%%Pages: (atend)\n");
  229. printf("%%%%EndComments\n");
  230. printf("%%%%BeginProlog\n");
  231. emitFont(stdout);
  232. printf("/d{bind def}def\n"); /* bind and def proc */
  233. printf("/m{0 exch moveto}d\n");
  234. printf("/s{show}d\n");
  235. printf("/p{showpage}d \n"); /* end page */
  236. printf("%%%%EndProlog\n");
  237. printf("%%%%Page: \"%u\" %u\n", pageNumber, pageNumber);
  238. printf("/$pageTop save def gsave\n");
  239. if (scaleToPage)
  240. scale = pageHeight / (h/yres) < pageWidth / (w/xres) ?
  241. pageHeight / (h/yres) : pageWidth / (w/xres);
  242. printf("%g %g translate\n",
  243. points * (pageWidth - scale*w/xres) * half,
  244. points * (scale*h/yres + (pageHeight - scale*h/yres) * half));
  245. printf("%g %g scale\n", points/xres*scale, -points/yres*scale);
  246. printf("0 setgray\n");
  247. TIFFSetField(tif, TIFFTAG_FAXFILLFUNC, printruns);
  248. ns = TIFFNumberOfStrips(tif);
  249. row = 0;
  250. for (s = 0; s < ns; s++)
  251. (void) TIFFReadEncodedStrip(tif, s, (tdata_t) NULL, (tsize_t) -1);
  252. printf("p\n");
  253. printf("grestore $pageTop restore\n");
  254. totalPages++;
  255. }
  256. #define GetPageNumber(tif) \
  257. TIFFGetField(tif, TIFFTAG_PAGENUMBER, &pn, &ptotal)
  258. int
  259. findPage(TIFF* tif, uint16 pageNumber)
  260. {
  261. uint16 pn = (uint16) -1;
  262. uint16 ptotal = (uint16) -1;
  263. if (GetPageNumber(tif)) {
  264. while (pn != (pageNumber-1) && TIFFReadDirectory(tif) && GetPageNumber(tif))
  265. ;
  266. return (pn == (pageNumber-1));
  267. } else
  268. return (TIFFSetDirectory(tif, (tdir_t)(pageNumber-1)));
  269. }
  270. void
  271. fax2ps(TIFF* tif, uint16 npages, uint16* pages, char* filename)
  272. {
  273. if (npages > 0) {
  274. uint16 pn, ptotal;
  275. int i;
  276. if (!GetPageNumber(tif))
  277. fprintf(stderr, "%s: No page numbers, counting directories.\n",
  278. filename);
  279. for (i = 0; i < npages; i++) {
  280. if (findPage(tif, pages[i]))
  281. printTIF(tif, pages[i]);
  282. else
  283. fprintf(stderr, "%s: No page number %d\n", filename, pages[i]);
  284. }
  285. } else {
  286. uint16 pageNumber = 0;
  287. do
  288. printTIF(tif, pageNumber++);
  289. while (TIFFReadDirectory(tif));
  290. }
  291. }
  292. #undef GetPageNumber
  293. static int
  294. pcompar(const void* va, const void* vb)
  295. {
  296. const int* pa = (const int*) va;
  297. const int* pb = (const int*) vb;
  298. return (*pa - *pb);
  299. }
  300. static void usage(int code);
  301. int
  302. main(int argc, char** argv)
  303. {
  304. extern int optind;
  305. extern char* optarg;
  306. uint16 *pages = NULL, npages = 0, pageNumber;
  307. int c, dowarnings = 0; /* if 1, enable library warnings */
  308. TIFF* tif;
  309. while ((c = getopt(argc, argv, "l:p:x:y:W:H:wS")) != -1)
  310. switch (c) {
  311. case 'H': /* page height */
  312. pageHeight = (float)atof(optarg);
  313. break;
  314. case 'S': /* scale to page */
  315. scaleToPage = 1;
  316. break;
  317. case 'W': /* page width */
  318. pageWidth = (float)atof(optarg);
  319. break;
  320. case 'p': /* print specific page */
  321. pageNumber = (uint16)atoi(optarg);
  322. if (pages)
  323. pages = (uint16*) realloc(pages, (npages+1)*sizeof(uint16));
  324. else
  325. pages = (uint16*) malloc(sizeof(uint16));
  326. pages[npages++] = pageNumber;
  327. break;
  328. case 'w':
  329. dowarnings = 1;
  330. break;
  331. case 'x':
  332. defxres = (float)atof(optarg);
  333. break;
  334. case 'y':
  335. defyres = (float)atof(optarg);
  336. break;
  337. case 'l':
  338. maxline = atoi(optarg);
  339. break;
  340. case '?':
  341. usage(-1);
  342. }
  343. if (npages > 0)
  344. qsort(pages, npages, sizeof(uint16), pcompar);
  345. if (!dowarnings)
  346. TIFFSetWarningHandler(0);
  347. if (optind < argc) {
  348. do {
  349. tif = TIFFOpen(argv[optind], "r");
  350. if (tif) {
  351. fax2ps(tif, npages, pages, argv[optind]);
  352. TIFFClose(tif);
  353. } else
  354. fprintf(stderr, "%s: Can not open, or not a TIFF file.\n",
  355. argv[optind]);
  356. } while (++optind < argc);
  357. } else {
  358. int n;
  359. FILE* fd;
  360. char buf[16*1024];
  361. fd = tmpfile();
  362. if (fd == NULL) {
  363. fprintf(stderr, "Could not obtain temporary file.\n");
  364. exit(-2);
  365. }
  366. #if defined(HAVE_SETMODE) && defined(O_BINARY)
  367. setmode(fileno(stdin), O_BINARY);
  368. #endif
  369. while ((n = read(fileno(stdin), buf, sizeof (buf))) > 0)
  370. write(fileno(fd), buf, n);
  371. lseek(fileno(fd), 0, SEEK_SET);
  372. #if defined(_WIN32) && defined(USE_WIN32_FILEIO)
  373. tif = TIFFFdOpen(_get_osfhandle(fileno(fd)), "temp", "r");
  374. #else
  375. tif = TIFFFdOpen(fileno(fd), "temp", "r");
  376. #endif
  377. if (tif) {
  378. fax2ps(tif, npages, pages, "<stdin>");
  379. TIFFClose(tif);
  380. } else
  381. fprintf(stderr, "Can not open, or not a TIFF file.\n");
  382. fclose(fd);
  383. }
  384. printf("%%%%Trailer\n");
  385. printf("%%%%Pages: %u\n", totalPages);
  386. printf("%%%%EOF\n");
  387. return (0);
  388. }
  389. char* stuff[] = {
  390. "usage: fax2ps [options] [input.tif ...]",
  391. "where options are:",
  392. " -w suppress warning messages",
  393. " -l chars set maximum output line length for generated PostScript",
  394. " -p page# select page to print (can use multiple times)",
  395. " -x xres set default horizontal resolution of input data (dpi)",
  396. " -y yres set default vertical resolution of input data (lpi)",
  397. " -S scale output to page size",
  398. " -W width set output page width (inches), default is 8.5",
  399. " -H height set output page height (inches), default is 11",
  400. NULL
  401. };
  402. static void
  403. usage(int code)
  404. {
  405. char buf[BUFSIZ];
  406. int i;
  407. setbuf(stderr, buf);
  408. fprintf(stderr, "%s\n\n", TIFFGetVersion());
  409. for (i = 0; stuff[i] != NULL; i++)
  410. fprintf(stderr, "%s\n", stuff[i]);
  411. exit(code);
  412. }
  413. /* vim: set ts=8 sts=8 sw=8 noet: */
  414. /*
  415. * Local Variables:
  416. * mode: c
  417. * c-basic-offset: 8
  418. * fill-column: 78
  419. * End:
  420. */