faxinfo.c++
上传用户:weiyuanprp
上传日期:2020-05-20
资源大小:1169k
文件大小:12k
源码类别:

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: faxinfo.c++,v 1.10 2007/10/31 19:01:59 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1990-1996 Sam Leffler
  4.  * Copyright (c) 1991-1996 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 <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <time.h>
  28. #include <stdio.h>
  29. #include <ctype.h>
  30. #include <errno.h>
  31. #include <string.h>
  32. #include <stdlib.h>
  33. #include "tiffio.h"
  34. #include "PageSize.h"
  35. #include "Class2Params.h"
  36. #include "CallID.h"
  37. #include "Sys.h"
  38. #include "port.h"
  39. extern const char* fmtTime(time_t t);
  40. /*
  41.  * This tests whether the tif file is a "fax" image.
  42.  * Traditional fax images are MH, MR, MMR, but some can
  43.  * be JPEG, JBIG, and possibly others.  So we use
  44.  * TIFFTAG_FAXRECVPARAMS as a "fax" image identifier,
  45.  * and if it's not there, then we resort to traditional
  46.  * tactics.
  47.  */
  48. static bool
  49. isFAXImage(TIFF* tif)
  50. {
  51. #ifdef TIFFTAG_FAXRECVPARAMS
  52.     uint32 v;
  53.     if (TIFFGetField(tif, TIFFTAG_FAXRECVPARAMS, &v) && v != 0)
  54. return (true);
  55. #endif
  56.     uint16 w;
  57.     if (TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &w) && w != 1)
  58. return (false);
  59.     if (TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &w) && w != 1)
  60. return (false);
  61.     if (!TIFFGetField(tif, TIFFTAG_COMPRESSION, &w) ||
  62.       (w != COMPRESSION_CCITTFAX3 && w != COMPRESSION_CCITTFAX4))
  63. return (false);
  64.     if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &w) ||
  65.       (w != PHOTOMETRIC_MINISWHITE && w != PHOTOMETRIC_MINISBLACK))
  66. return (false);
  67.     return (true);
  68. }
  69. static void
  70. sanitize(fxStr& s)
  71. {
  72.     for(u_int i = 0; i < s.length(); i++) {
  73.         if (!isascii(s[i]) || !isprint(s[i])) s[i] = '?';
  74.     }
  75. }
  76. static void
  77. usage (const char* app)
  78. {
  79.     printf("usage: %s [-n] [-S fmt] [-s fmt] [-e fmt] [-E fmt] [-D]nn", app);
  80.     printf("t-ntPrint FAX filenamen");
  81.     printf("t-C dtQuoted CSV-style output with <d> as the deliminatorn");
  82.     printf("t-c dtCSV-style output with <d> as the deliminatorn");
  83.     printf("t-rtraw format - values outputed with no namesn");
  84.     printf("  Raw format options:n");
  85.     printf("t-S fmttUse fmt for the fax start formatn");
  86.     printf("t-s fmttUse fmt for the field start formatn");
  87.     printf("t-e fmttUse fmt for the field end formatn");
  88.     printf("t-E fmttUse fmt for the fax end formatn");
  89. }
  90. static const char*
  91. escapedString (const char*src)
  92. {
  93.     char* res;
  94.     int len;
  95.     len = strlen(src);
  96.     res = (char*)malloc(len+1);
  97.     if (res)
  98.     {
  99. char* dst = res;
  100. for (int i = 0; i <= len; i++)
  101. {
  102.     switch (src[i])
  103.     {
  104.      case '\':
  105.     switch (src[++i])
  106.     {
  107. case 'n': *dst++ = 'n'; break;
  108. case 'r': *dst++ = 'r'; break;
  109. case 't': *dst++ = 't'; break;
  110. default:
  111.     *dst++ = src[i];
  112.     }
  113.     break;
  114. case '%':
  115.     *dst++ = src[i];
  116.     switch (src[++i])
  117.     {
  118. case 'n': *dst++ = '%'; break;
  119. default:
  120.     *dst++ = src[i];
  121.     }
  122.     break;
  123. default:
  124.     *dst++ = src[i];
  125.     }
  126. }
  127.     } else
  128.     {
  129.      exit(ENOMEM);
  130.     }
  131.     return res;
  132. }
  133. static const char* faxStart = "%s:n";
  134. static const char* fieldStart = "%10s: ";
  135. static const char* fieldEnd = "n";
  136. static const char* faxEnd = "";
  137. static void 
  138. printStart (const char* filename)
  139. {
  140.     printf(faxStart, filename);
  141. }
  142. static void
  143. printField (const char* val_fmt, const char* name, ...)
  144. {
  145.     printf(fieldStart, name);
  146.     va_list ap;
  147.     va_start(ap,name);
  148.     vprintf(val_fmt, ap);
  149.     va_end(ap);
  150.     printf(fieldEnd, name);
  151. }
  152. static void
  153. printEnd (const char* filename)
  154. {
  155.     printf(faxEnd, filename);
  156. }
  157. int
  158. main(int argc, char** argv)
  159. {
  160.     const char* appName = argv[0];
  161.     bool debug = false;
  162.     bool baseName = false;
  163.     int c;
  164.     while ((c = getopt(argc, argv, "C:c:rnbS:s:e:E:D")) != -1)
  165. switch (c) {
  166.     case '?':
  167.      usage(appName);
  168. return 0;
  169.     case 'C':
  170. faxStart = ""%s"";
  171. fieldStart = escapedString(fxStr::format("%%0.0s%s"", optarg));
  172. fieldEnd = """;
  173. faxEnd = "n";
  174. break;
  175.     case 'c':
  176. faxStart = "%s";
  177. fieldStart = escapedString(fxStr::format("%%0.0s%s", optarg));
  178. fieldEnd = "";
  179. faxEnd = "n";
  180. break;
  181.     case 'r':
  182. faxStart = "";
  183. fieldStart = "%0.0s";
  184. fieldEnd = "n";
  185. faxEnd = "";
  186. break;
  187.     case 'n':
  188. faxStart = "";
  189. break;
  190.     case 'b':
  191.      baseName = true;
  192. break;
  193.     case 'S':
  194. faxStart = escapedString(optarg);
  195.      break;
  196.     case 's':
  197. fieldStart = escapedString(optarg);
  198.      break;
  199.     case 'e':
  200. fieldEnd = escapedString(optarg);
  201.      break;
  202.     case 'E':
  203. faxEnd = escapedString(optarg);
  204.      break;
  205.     case 'D':
  206.      debug = true;
  207. break;
  208. }
  209.     if (debug)
  210. fprintf(stderr, "faxStart='%s'nfieldStart='%s'nfieldEnd='%s'nfaxEnd'%s'n",
  211. faxStart,fieldStart,fieldEnd,faxEnd);
  212.     while (optind < argc) {
  213. const char* name = argv[optind];
  214. if (baseName) {
  215.     const char* r = strrchr(name, '/');
  216.     if (r)
  217. name = r+1;
  218. }
  219. printStart(name);
  220. TIFFSetErrorHandler(NULL);
  221. TIFFSetWarningHandler(NULL);
  222. TIFF* tif = TIFFOpen(argv[optind], "r");
  223. if (tif == NULL) {
  224.     printf("Could not open %s; either not TIFF or corrupted.n",
  225.     argv[optind]);
  226.     return (1);
  227. }
  228. bool ok = isFAXImage(tif);
  229. if (!ok) {
  230.     printf("Does not look like a facsimile?n");
  231.     return (1);
  232. }
  233. Class2Params params;
  234. params.jp = 0;
  235. uint32 v;
  236. float vres = 3.85; // XXX default
  237. float hres = 8.03;
  238. #ifdef TIFFTAG_FAXRECVPARAMS
  239. if (TIFFGetField(tif, TIFFTAG_FAXRECVPARAMS, &v)) {
  240.     params.decode((u_int) v); // page transfer params
  241.     // inch & metric resolutions overlap and are distinguished by yres
  242.     TIFFGetField(tif, TIFFTAG_YRESOLUTION, &vres);
  243.     switch ((u_int) vres) {
  244. case 100:
  245.     params.vr = VR_200X100;
  246.     break;
  247. case 200:
  248.     params.vr = VR_200X200;
  249.     break;
  250. case 400:
  251.     params.vr = VR_200X400;
  252.     break;
  253. case 300:
  254.     params.vr = VR_300X300;
  255.     break;
  256.     }
  257. } else {
  258. #endif
  259. uint16 compression = 0;
  260. (void) TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression);
  261. if (compression == COMPRESSION_JBIG) {
  262.     params.df = DF_JBIG;
  263. } else if (compression == COMPRESSION_JPEG) {
  264.     params.df = 0;
  265.     params.jp = JP_COLOR;
  266. } else if (compression == COMPRESSION_CCITTFAX4) {
  267.     params.df = DF_2DMMR;
  268. } else {
  269.     uint32 g3opts = 0;
  270.     TIFFGetField(tif, TIFFTAG_GROUP3OPTIONS, &g3opts);
  271.     params.df = (g3opts&GROUP3OPT_2DENCODING ? DF_2DMR : DF_1DMH);
  272. }
  273. if (TIFFGetField(tif, TIFFTAG_YRESOLUTION, &vres)) {
  274.     uint16 resunit = RESUNIT_INCH; // TIFF spec default
  275.     TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
  276.     if (resunit == RESUNIT_INCH)
  277. vres /= 25.4;
  278.     if (resunit == RESUNIT_NONE)
  279. vres /= 720.0; // postscript units ?
  280.     if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &hres)) {
  281. if (resunit == RESUNIT_INCH)
  282.     hres /= 25.4;
  283. if (resunit == RESUNIT_NONE)
  284.     hres /= 720.0; // postscript units ?
  285.     }
  286. }
  287. params.setRes((u_int) hres, (u_int) vres); // resolution
  288. TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &v);
  289. params.setPageWidthInPixels((u_int) v); // page width
  290. TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &v);
  291. params.setPageLengthInMM((u_int)(v / vres)); // page length
  292. #ifdef TIFFTAG_FAXRECVPARAMS
  293. }
  294. #endif
  295. char* cp;
  296. #ifdef TIFFTAG_FAXDCS
  297. if (TIFFGetField(tif, TIFFTAG_FAXDCS, &cp) && strncmp(cp, "00 00 00", 8) != 0) {
  298.     // cannot trust br from faxdcs as V.34-Fax does not provide it there
  299.     u_int brhold = params.br;
  300.     fxStr faxdcs(cp);
  301.     sanitize(faxdcs);
  302.     params.asciiDecode((const char*) faxdcs); // params per Table 2/T.30
  303.     params.setFromDCS(params);
  304.     params.br = brhold;
  305. }
  306. #endif
  307. fxStr sender = "";
  308. CallID callid;
  309. fxStrArray callidLabels;
  310. if (TIFFGetField(tif, TIFFTAG_IMAGEDESCRIPTION, &cp)) {
  311.     while (cp[0] != '' && cp[0] != 'n') { // sender
  312. sender.append(cp[0]);
  313. cp++;
  314.     }
  315.     sanitize(sender);
  316.     u_int i = 0;
  317.     while (cp[0] == 'n') {
  318. cp++;
  319. callid.resize(i+1);
  320. callidLabels.resize(i+1);
  321. if (strchr(cp, 't') && (!strchr(cp, 'n') || strchr(cp, 't') < strchr(cp, 'n'))) {
  322.     while (cp[0] != '' && cp[0] != 't') {
  323. callidLabels[i].append(cp[0]);
  324. cp++;
  325.     }
  326.     if (cp[0] == 't') cp++;
  327. } else callidLabels[i] = fxStr::format("CallID%u", i+1);
  328. while (cp[0] != '' && cp[0] != 'n') {
  329.     callid[i].append(cp[0]);
  330.     cp++;
  331. }
  332. sanitize(callid[i]);
  333. i++;
  334.     }
  335. } else
  336.     sender = "<unknown>";
  337. printField("%s", "Sender", (const char*) sender);
  338. #ifdef TIFFTAG_FAXSUBADDRESS
  339. if (TIFFGetField(tif, TIFFTAG_FAXSUBADDRESS, &cp)) {
  340.     fxStr subaddr(cp);
  341.     sanitize(subaddr);
  342.     printField("%s", "SubAddr", (const char*) subaddr);
  343. }
  344. #endif
  345. fxStr date;
  346. if (TIFFGetField(tif, TIFFTAG_DATETIME, &cp)) { // time received
  347.     date = cp;
  348.     sanitize(date);
  349. } else {
  350.     struct stat sb;
  351.     fstat(TIFFFileno(tif), &sb);
  352.     char buf[80];
  353.     strftime(buf, sizeof (buf),
  354. "%Y:%m:%d %H:%M:%S %Z", localtime(&sb.st_mtime));
  355.     date = buf;
  356. }
  357. TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &v);
  358. float h = v / (params.vr == VR_NORMAL ? 3.85 : 
  359.     params.vr == VR_200X100 ? 3.94 : 
  360.     params.vr == VR_FINE ? 7.7 :
  361.     params.vr == VR_200X200 ? 7.87 : 
  362.     params.vr == VR_R8 ? 15.4 : 
  363.     params.vr == VR_200X400 ? 15.75 : 
  364.     params.vr == VR_300X300 ? 11.81 : 15.4);
  365. TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &v);
  366. float w = v / (params.vr == VR_NORMAL ? 8.0 : 
  367.     params.vr == VR_200X100 ? 8.00 : 
  368.     params.vr == VR_FINE ? 8.00 :
  369.     params.vr == VR_200X200 ? 8.00 : 
  370.     params.vr == VR_R8 ? 8.00 : 
  371.     params.vr == VR_200X400 ? 8.00 : 
  372.     params.vr == VR_300X300 ? 12.01 : 16.01);
  373. time_t time = 0;
  374. u_int npages = 0; // page count
  375. do {
  376.     npages++;
  377. #ifdef TIFFTAG_FAXRECVTIME
  378.     if (TIFFGetField(tif, TIFFTAG_FAXRECVTIME, &v))
  379. time += v;
  380. #endif
  381. } while (TIFFReadDirectory(tif));
  382. TIFFClose(tif);
  383. printField("%u", "Pages", npages);
  384. if (params.vr == VR_NORMAL)
  385.     printField("Normal", "Quality");
  386. else if (params.vr == VR_FINE)
  387.     printField("Fine", "Quality");
  388. else if (params.vr == VR_R8)
  389.     printField("Superfine", "Quality");
  390. else if (params.vr == VR_R16)
  391.     printField("Hyperfine", "Quality");
  392. else
  393.     printField("%u lines/inch", "Quality", params.verticalRes());
  394. PageSizeInfo* info = PageSizeInfo::getPageSizeBySize(w, h);
  395. if (info)
  396.     printField("%s", "Page", info->name());
  397. else
  398.     printField("%u by %u", "Page", params.pageWidth(), (u_int) h);
  399. delete info;
  400. printField("%s", "Received", (const char*) date);
  401. printField("%s", "TimeToRecv", time == 0 ? "<unknown>" : fmtTime(time));
  402. printField("%s", "SignalRate", params.bitRateName());
  403. printField("%s", "DataFormat", params.dataFormatName());
  404. printField("%s", "ErrCorrect", params.ec == EC_DISABLE ? "No" : "Yes");
  405. for (u_int i = 0; i < callid.size(); i++) {
  406.     printField("%s", (const char*) callidLabels[i], (const char*) callid.id(i));
  407. }
  408. printEnd(name);
  409. optind++;
  410.     }
  411.     return (0);
  412. }