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

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: TagLine.c++,v 1.9 2008/01/01 01:21:42 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1994-1996 Sam Leffler
  4.  * Copyright (c) 1994-1996 Silicon Graphics, Inc.
  5.  * HylaFAX is a trademark of Silicon Graphics
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26. #include "FaxServer.h"
  27. #include "PCFFont.h"
  28. #include "StackBuffer.h"
  29. #include "FaxFont.h"
  30. #include "FaxRequest.h"
  31. #if HAS_LOCALE
  32. extern "C" {
  33. #include <locale.h>
  34. }
  35. #endif
  36. #if HAS_LANGINFO
  37. extern "C" {
  38. #ifndef __USE_XOPEN
  39. #define __USE_XOPEN
  40. #endif
  41. #include <langinfo.h>
  42. }
  43. #endif
  44. #include "Sys.h"
  45. static void
  46. insert(fxStr& tag, u_int l, const fxStr& s)
  47. {
  48.     tag.remove(l,2);
  49.     tag.insert(s, l);
  50. }
  51. /*
  52.  * Read in the PCF font to use for imaging the tag line and
  53.  * preformat as much of the tag line as possible.
  54.  */
  55. void
  56. FaxModem::setupTagLine(const FaxRequest& req, const fxStr& tagLineFmt, const fxStr& locale)
  57. {
  58.     if (tagLineFont == NULL)
  59. tagLineFont = new PCFFont;
  60.     if (!tagLineFont->isReady() && conf.tagLineFontFile != "")
  61. (void) tagLineFont->read(conf.tagLineFontFile);
  62.     tagLineLocale = locale;
  63. #ifdef LC_CTYPE
  64.     setlocale(LC_CTYPE, tagLineLocale);         // for <ctype.h> calls
  65. #endif
  66. #ifdef LC_TIME
  67.     setlocale(LC_TIME, tagLineLocale);          // for strftime calls
  68. #endif
  69.     bool isutf8 = false;
  70. #if HAS_LANGINFO
  71.     isutf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0);
  72.     tagLine.setUTF8(isutf8);
  73. #endif
  74.     time_t t = Sys::now();
  75.     tm* tm = localtime(&t);
  76.     char line[1024];
  77.     strftime(line, sizeof (line)-1, tagLineFmt, tm);
  78.     tagLine = line;
  79.     u_int l = 0;
  80.     while (l < tagLine.length()) {
  81. l = tagLine.next(l, '%');
  82. if (l >= tagLine.length()-1)
  83.     break;
  84. switch (tagLine[l+1]) {
  85. case 'a': insert(tagLine, l, req.subaddr); break;
  86. case 'c': insert(tagLine, l, req.company); break;
  87. case 'C': insert(tagLine, l, req.fromcompany); break;
  88. case 'd': insert(tagLine, l, req.external); break;
  89. case 'g': insert(tagLine, l, req.location); break;
  90. case 'G': insert(tagLine, l, req.fromlocation); break;
  91. case 'i': insert(tagLine, l, req.jobid); break;
  92. case 'I': insert(tagLine, l, req.groupid); break;
  93. case 'j': insert(tagLine, l, req.jobtag); break;
  94. case 'l': insert(tagLine, l, server.getLocalIdentifier()); break;
  95. case 'm': insert(tagLine, l, req.mailaddr); break;
  96. case 'n':
  97.     if (req.faxnumber == "")
  98. insert(tagLine, l, server.getModemNumber());
  99.     else
  100. insert(tagLine, l, req.faxnumber);
  101.     break;
  102. case 'r': insert(tagLine, l, req.receiver); break;
  103. case 's': insert(tagLine, l, req.sender); break;
  104. case 'S': insert(tagLine, l, req.regarding); break;
  105. case 't': insert(tagLine, l,
  106. fxStr((int)(req.totpages-req.npages), "%u")); break;
  107. case 'T': insert(tagLine, l,
  108. fxStr((int)(req.totpages+req.skippedpages-req.nocountcover), "%u")); break;
  109. case 'v': insert(tagLine, l, req.voice); break;
  110. case 'V': insert(tagLine, l, req.fromvoice); break;
  111. case '%': tagLine.remove(l); break;
  112. default:  l += 2; break;
  113. }
  114.     }
  115.     /*
  116.      * Break the tag into fields.
  117.      */
  118.     tagLineFields = 0;
  119.     for (l = 0; l < tagLine.length(); l = tagLine.next(l+1, '|'))
  120. tagLineFields++;
  121. }
  122. #define MARGIN_TOP 2
  123. #define MARGIN_BOT 2
  124. #define MARGIN_LEFT 2
  125. #define MARGIN_RIGHT 2
  126. #define SLOP_LINES 3
  127. /*
  128.  * Calculate a ``slop factor'' to use in processing the tag line.
  129.  * This is the amount of space to preallocate for storing the
  130.  * encoded tag line once its been imaged.  We guestimate that
  131.  * the encoded data will be <= the amount of space needed to store
  132.  * the unencoded bitmap raster.  If this number is low then the
  133.  * encoded raster will be truncated resulting in the tag line
  134.  * being cropped at the bottom; probably together with a decoding
  135.  * error of one row at the receiver.
  136.  */
  137. bool
  138. FaxModem::setupTagLineSlop(const Class2Params& params)
  139. {
  140.     if (tagLineFont->isReady() && tagLineFields > 0) {
  141. tagLineSlop = (tagLineFont->fontHeight()+MARGIN_TOP+MARGIN_BOT+SLOP_LINES) * 
  142.     howmany(params.pageWidth(),8);
  143. return (true);
  144.     } else {
  145. tagLineSlop = 0;
  146. return (false);
  147.     }
  148. }
  149. #include "MemoryDecoder.h"
  150. /*
  151.  * Image the tag line in place of the top few lines of the page
  152.  * data and return the encoded tag line at the front of the
  153.  * data buffer.  The buffer that holds the page data is assumed
  154.  * to have tagLineSlop extra space allocated in front of the
  155.  * page data.  The tag line format string is assumed to be
  156.  * preprocessed by setupTagLine above so that we only need to
  157.  * setup the current page number.
  158.  */
  159. u_char*
  160. FaxModem::imageTagLine(u_char* buf, u_int fillorder, const Class2Params& params, u_long& totdata)
  161. {
  162.     u_int l;
  163. #ifdef LC_CTYPE
  164.     setlocale(LC_CTYPE, tagLineLocale);         // for <ctype.h> calls
  165. #endif
  166. #ifdef LC_TIME
  167.     setlocale(LC_TIME, tagLineLocale);          // for strftime calls
  168. #endif
  169.     bool isutf8 = false;
  170. #if HAS_LANGINFO
  171.     isutf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0);
  172.     tagLine.setUTF8(isutf8);
  173. #endif
  174.     /*
  175.      * Fill in any per-page variables used in the tag line.
  176.      */
  177.     fxStr tag = tagLine;
  178.     l = 0;
  179.     while (l < tag.length()) {
  180. l = tag.next(l, '%');
  181. if (l >= tag.length()-1)
  182.     break;
  183. if (tag[l+1] == 'p')
  184.     insert(tag, l, fxStr((int) pageNumber, "%d"));
  185. if (tag[l+1] == 'P') {
  186.     if (noCountCoverPages)
  187. insert(tag, l, "-");
  188.     else
  189. insert(tag, l, fxStr((int) pageNumberOfJob, "%d"));
  190. } else
  191.     l += 2;
  192.     }
  193.     /* 
  194.      * Setup the raster in which the tag line is imaged.
  195.      *
  196.      * The font size information received from the font functions
  197.      * is suitable for VR_FINE.  Thus VR_FINE is used as the reference
  198.      * resolution, and all other resolutions must be scaled.
  199.      */
  200.     u_int w = params.pageWidth();
  201.     u_int h = (tagLineFont->fontHeight()*2)+MARGIN_TOP+MARGIN_BOT; // max height - double VR_FINE
  202.     u_int th = 0; // actual tagline height
  203.     switch(params.vr) {
  204. case VR_NORMAL:
  205. case VR_200X100:
  206.     th = (tagLineFont->fontHeight()/2)+MARGIN_TOP+MARGIN_BOT; // half VR_FINE
  207.     break;
  208. case VR_FINE:
  209. case VR_200X200:
  210.     th = tagLineFont->fontHeight()+MARGIN_TOP+MARGIN_BOT; // reference resolution
  211.     break;
  212. case VR_R8:
  213. case VR_R16:
  214. case VR_200X400:
  215. case VR_300X300: // not proportionate but legible
  216.     th = (tagLineFont->fontHeight()*2)+MARGIN_TOP+MARGIN_BOT; // double VR_FINE
  217.     break;
  218.     }
  219.     /*
  220.      * imageText assumes that raster is word-aligned; we use
  221.      * longs here to optimize the scaling done below for the
  222.      * low res case.  This should satisfy the word-alignment.
  223.      *
  224.      * NB: The +SLOP_LINES below is for the case where we need to
  225.      *     re-encode 2D-encoded data.  An extra 3 rows is sufficient
  226.      *     because the number of consecutive 2D-encoded rows is bounded
  227.      *     by the K parameter in the CCITT spec.
  228.      */
  229.     u_int lpr = howmany(w, sizeof(u_long)*8); // longs/raster row
  230.     u_long* raster = new u_long[(h+SLOP_LINES)*lpr]; // decoded raster
  231.     memset(raster,0,(h+SLOP_LINES)*lpr*sizeof (u_long));// clear raster to white
  232.     /*
  233.      * Break the tag into fields and render each piece of
  234.      * text centered in its field.  Experiments indicate
  235.      * that rendering the text over white is better than,
  236.      * say, rendering it over the original page.
  237.      */
  238.     l = 0;
  239.     /*
  240.      * imageText produces good dimensioned fonts at 1728 pixels/row. At VR_R16
  241.      * and VR_300X300, both being wider than 1728, text appears shrinked
  242.      * horizontally; while VR_300 is still ok, VR_R16 is too small. To help
  243.      * streching the text horizontally we force text imaging to still use
  244.      * 1728 instead of VR_R16's 3456 (3456 / 2 = 1728); text will be
  245.      * imaged the 1st (left) half of the line, it will be stretched after
  246.      * imaging takes place.
  247.      */
  248.     u_int fieldWidth = params.pageWidth() / (params.vr == VR_R16 ? 2 : 1) / tagLineFields;
  249.     for (u_int f = 0; f < tagLineFields; f++) {
  250. fxStr tagField = tag.token(l, '|');
  251. u_int fw, fh;
  252. tagLineFont->strWidth(tagField, fw, fh);
  253. u_int xoff = f*fieldWidth;
  254. if (fw < fieldWidth)
  255.     xoff += (fieldWidth-fw)/2;
  256. else
  257.     xoff += MARGIN_LEFT;
  258. (void) tagLineFont->imageText(tagField, isutf8, (u_short*) raster, w, h,
  259.     xoff, MARGIN_RIGHT, MARGIN_TOP, MARGIN_BOT);
  260.     }
  261.     /*
  262.      * Scale image data as needed (see notes above).
  263.      */
  264.     if (params.vr == VR_NORMAL || params.vr == VR_200X100) {
  265. /*
  266.  * These resolutions require vertical "shrinking" of the
  267.  * tagline image.  We make 1 line out of 2.
  268.  * (Note the ``or'' used to generate the final samples.)
  269.  *
  270.  * Details:  
  271.  * - image is in lines 1 through y
  272.  * - available lines are 1 through y/2
  273.  * - start at the top of the image
  274.  * - line 1 is ORed with line 2 to get new line 1
  275.  * - line 3 is ORed with line 4 to get new line 2
  276.  * - ...
  277.  * - line y is ORed with line y+1 to get new line (y+1)/2
  278.  */
  279. u_long* l1 = raster+MARGIN_TOP*lpr;
  280. u_long* l2 = l1+lpr;
  281. u_long* l3 = raster+MARGIN_TOP*lpr;
  282. for (u_int nr = th-(MARGIN_TOP+MARGIN_BOT); nr; nr--) {
  283.     for (u_int nl = lpr; nl; nl--)
  284. *l3++ = *l1++ | *l2++;
  285.     l1 += lpr;
  286.     l2 += lpr;
  287. }
  288. memset(l3, 0, MARGIN_BOT*lpr*sizeof (u_long));
  289.     }
  290.     if (params.vr == VR_R8 || params.vr == VR_R16 || params.vr == VR_200X400 || params.vr == VR_300X300) {
  291. /*
  292.  * These resolutions require vertical "stretching" of the
  293.  * tagline image.  We make 2 lines out of 1.
  294.  * Go bottom-to-top since the image resides in the top half and the
  295.  * bottom data can be overwritten since it is unset.
  296.  * 
  297.  * Details:
  298.  * - image is in lines 1 through y/2
  299.  * - available lines are 1 through y
  300.  * - we use 2 pointers, 1st starting at line y/2 the other at line y
  301.  * - line y/2   copied in line y   and y-1
  302.  * - line y/2-1 copied in line y-2 and y-2-1
  303.  * - ...
  304.  */
  305. // bottom of actual image
  306. u_long* l1 = raster - 1 + lpr * (MARGIN_TOP + (th-MARGIN_TOP-MARGIN_BOT)/2 + 2);
  307. // bottom of available image
  308. u_long* l2 = raster - 1 + lpr * (MARGIN_TOP + (th-MARGIN_TOP-MARGIN_BOT) + 1);
  309. /* stretch vertically (going backwards, R->L, B->T) */
  310. for (u_int nr = (th-(MARGIN_TOP+MARGIN_BOT))/2; nr; nr--) {
  311.     for (u_int nl = lpr; nl; nl--) { 
  312. *(l2 - lpr) = *l1; /* y/2 copied into y-1 */
  313. *l2 = *l1; /* y/2 copied into y */ 
  314. l2--; /* left 1 long */
  315. l1--; /* left 1 long */
  316.     }
  317.     /* after previous loop, l1 and l2 are up 1 line; l2 needs 1 more */
  318.     l2 -= lpr; /* 2nd ptr up 1 line */
  319. }
  320. if (params.vr == VR_R16) {
  321.     /*
  322.      * hr is twice the hr in which data is imaged.
  323.      * We need to strech the image horizontally:
  324.      * 1234567890ABCDEFGHIJ -> 11223344556677889900
  325.      * (ABCDEFGHIJ is whitespace)
  326.      */
  327.     /* Reset ptr to begin of image */
  328.     l1 = raster + MARGIN_TOP*lpr;               // begin of 1st line
  329.     l2 = raster + MARGIN_TOP*lpr + lpr - 1;     // end of 1st line
  330.     for (u_int nr = th-(MARGIN_TOP+MARGIN_BOT); nr; nr--) {
  331. /*
  332.  * 0      lpr/2      lpr
  333.  * |        |         |
  334.  * 1234567890__________
  335.  * 1234567890________00  x/2   copied into x   and x-1
  336.  * 1234567890______9900  x/2-1 copied into x-2 and x-3
  337.  * ...
  338.  * 11223344556677889900
  339.  */
  340. u_int bpl = sizeof(u_long) * 8; // bits per u_long
  341. for (u_int nl = lpr/2 - 1; nl ; nl--) {
  342.     // make 2 longs out of 1 (ABCD -> AABB CCDD)
  343.     int pos = 0;
  344.     for (u_int i = 0; i < (bpl/8); i++) {
  345. if (i == 0 || i == bpl/8/2) {
  346.     *l2 = (u_long) 0;
  347.     pos = bpl - 2;
  348. }
  349. // put pairs of bits from l1 into the right places within l2
  350. *l2 |= (u_long)((*(l1+nl) & (1<<(bpl-8*i-5))) >> (bpl-8*i-5) << pos);
  351. *l2 |= ((u_long)((*(l1+nl) & (1<<(bpl-8*i-5))) >> (bpl-8*i-5) << pos)) << 1;
  352. pos -= 2;
  353. *l2 |= (u_long)((*(l1+nl) & (1<<(bpl-8*i-6))) >> (bpl-8*i-6) << pos);
  354. *l2 |= ((u_long)((*(l1+nl) & (1<<(bpl-8*i-6))) >> (bpl-8*i-6) << pos)) << 1;
  355. pos -= 2;
  356. *l2 |= (u_long)((*(l1+nl) & (1<<(bpl-8*i-7))) >> (bpl-8*i-7) << pos);
  357. *l2 |= ((u_long)((*(l1+nl) & (1<<(bpl-8*i-7))) >> (bpl-8*i-7) << pos)) << 1;
  358. pos -= 2;
  359. *l2 |= (u_long)((*(l1+nl) & (1<<(bpl-8*i-8))) >> (bpl-8*i-8) << pos);
  360. *l2 |= ((u_long)((*(l1+nl) & (1<<(bpl-8*i-8))) >> (bpl-8*i-8) << pos)) << 1;
  361. pos -= 2;
  362. *l2 |= (u_long)((*(l1+nl) & (1<<(bpl-8*i-1))) >> (bpl-8*i-1) << pos);
  363. *l2 |= ((u_long)((*(l1+nl) & (1<<(bpl-8*i-1))) >> (bpl-8*i-1) << pos)) << 1;
  364. pos -= 2;
  365. *l2 |= (u_long)((*(l1+nl) & (1<<(bpl-8*i-2))) >> (bpl-8*i-2) << pos);
  366. *l2 |= ((u_long)((*(l1+nl) & (1<<(bpl-8*i-2))) >> (bpl-8*i-2) << pos)) << 1;
  367. pos -= 2;
  368. *l2 |= (u_long)((*(l1+nl) & (1<<(bpl-8*i-3))) >> (bpl-8*i-3) << pos);
  369. *l2 |= ((u_long)((*(l1+nl) & (1<<(bpl-8*i-3))) >> (bpl-8*i-3) << pos)) << 1;
  370. pos -= 2;
  371. *l2 |= (u_long)((*(l1+nl) & (1<<(bpl-8*i-4))) >> (bpl-8*i-4) << pos);
  372. *l2 |= ((u_long)((*(l1+nl) & (1<<(bpl-8*i-4))) >> (bpl-8*i-4) << pos)) << 1;
  373. pos -= 2;
  374. if (pos < 0) *l2--;
  375.     }
  376. }
  377. l1 += lpr;              // begin of next line
  378. l2 = l1 + lpr - 1;      // end of next line
  379.     }
  380. }
  381. memset(l2, 0, MARGIN_BOT*lpr*sizeof (u_long));
  382.     }
  383.     MemoryDecoder dec(buf, w, totdata, fillorder, params.is2D(), (params.df == DF_2DMMR));
  384.     u_char* encbuf = dec.encodeTagLine(raster, th, tagLineSlop);   
  385.     totdata = dec.getCC();
  386.     return (encbuf);
  387. }