]> git.ipfire.org Git - thirdparty/HylaFAX.git/commitdiff
[Bug 389] superfine, hyperfine, etc. resolution support
authorDarren Nickerson <darren.nickerson@ifax.com>
Mon, 16 Jun 2003 21:05:47 +0000 (21:05 +0000)
committerDarren Nickerson <darren.nickerson@ifax.com>
Mon, 16 Jun 2003 21:05:47 +0000 (21:05 +0000)
This is a very large and involved patch.  Please see the included documentation
with regards to what it does and how it does it.  Essentially it changes an
info entry from SupportsHighRes (boolean) to SupportsVR (integer), allows a
modem to receive all resolutions for which it is capable (all of them in Class
1), allows a user to send in extended resolutions using the JPARM USEXRES or
'sendfax -G' option (if the modem and remote supports it).

45 files changed:
config/lucent-mt-20
config/lucent-mt-21
faxd/Class1.c++
faxd/Class1Recv.c++
faxd/Class2.c++
faxd/ClassModem.c++
faxd/ClassModem.h
faxd/CopyQuality.c++
faxd/FaxMachineInfo.c++
faxd/FaxMachineInfo.h
faxd/FaxModem.c++
faxd/FaxModem.h
faxd/FaxRequest.c++
faxd/FaxRequest.h
faxd/FaxSend.c++
faxd/FaxServer.c++
faxd/FaxServer.h
faxd/G3Decoder.c++
faxd/Job.h
faxd/Modem.c++
faxd/Modem.h
faxd/TagLine.c++
faxd/choptest.c++
faxd/cqtest.c++
faxd/faxQueueApp.c++
faxd/mkhash.c
faxd/tagtest.c++
hfaxd/HylaFAXServer.h
hfaxd/Jobs.c++
hfaxd/Parser.c++
hfaxd/RecvQueue.c++
man/doneq.4f
man/hylafax-info.4f
man/sendfax.1
man/sendq.4f
sendfax/sendfax.c++
util/Class2Params.c++
util/Class2Params.h
util/FaxClient.c++
util/SendFaxJob.c++
util/SendFaxJob.h
util/class2.h
util/faxinfo.c++
util/pdf2fax.gs.sh.in
util/ps2fax.gs.sh.in

index 802d43e2cc087449545fbef0613d90919d762c6a..ef1bdb1db3901050735450ce4e146bc2493f6d08 100644 (file)
@@ -27,11 +27,18 @@ Class2UseHex:               yes
 # versions that respond to AT+FFC=? with non-zero data support RTFCC
 # Class2RTFCC:         yes
 
-# unfortunately, HylaFAX can't currently receive in color
+# unfortunately, HylaFAX can't currently send or receive in color
 ModemAnswerCmd:                AT+FCC=,,,,,,,,0;A
-# and, let's try to prevent any color sending attempts, also
 ModemDialCmd:          AT+FCC=,,,,,,,,0;DT%s
 
+# Some firmware revisions (i.e. 1.25 in ZBAs) report MMR support but
+# corrupt the data.  Enabling the following lines should work around this.
+# Compare this against the modem's AT+FCC=? response.
+# Class2DCCQueryCmd:    "!(00-01),(00-05),(00-02),(00-02),(00-01),(00-01),(00),(00-07)"
+# ModemAnswerCmd:      AT+FCC=,,,,1,,,,0;A
+# ModemDialCmd:                AT+FCC=,,,,1,,,,0;DT%s
+
+
 # If your line supports Caller-ID, you may want to uncomment this...
 # QualifyCID:          etc/cid         # you must create this file
 # ModemResetCmds:      AT+VCID=1
index 9c41fe3b736c4689cf520f65f530e076aacb851a..550aca6e7e5dea8eaaa7d7e056143a7f732932f1 100644 (file)
@@ -27,10 +27,19 @@ Class2UseHex:               yes
 # versions that respond to AT+FFC=? with non-zero data support RTFCC
 # Class2RTFCC:         yes
 
-# unfortunately, HylaFAX can't currently receive in color
-ModemAnswerCmd:                AT+FCC=,,,,,,,,0;A
-# and, let's try to prevent any color sending attempts, also
-ModemDialCmd:          AT+FCC=,,,,,,,,0;DT%s
+# unfortunately, HylaFAX can't currently send or receive in color
+# Also, the modem's extended resolution support is buggy
+ModemAnswerCmd:                AT+FCC=1,,,,,,,,0;A
+ModemDialCmd:          AT+FCC=1,,,,,,,,0;DT%s
+
+# Some firmware revisions (i.e. 1.25) report MMR support but corrupt the data.
+# Some firmware revisions (i.e. 1.25 and 1.28) report extended resolution support but
+# have trouble with 300x300 and 400x400 resolutions and corrupt DIS for inch resolutions.
+# Enabling the following lines should work around these things.
+# Compare this against the modem's AT+FCC=? response.
+# Class2DCCQueryCmd:   "!(03),(00-05),(00-02),(00-02),(00-01),(00-01),(00),(00-07)"
+# ModemAnswerCmd:      AT+FCC=03,,,,1,,,,0;A
+# ModemDialCmd:                AT+FCC=03,,,,1,,,,0;DT%s
 
 # If your line supports Caller-ID, you may want to uncomment this...
 # QualifyCID:          etc/cid         # you must create this file
index a92b5fc5a7f06cef29e28221b9981c484ec21335..73bd294809f10b8ea7e9ab1ccc7497a5a0f9ec43 100644 (file)
@@ -876,11 +876,11 @@ Class1Modem::modemXINFO() const
        | DIS_864
        | DIS_1728H
        | DIS_1728L
-#ifdef notdef
        | DIS_200X400                   // additional resolutions
        | DIS_300X300
        | DIS_400X400
-#endif
+       | DIS_METRES                    // announce support for both metric
+       | DIS_INCHRES                   // and inch-based resolutions.
        ;
 }
 
index 19ca8756e77f56c4adb0a168b6c37b0c489b18c8..62578da4c4bd2ec8d91927d1dbc7e63c34c3e9ee 100644 (file)
@@ -353,7 +353,8 @@ void
 Class1Modem::processDCSFrame(const HDLCFrame& frame)
 {
     u_int dcs = frame.getDIS();                        // NB: really DCS
-    params.setFromDCS(dcs, frame.getXINFO());
+    u_int xinfo = frame.getXINFO();
+    params.setFromDCS(dcs, xinfo);
     setDataTimeout(60, params.br);
     curcap = findSRCapability(dcs&DCS_SIGRATE, recvCaps);
     recvDCS(params);                           // announce session params
index 2e9d1df57f3cd9c8ddd5e5fe333ef3d076389fcc..d475e060ef83ba251119032993552392e7ce72aa 100644 (file)
@@ -126,7 +126,7 @@ Class2Modem::setupModem()
     // some modems don't support an AP-query command
     if (strcasecmp(conf.class2APQueryCmd, "none") != 0) {
        if (doQuery(conf.class2APQueryCmd, s))
-           (void) vparseRange(s, 3, &sub, &sep, &pwd);
+           (void) vparseRange(s, 0, 3, &sub, &sep, &pwd);
     }
     if (sub & BIT(1)) {
        saCmd = conf.class2SACmd;
@@ -309,7 +309,7 @@ Class2Modem::setupFlowControl(FlowControl fc)
 bool
 Class2Modem::setupDCC()
 {
-    params.vr = getBestVRes();
+    params.vr = getVRes();
     params.br = getBestSignallingRate();
     params.wd = getBestPageWidth();
     params.ln = getBestPageLength();
@@ -343,7 +343,7 @@ Class2Modem::parseClass2Capabilities(const char* cap, Class2Params& params)
         * Clamp values to insure modem doesn't feed us
         * nonsense; should log bogus stuff also.
         */
-       params.vr = fxmin(params.vr, (u_int) VR_FINE);
+       params.vr = params.vr & VR_ALL;
        params.br = fxmin(params.br, (u_int) BR_33600);
        params.wd = fxmin(params.wd, (u_int) WD_864);
        params.ln = fxmin(params.ln, (u_int) LN_INF);
@@ -531,7 +531,13 @@ Class2Modem::class2Cmd(const fxStr& cmd, const fxStr& s, ATResponse r, long ms)
 bool
 Class2Modem::parseRange(const char* cp, Class2Params& p)
 {
-    if (!vparseRange(cp, 8, &p.vr,&p.br,&p.wd,&p.ln,&p.df,&p.ec,&p.bf,&p.st))
+    /*
+     * VR, BF, and JP are already reported as bitmap
+     * values accoring to T.32 Table 21.
+     * In vparseRange(), VR:nargs=7, BF:nargs=1.  JP not handled.
+     */
+    int masked = (1 << 7) + (1 << 1);  // reversed, count-down style
+    if (!vparseRange(cp, masked, 8, &p.vr,&p.br,&p.wd,&p.ln,&p.df,&p.ec,&p.bf,&p.st))
        return (false);
     p.vr &= VR_ALL;
     p.br &= BR_ALL;
index ada5f2d37cfa2faaf0b70d068ba604d73749d758..7c2461f54a1e2092643e8f095ec9a2e5e1b0a928 100644 (file)
@@ -414,6 +414,22 @@ ClassModem::traceBits(u_int bits, const char* bitNames[])
        }
 }
 
+/*
+ * Trace a modem capability true bit mask (VR, BF, JP).
+ */
+void
+ClassModem::traceBitMask(u_int bits, const char* bitNames[])
+{
+    u_int i = 0;
+    do {
+       if ((bits & i) == i) {
+           modemSupports(bitNames[i]);
+           bits -= i;
+       }
+       i++;
+    } while (bits);
+}
+
 /*
  * Modem i/o support.
  */
@@ -1054,7 +1070,7 @@ const char SPACE = ' ';
  *     that indicate they support ``Class Z'' are handled.
  */
 bool
-ClassModem::vparseRange(const char* cp, int nargs ... )
+ClassModem::vparseRange(const char* cp, int masked, int nargs ... )
 {
     bool b = true;
     va_list ap;
@@ -1145,9 +1161,30 @@ ClassModem::vparseRange(const char* cp, int nargs ... )
                    cp++;
            }
            if (v != -1) {                              // expand range or list
-               r = fxmin(r, 31);                       // clamp to valid range
-               for (; v <= r; v++)
-                   mask |= 1<<v;
+               if ((BIT(nargs) & masked) == BIT(nargs)) {
+                   /*
+                    * These are pre-masked values. T.32 Table 21 gives valid
+                    * values as: 00, 01, 02, 04, 08, 10, 20, 40 (hex).
+                    *
+                    * Some modems may say "(00-7F)" when what's meant is
+                    * "(00-40)" or simply "(7F)".
+                    */
+                   if (v == 00 && r == 127)
+                       v = r = 127;
+                   if (v == r)
+                       mask = v;
+                   else {
+                       r = fxmin(r, 64);               // clamp to valid range
+                       mask = 0;
+                       for (; v <= r; v++)
+                           if (v == 0 || v == 1 || v == 2 || v == 4 || v == 8 || v == 16 || v == 32 || v == 64)
+                               mask += v;
+                   }
+               } else {
+                   r = fxmin(r, 31);                   // clamp to valid range
+                   for (; v <= r; v++)
+                       mask |= 1<<v;
+               }
            }
            if (acceptList && cp[0] == COMMA)           // (<item>,<item>...)
                cp++;
@@ -1170,7 +1207,7 @@ done:
 bool
 ClassModem::parseRange(const char* cp, u_int& a0)
 {
-    return vparseRange(cp, 1, &a0);
+    return vparseRange(cp, 0, 1, &a0);
 }
 
 void
index 4d959ea993150e1d49bc4c37a899dd08a4c06a8c..ebc996dc3da2a13305e33b1b11f4116c607f4139 100644 (file)
@@ -212,6 +212,7 @@ protected:
     void       modemSupports(const char* fmt, ...);
     void       modemCapability(const char* fmt, ...);
     void       traceBits(u_int bits, const char* bitNames[]);
+    void       traceBitMask(u_int bits, const char* bitNames[]);
 public:
     virtual ~ClassModem();
 
@@ -263,7 +264,7 @@ public:
     bool       atQuery(const char* what, fxStr& v, long ms = 30*1000);
     bool       atQuery(const char* what, u_int& v, long ms = 30*1000);
     bool       parseRange(const char*, u_int&);
-    bool       vparseRange(const char*, int nargs ...);
+    bool       vparseRange(const char*, int masked, int nargs ...);
 // modem line control
     bool       sendBreak(bool pause);
     bool       setBaudRate(BaudRate rate);
index a26c9f098d9256f61bfffb1ab565259ee6c8a1be..a1edaf82d7b3e6d9dc098bffc1269839301eb9da 100644 (file)
@@ -49,9 +49,9 @@ FaxModem::recvPageDLEData(TIFF* tif, bool checkQuality,
 {
     setupDecoder(recvFillOrder, params.is2D());
 
-    u_int rowpixels = params.pageWidth();      // NB: assume rowpixels <= 2432
-    tiff_runlen_t runs[2*2432];                        // run arrays for cur+ref rows
-    setRuns(runs, runs+2432, rowpixels);
+    u_int rowpixels = params.pageWidth();      // NB: assume rowpixels <= 4864
+    tiff_runlen_t runs[2*4864];                        // run arrays for cur+ref rows
+    setRuns(runs, runs+4864, rowpixels);
 
     recvEOLCount = 0;                          // count of EOL codes
     recvBadLineCount = 0;                      // rows with a decoding error
@@ -301,7 +301,7 @@ FaxModem::recvSetupTIFF(TIFF* tif, long, int fillOrder)
     TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,    (uint32) -1);
     TIFFSetField(tif, TIFFTAG_PLANARCONFIG,    PLANARCONFIG_CONTIG);
     TIFFSetField(tif, TIFFTAG_FILLORDER,       (uint16) fillOrder);
-    TIFFSetField(tif, TIFFTAG_XRESOLUTION,     204.);
+    TIFFSetField(tif, TIFFTAG_XRESOLUTION,     (float) params.horizontalRes());
     TIFFSetField(tif, TIFFTAG_YRESOLUTION,     (float) params.verticalRes());
     TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT,  RESUNIT_INCH);
     TIFFSetField(tif, TIFFTAG_SOFTWARE,                HYLAFAX_VERSION);
index 8821df56a7641838a4da50c7a5cc4063a091593d..9d2301537f81234b003d2038992a3ed90500ab56 100644 (file)
@@ -54,7 +54,7 @@ FaxMachineInfo::FaxMachineInfo(const FaxMachineInfo& other)
 {
     locked = other.locked;
 
-    supportsHighRes = other.supportsHighRes;
+    supportsVRes = other.supportsVRes;
     supports2DEncoding = other.supports2DEncoding;
     supportsMMR = other.supportsMMR;
     supportsPostScript = other.supportsPostScript;
@@ -99,7 +99,7 @@ FaxMachineInfo::updateConfig(const fxStr& number)
 void
 FaxMachineInfo::resetConfig()
 {
-    supportsHighRes = true;            // assume 196 lpi support
+    supportsVRes = VR_FINE;            // normal and high res support
     supports2DEncoding = true;         // assume 2D-encoding support
     supportsMMR = true;                        // assume MMR support
     supportsPostScript = false;                // no support for Adobe protocol
@@ -162,7 +162,7 @@ static const char* stnames[] =
      "20ms/10ms", "20ms", "40ms/20ms", "40ms" };
 #define        NST     N(stnames)
 
-#define        HIRES   0
+#define VR     0
 #define        G32D    1
 #define        G4      2
 #define        PS      3
@@ -178,9 +178,12 @@ FaxMachineInfo::setConfigItem(const char* tag, const char* value)
 {
     int b = (tag[0] == '&' ? 1 : 0);   // locked down indicator
     if (b) tag++;
-    if (streq(tag, "supportshighres")) {
-       supportsHighRes = getBoolean(value);
-       setLocked(b, HIRES);
+    if (streq(tag, "supportshighres")) {       // obsolete tag
+       supportsVRes = VR_FINE;
+       setLocked(b, VR);
+    } else if (streq(tag, "supportsvres")) {
+       supportsVRes = getNumber(value);
+       setLocked(b, VR);
     } else if (streq(tag, "supports2dencoding")) {
        supports2DEncoding = getBoolean(value);
        setLocked(b, G32D);
@@ -245,8 +248,8 @@ FaxMachineInfo::setConfigItem(const char* tag, const char* value)
        changed = true;                 \
     }
 
-void FaxMachineInfo::setSupportsHighRes(bool b)
-    { checkLock(HIRES, supportsHighRes, b); }
+void FaxMachineInfo::setSupportsVRes(int v)
+    { checkLock(VR, supportsVRes, v); }
 void FaxMachineInfo::setSupports2DEncoding(bool b)
     { checkLock(G32D, supports2DEncoding, b); }
 void FaxMachineInfo::setSupportsMMR(bool b)
@@ -341,7 +344,7 @@ putIfString(fxStackBuffer& buf, const char* tag, bool locked, const char* v)
 void
 FaxMachineInfo::writeConfig(fxStackBuffer& buf)
 {
-    putBoolean(buf, "supportsHighRes", isLocked(HIRES), supportsHighRes);
+    putDecimal(buf, "supportsVRes", isLocked(VR), supportsVRes);
     putBoolean(buf, "supports2DEncoding", isLocked(G32D),supports2DEncoding);
     putBoolean(buf, "supportsMMR", isLocked(G4),supportsMMR);
     putBoolean(buf, "supportsPostScript", isLocked(PS), supportsPostScript);
index 505e85d598fd74f1e8dc987a99ee4b4f659c454d..349b5b6e53a1f254d6dc7c1e254e8affe6b6fc3a 100644 (file)
@@ -49,7 +49,7 @@ private:
     fxStr      file;                   // pathname to info file
     u_int      locked;                 // bit vector of locked items
     bool       changed;                // changed since restore
-    bool       supportsHighRes;        // capable of 7.7 line/mm vres
+    u_short    supportsVRes;           // VR support bitmask
     bool       supports2DEncoding;     // handles Group 3 2D
     bool       supportsMMR;            // handles Group 4
     bool       supportsPostScript;     // handles Adobe NSF protocol
@@ -88,7 +88,7 @@ public:
     virtual void writeConfig();
     virtual void resetConfig();
 
-    bool getSupportsHighRes() const;
+    u_short getSupportsVRes() const;
     bool getSupports2DEncoding() const;
     bool getSupportsMMR() const;
     bool getSupportsPostScript() const;
@@ -105,7 +105,7 @@ public:
     const fxStr& getLastSendFailure() const;
     const fxStr& getLastDialFailure() const;
 
-    void setSupportsHighRes(bool);
+    void setSupportsVRes(int);
     void setSupports2DEncoding(bool);
     void setSupportsMMR(bool);
     void setSupportsPostScript(bool);
@@ -129,8 +129,8 @@ public:
     const fxStr& getPagerSetupCmds() const;
 };
 
-inline bool FaxMachineInfo::getSupportsHighRes() const
-    { return supportsHighRes; }
+inline u_short FaxMachineInfo::getSupportsVRes() const
+    { return supportsVRes; }
 inline bool FaxMachineInfo::getSupports2DEncoding() const
     { return supports2DEncoding; }
 inline bool FaxMachineInfo::getSupportsMMR() const
index 5ed0855d0af7d20b64418b0546739074b3a0278f..c0f272bafbf8bb89273447f0e91a62b3a8445b27 100644 (file)
@@ -342,9 +342,14 @@ FaxModem::getBestScanlineTime() const
  * Return the best vres the modem supports.
  */
 u_int
-FaxModem::getBestVRes() const
+FaxModem::getVRes() const
 {
-    return bestBit(modemParams.vr, VR_FINE, VR_NORMAL);
+    /*
+     * We don't use bestBit() here because T.32 Table 21
+     * states that VR is to be reported as a bitmask
+     * of supported resolutions.  So we already have it.
+     */
+    return (modemParams.vr);
 }
 
 /*
@@ -436,14 +441,24 @@ FaxModem::supportsECM() const
  * rather tolerant because of potential precision
  * problems and general sloppiness on the part of
  * applications writing TIFF files.
+ *
+ * Because R8 and R16 vertical resolutions are the same
+ * but differ by horizontal resolution, R16 is "coded"
+ * as "20" in order to support it.
  */
 bool
 FaxModem::supportsVRes(float res) const
 {
     if (3.0 <= res && res < 4.75)
-       return (modemParams.vr & BIT(VR_NORMAL)) != 0;
+       return ((modemParams.vr & VR_NORMAL) || (modemParams.vr & VR_200X100)) != 0;
     else if (5.9 <= res && res < 9.8)
-       return (modemParams.vr & BIT(VR_FINE)) != 0;
+       return ((modemParams.vr & VR_FINE) || (modemParams.vr & VR_200X200)) != 0;
+    else if (9.8 <= res && res < 13)
+       return (modemParams.vr & VR_300X300) != 0;
+    else if (13 <= res && res < 19)
+       return ((modemParams.vr & VR_R8) || (modemParams.vr & VR_200X400)) != 0;
+    else if (res == 20)
+       return (modemParams.vr & VR_R16) != 0;
     else
        return false;
 }
@@ -453,14 +468,34 @@ FaxModem::supportsVRes(float res) const
  * specified page width.
  */
 bool
-FaxModem::supportsPageWidth(u_int w) const
-{
-    switch (w) {
-    case 1728: return (modemParams.wd & BIT(WD_1728)) != 0;
-    case 2048: return (modemParams.wd & BIT(WD_2048)) != 0;
-    case 2432: return (modemParams.wd & BIT(WD_2432)) != 0;
-    case 1216: return (modemParams.wd & BIT(WD_1216)) != 0;
-    case 864:  return (modemParams.wd & BIT(WD_864)) != 0;
+FaxModem::supportsPageWidth(u_int w, u_int r) const
+{
+    switch (r) {
+       case VR_R16:
+           switch (w) {
+               case 3456:   return (modemParams.wd & BIT(WD_1728)) != 0;
+               case 4096:   return (modemParams.wd & BIT(WD_2048)) != 0;
+               case 4864:   return (modemParams.wd & BIT(WD_2432)) != 0;
+               case 2432:   return (modemParams.wd & BIT(WD_1216)) != 0;
+               case 1728:   return (modemParams.wd & BIT(WD_864)) != 0;
+           }
+       case VR_300X300:
+           switch (w) {
+               case 2592:   return (modemParams.wd & BIT(WD_1728)) != 0;
+           }
+       case VR_NORMAL:
+       case VR_FINE:
+       case VR_R8:
+       case VR_200X100:
+       case VR_200X200:
+       case VR_200X400:
+           switch (w) {
+               case 1728:   return (modemParams.wd & BIT(WD_1728)) != 0;
+               case 2048:   return (modemParams.wd & BIT(WD_2048)) != 0;
+               case 2432:   return (modemParams.wd & BIT(WD_2432)) != 0;
+               case 1216:   return (modemParams.wd & BIT(WD_1216)) != 0;
+               case 864:    return (modemParams.wd & BIT(WD_864)) != 0;
+           }
     }
     return false;
 }
@@ -490,7 +525,7 @@ u_int
 FaxModem::modemDIS() const
 {
     return DIS_T4RCVR
-         | Class2Params::vrDISTab[getBestVRes()]
+         | DIS_7MMVRES         // not getVRes(), DIS only contains partial VR data
          | Class2Params::brDISTab[getBestSignallingRate()]
          | Class2Params::wdDISTab[getBestPageWidth()]
          | Class2Params::lnDISTab[getBestPageWidth()]
@@ -523,7 +558,7 @@ FaxModem::modemXINFO() const
 void
 FaxModem::traceModemParams()
 {
-    traceBits(modemParams.vr, Class2Params::verticalResNames);
+    traceBitMask(modemParams.vr, Class2Params::verticalResNames);
     traceBits(modemParams.br, Class2Params::bitRateNames);
     traceBits(modemParams.wd, Class2Params::pageWidthNames);
     traceBits(modemParams.ln, Class2Params::pageLengthNames);
index 246e0589b88e2a27bb2bc0692d3979d21830123b..452515204b0d38d01443a7baee28cd8b2f4d670b 100644 (file)
@@ -165,7 +165,7 @@ public:
     virtual bool supportsMMR() const;
     virtual bool supportsEOLPadding() const;
     virtual bool supportsVRes(float res) const;
-    virtual bool supportsPageWidth(u_int w) const;
+    virtual bool supportsPageWidth(u_int w, u_int r) const;
     virtual bool supportsPageLength(u_int l) const;
     virtual bool supportsPolling() const;
     virtual bool supportsECM() const;
@@ -176,7 +176,7 @@ public:
     u_int getBestScanlineTime() const;
     virtual int selectScanlineTime(int st) const;
 
-    u_int getBestVRes() const;
+    u_int getVRes() const;
     u_int getBestDataFormat() const;
     u_int getBestPageWidth() const;
     u_int getBestPageLength() const;
index caeae5fd0d3c0a6d2f55e7ba953a92ff0d0bdfd9..3e48f62f645d3b322782ffa419e400c399ca08a6 100644 (file)
@@ -68,6 +68,7 @@ FaxRequest::reset(void)
     totdials = 0, maxdials = (u_short) FAX_REDIALS;
     tottries = 0, maxtries = (u_short) FAX_RETRIES;
     useccover = true;
+    usexvres = false;
     pagechop = chop_default;
     chopthreshold = -1;
     notify = no_notice;
@@ -129,6 +130,7 @@ FaxRequest::shortval FaxRequest::shortvals[] = {
     { "desireddf",     &FaxRequest::desireddf },
     { "desiredtl",     &FaxRequest::desiredtl },
     { "useccover",     &FaxRequest::useccover },
+    { "usexvres",      &FaxRequest::usexvres },
 };
 char* FaxRequest::opNames[18] = {
     "fax",
@@ -294,6 +296,7 @@ FaxRequest::readQFile(bool& rejectJob)
        case H_DESIREDDF:       desireddf = tag[0] - '0'; break;
        case H_DESIREDTL:       desiredtl = tag[0] - '0'; break;
        case H_USECCOVER:       useccover = tag[0] - '0'; break;
+       case H_USEXVRES:        usexvres = tag[0] - '0'; break;
        case H_TTS:
            tts = atoi(tag);
            if (tts == 0)       // distinguish ``now'' from unset
index 4e3d8dff4ebe7d0362207be4e38ff580ce8490b9..c5fd2b2d5f3f21a74c8320c3ecc4b52b58e8a564 100644 (file)
@@ -118,7 +118,7 @@ public:
     u_short    maxtries;       // max # attempts to deliver (answered calls)
     u_short    pagewidth;      // desired output page width (mm)
     u_short    pagelength;     // desired output page length (mm)
-    u_short    resolution;     // desired vertical resolution (lpi)
+    u_short    resolution;     // desired vertical resolution (lpi) (normal/fine)
     u_short    usrpri;         // user-requested scheduling priority
     u_short    pri;            // current scheduling priority
     u_short    minsp;          // minimum acceptable signalling rate
@@ -128,6 +128,7 @@ public:
     u_short    desireddf;      // desired data format
     u_short    desiredtl;      // desired tagline handling
     u_short    useccover;      // whether to use continuation cover page
+    u_short    usexvres;       // whether to use extended VR
     u_short    pagechop;       // whether to do page chopping
     u_short    notify;         // email notification flags
     float      chopthreshold;  // minimum white space before chopping
index 5ca1f12685d414d4af3d5895f0829418e3605a9d..98350a9e7761b4d7ca731ecb17724b421d3ea379 100644 (file)
@@ -460,7 +460,7 @@ FaxServer::sendClientCapabilitiesOK(FaxRequest& fax, FaxMachineInfo& clientInfo,
      * constructed here is also recorded in a private database for
      * use in pre-formatting documents sent in future conversations.
      */
-    clientInfo.setSupportsHighRes(clientCapabilities.vr == VR_FINE);
+    clientInfo.setSupportsVRes(clientCapabilities.vr);
     clientInfo.setSupports2DEncoding(clientCapabilities.df >= DF_2DMR);
     clientInfo.setSupportsMMR(clientCapabilities.df >= DF_2DMMR);
     clientInfo.setMaxPageWidthInPixels(clientCapabilities.pageWidth());
@@ -468,7 +468,7 @@ FaxServer::sendClientCapabilitiesOK(FaxRequest& fax, FaxMachineInfo& clientInfo,
     traceProtocol("REMOTE best rate %s", clientCapabilities.bitRateName());
     traceProtocol("REMOTE max %s", clientCapabilities.pageWidthName());
     traceProtocol("REMOTE max %s", clientCapabilities.pageLengthName());
-    traceProtocol("REMOTE best vres %s", clientCapabilities.verticalResName());
+    traceProtocol("REMOTE best vres %s", clientCapabilities.bestVerticalResName());
     traceProtocol("REMOTE best format %s", clientCapabilities.dataFormatName());
     if (clientCapabilities.ec != EC_DISABLE)
        traceProtocol("REMOTE supports %s", clientCapabilities.ecmName());
@@ -554,35 +554,9 @@ FaxServer::sendSetupParams1(TIFF* tif,
        } else
            params.df = DF_1DMR;
     }
-    uint32 w;
-    (void) TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
-    if (w > (uint32)clientInfo.getMaxPageWidthInPixels()) {
-       emsg = fxStr::format("Client does not support document page width"
-               ", max remote page width %u pixels, image width %lu pixels",
-               clientInfo.getMaxPageWidthInPixels(), w);
-       return (send_reformat);
-    }
-    if (!modem->supportsPageWidth((u_int) w)) {
-       static const char* widths[8] = {
-           "1728",     // 1728 in 215 mm line
-           "2048",     // 2048 in 255 mm line
-           "2432",     // 2432 in 303 mm line
-           "1216",     // 1216 in 151 mm line
-           "864",      // 864 in 107 mm line
-           "<undefined>",
-           "<undefined>",
-           "<undefined>",
-       };
-       emsg = fxStr::format("Modem does not support document page width"
-               ", max page width %s pixels, image width %lu pixels",
-               widths[modem->getBestPageWidth()&7], w);
-       return (send_reformat);
-    }
-    // NB: only common values
-    params.wd = (w <= 1728 ? WD_1728 : w <= 2048 ? WD_2048 : WD_2432);
 
     /*
-     * Try to deduce the vertical resolution of the image
+     * Try to deduce the resolution of the image
      * image.  This can be problematical for arbitrary TIFF
      * images 'cuz vendors sometimes don't give the units.
      * We, however, can depend on the info in images that
@@ -605,20 +579,110 @@ FaxServer::sendSetupParams1(TIFF* tif,
        TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &l);
        yres = (l < 1450 ? 3.85 : 7.7);         // B4 at 98 lpi is ~1400 lines
     }
-    if (yres >= 7.) {
-       if (!clientInfo.getSupportsHighRes()) {
+    float xres;
+    if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres)) {
+       short resunit = RESUNIT_INCH;           // TIFF spec default
+       (void) TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
+       if (resunit == RESUNIT_INCH)
+           xres /= 25.4;
+       if (resunit == RESUNIT_NONE)
+           xres /= 720.0;                      // postscript units ?
+    } else {
+       /*
+        * No horizontal resolution is specified, try
+        * to deduce one from the image width.
+        */
+       u_long l;
+       TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &l);
+       xres = (l < 1729 ? 8 : 16);             // R8 = 8 l/mm, R16 = 16 l/mm
+    }
+    if (yres >= 15.) {
+       if (xres > 10) {
+           if (!(clientInfo.getSupportsVRes() & VR_R16)) {
+               emsg = fxStr::format("Hyperfine resolution document is not supported"
+                   " by client, image resolution %g x %g lines/mm", xres, yres);
+               return (send_reformat);
+           }
+           if (!modem->supportsVRes(20)) {     // "20" is coded for R16
+               emsg = fxStr::format("Hyperfine resolution document is not supported"
+                   " by modem, image resolution %g x %g lines/mm", xres, yres);
+               return (send_reformat);
+           }
+       params.vr = VR_R16;
+       } else {
+           if (!((clientInfo.getSupportsVRes() & VR_R8) || (clientInfo.getSupportsVRes() & VR_200X400))) {
+               emsg = fxStr::format("Superfine resolution document is not supported"
+                   " by client, image resolution %g lines/mm", yres);
+               return (send_reformat);
+           }
+           if (!modem->supportsVRes(yres)) {
+               emsg = fxStr::format("Superfine resolution document is not supported"
+                   " by modem, image resolution %g lines/mm", yres);
+               return (send_reformat);
+           }
+       if (clientInfo.getSupportsVRes() & VR_R8) params.vr = VR_R8;
+       else params.vr = VR_200X400;
+       }
+    } else if (yres >= 10.) {
+       if (!(clientInfo.getSupportsVRes() & VR_300X300)) {
+           emsg = fxStr::format("300x300 resolution document is not supported"
+               " by client, image resolution %g lines/mm", yres);
+           return (send_reformat);
+       }
+       if (!modem->supportsVRes(yres)) {
+           emsg = fxStr::format("300x300 resolution document is not supported"
+               " by modem, image resolution %g lines/mm", yres);
+           return (send_reformat);
+       }
+       params.vr = VR_300X300;
+    } else if (yres >= 7.) {
+       if (!((clientInfo.getSupportsVRes() & VR_FINE) || (clientInfo.getSupportsVRes() & VR_200X200))) {
            emsg = fxStr::format("High resolution document is not supported"
-                         " by client, image resolution %g lines/mm", yres);
+               " by client, image resolution %g lines/mm", yres);
            return (send_reformat);
        }
        if (!modem->supportsVRes(yres)) {
            emsg = fxStr::format("High resolution document is not supported"
-                         " by modem, image resolution %g lines/mm", yres);
+               " by modem, image resolution %g lines/mm", yres);
            return (send_reformat);
        }
-       params.vr = VR_FINE;
+       if (clientInfo.getSupportsVRes() & VR_FINE) params.vr = VR_FINE;
+       else params.vr = VR_200X200;
     } else
-       params.vr = VR_NORMAL;
+       params.vr = VR_NORMAL;          // support required
+
+    /*
+     * Max page width depends on the resolution, so this must come after VR.
+     * maxPageWidth is stored in normal values, so we must compare against
+     * the corresponding normal resolution page width.
+     */
+    uint32 w;
+    (void) TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
+    double rf = (params.vr == VR_R16 ? 2 : params.vr == VR_300X300 ? 1.5 : 1);
+    if (w > (clientInfo.getMaxPageWidthInPixels()*rf)) {
+       emsg = fxStr::format("Client does not support document page width"
+               ", max remote page width %u pixels, image width %lu pixels",
+               (uint32) (clientInfo.getMaxPageWidthInPixels()*rf), w);
+       return (send_reformat);
+    }
+    if (!modem->supportsPageWidth((u_int) w, params.vr)) {
+       static const double widths[8] = {
+           1728*rf,    // 1728 in 215 mm line
+           2048*rf,    // 2048 in 255 mm line
+           2432*rf,    // 2432 in 303 mm line
+           1216*rf,    // 1216 in 151 mm line
+           864*rf,     // 864 in 107 mm line
+           0,
+           0,
+           0,
+       };
+       emsg = fxStr::format("Modem does not support document page width"
+               ", max page width %u pixels, image width %lu pixels",
+               widths[modem->getBestPageWidth()&7], w);
+       return (send_reformat);
+    }
+    // NB: only common values
+    params.wd = ((uint32) (w/rf) <= 1728 ? WD_1728 : (uint32) (w/rf) <= 2048 ? WD_2048 : WD_2432);
 
     /*
      * Select page length according to the image size and
index fd7ad8fb6434fd5547e9db127c1e722a62c40265..f92a433eb8fd399be1d65c324741b71be00bfc09 100644 (file)
@@ -202,8 +202,6 @@ bool FaxServer::modemSupportsEOLPadding() const
     { return modem ? modem->supportsEOLPadding() : false; }
 bool FaxServer::modemSupportsVRes(float res) const
     { return modem ? modem->supportsVRes(res) : true; }
-bool FaxServer::modemSupportsPageWidth(u_int w) const
-    { return modem ? modem->supportsPageWidth(w) : true; }
 bool FaxServer::modemSupportsPageLength(u_int l) const
     { return modem ? modem->supportsPageLength(l) : true; }
 
index 9f1447541035547b8f7e81d705da9d69ed0e4266..fcb92963e64cb6d4207b4160118d94b8a9542234 100644 (file)
@@ -120,7 +120,6 @@ public:
     bool modemSupportsMMR() const;
     bool modemSupportsEOLPadding() const;
     bool modemSupportsVRes(float res) const;
-    bool modemSupportsPageWidth(u_int w) const;
     bool modemSupportsPageLength(u_int l) const;
     bool modemSupportsPolling() const;
 };
index 0d6ac30cf337802c4bf50b525803ffe47d3695d8..674a4ab553e2d2ddd7fd121bc3738cbb2028feb0 100644 (file)
@@ -134,8 +134,8 @@ G3Decoder::decode(void* raster, u_int w, u_int h)
 {
     u_int rowbytes = howmany(w, 8);
     if (curruns == NULL) {
-       tiff_runlen_t runs[2*2432];             // run arrays for cur+ref rows
-       setRuns(runs, runs+2432, w);
+       tiff_runlen_t runs[2*4864];             // run arrays for cur+ref rows
+       setRuns(runs, runs+4864, w);
        while (h-- > 0) {
            decodeRow(raster, w);
            if (raster)
index e85da57a680f1fad0ff444f1972f6c31a3cb7257..92891211b24f38f542a94b10b94b7fd186c96f55 100644 (file)
@@ -115,7 +115,7 @@ public:
     u_short    state;          // scheduling state
     u_short    pagewidth;      // desired output page width (mm)
     u_short    pagelength;     // desired output page length (mm)
-    u_short    resolution;     // desired vertical resolution (lpi)
+    u_short    resolution;     // desired vertical resolution (lpi) (normal/fine)
     bool       willpoll;       // job has polling request
     bool       suspendPending; // suspend state change pending for job
 
index 17fd8e8ee435a10589d568ca734fe8737f2f38e9..b828b9c8144754e9a214c7bb15c0c4644442a9ec 100644 (file)
@@ -116,7 +116,7 @@ Modem::getModemByID(const fxStr& id)
 
 /*
  * Is the modem capable of handling the job.
- */ 
+ */
 bool
 Modem::isCapable(const Job& job) const
 {
@@ -365,13 +365,27 @@ bool
 Modem::supportsVRes(float res) const
 {
     if (75 <= res && res < 120)
-       return caps.vr & BIT(VR_NORMAL);
+       return (caps.vr & VR_NORMAL || caps.vr & VR_200X100);
     else if (150 <= res && res < 250)
-       return caps.vr & BIT(VR_FINE);
+       return (caps.vr & VR_FINE || caps.vr & VR_200X200);
+    else if (250 <= res && res < 350)
+       return caps.vr & VR_300X300;
+    else if (350 <= res && res < 500)
+       return (caps.vr & VR_R8 || caps.vr & VR_200X400 || caps.vr & VR_R16);
     else
        return false;
 }
 
+/*
+ * Return whether or not the modem supports the
+ * specified VR setting.
+ */
+bool
+Modem::supportsVR(u_int r) const
+{
+        return caps.vr & r;
+}
+
 /*
  * Return whether or not the modem supports 2DMR.
  */
index 1960c2289e0762c15ab0a465c6a514bfc19988ef..2aa2c20b019b15b19beef17fb69323bfca75ea09 100644 (file)
@@ -126,6 +126,7 @@ public:
     bool supports2D() const;           // modem supports 2D-encoded fax
     bool supportsMMR() const;          // modem supports 2D-MMR encoding
     bool supportsVRes(float) const;    // modem supports vertical resolution
+    bool supportsVR(u_int) const;      // modem supports VR setting
     // modem support fax page width
     bool supportsPageWidthInMM(u_int) const;
     bool supportsPageWidthInPixels(u_int) const;
index 95207a2b3404a0346e4abe830ffc03fb63e8b4ea..bea3c4c995f219e12f67351045f2931453de9c33 100644 (file)
@@ -170,15 +170,17 @@ FaxModem::imageTagLine(u_char* buf, u_int fillorder, const Class2Params& params)
      */
     u_int w = params.pageWidth();
     u_int h = tagLineFont->fontHeight()+MARGIN_TOP+MARGIN_BOT;
-    u_int th = (params.vr == VR_FINE) ?
-       h : (tagLineFont->fontHeight()/2)+MARGIN_TOP+MARGIN_BOT;
+    u_int th = (params.vr == VR_R16 or params.vr == VR_R8 or params.vr == VR_200X400) ? h :
+       (params.vr == VR_300X300) ? (tagLineFont->fontHeight()/2)+MARGIN_TOP+MARGIN_BOT :
+       (params.vr == VR_FINE or params.vr == VR_200X200) ? (tagLineFont->fontHeight()/2)+MARGIN_TOP+MARGIN_BOT :
+       (tagLineFont->fontHeight()/2)+MARGIN_TOP+MARGIN_BOT;
     /*
      * imageText assumes that raster is word-aligned; we use
      * longs here to optimize the scaling done below for the
      * low res case.  This should satisfy the word-alignment.
      *
      * NB: The +3 below is for the case where we need to re-encode
-     *     2D-encoded data.  An extra 3 rows is sufficinet because
+     *     2D-encoded data.  An extra 3 rows is sufficient because
      *     the number of consecutive 2D-encoded rows is bounded
      *     by the K parameter in the CCITT spec.
      */
@@ -213,8 +215,8 @@ FaxModem::imageTagLine(u_char* buf, u_int fillorder, const Class2Params& params)
      */
     TagLineMemoryDecoder dec(buf);
     dec.setupDecoder(fillorder, params.is2D());
-    tiff_runlen_t runs[2*2432];                // run arrays for cur+ref rows
-    dec.setRuns(runs, runs+2432, w);
+    tiff_runlen_t runs[2*4864];                // run arrays for cur+ref rows
+    dec.setRuns(runs, runs+4864, w);
 
     dec.decode(NULL, w, th);           // discard decoded data
     /*
@@ -244,7 +246,7 @@ FaxModem::imageTagLine(u_char* buf, u_int fillorder, const Class2Params& params)
     u_int look_ahead = roundup(dec.getPendingBits(),8) / 8;
     u_int decoded = dec.current() - look_ahead - buf;
 
-    if (params.vr == VR_NORMAL) {
+    if (params.vr != VR_R8 and params.vr != VR_R16 and params.vr != VR_200X400) {
        /*
         * Scale text vertically before encoding.  Note the
         * ``or'' used to generate the final samples. 
index cbd982c6d04bb430e86ac30fb1c524a313bb6b3a..aad8ea663a9179f8fbd9a2b7b1c0993666461615 100644 (file)
@@ -88,9 +88,9 @@ void
 MemoryDecoder::scanPage(u_int fillorder, const Class2Params& params)
 {
     setupDecoder(fillorder,  params.is2D());
-    u_int rowpixels = params.pageWidth();      // NB: assume rowpixels <= 2432
-    tiff_runlen_t runs[2*2432];                        // run arrays for cur+ref rows
-    setRuns(runs, runs+2432, rowpixels);
+    u_int rowpixels = params.pageWidth();      // NB: assume rowpixels <= 4864
+    tiff_runlen_t runs[2*4864];                        // run arrays for cur+ref rows
+    setRuns(runs, runs+4864, rowpixels);
 
     if (!RTCraised()) {
        /*
index 9fcfde0560fafc9ac96b7086385d5cf93076b31a..1577d0d7e52e2f958d10031015c8cd8612f8d9e1 100644 (file)
@@ -114,7 +114,7 @@ CQDecoder::recvSetupTIFF(TIFF* tif, long, int fillOrder, const Class2Params& par
     TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,    (uint32) -1);
     TIFFSetField(tif, TIFFTAG_PLANARCONFIG,    PLANARCONFIG_CONTIG);
     TIFFSetField(tif, TIFFTAG_FILLORDER,       (uint16) fillOrder);
-    TIFFSetField(tif, TIFFTAG_XRESOLUTION,     204.);
+    TIFFSetField(tif, TIFFTAG_XRESOLUTION,     (float) params.horizontalRes());
     TIFFSetField(tif, TIFFTAG_YRESOLUTION,     (float) params.verticalRes());
     TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT,  RESUNIT_INCH);
     TIFFSetField(tif, TIFFTAG_SOFTWARE,                HYLAFAX_VERSION);
@@ -143,9 +143,9 @@ CQDecoder::recvPageDLEData(TIFF* tif, bool checkQuality,
 {
     setupDecoder(recvFillOrder, params.is2D());
 
-    u_int rowpixels = params.pageWidth();      // NB: assume rowpixels <= 2432
-    tiff_runlen_t runs[2*2432];                        // run arrays for cur+ref rows
-    setRuns(runs, runs+2432, rowpixels);
+    u_int rowpixels = params.pageWidth();      // NB: assume rowpixels <= 4864
+    tiff_runlen_t runs[2*4864];                        // run arrays for cur+ref rows
+    setRuns(runs, runs+4864, rowpixels);
 
     recvEOLCount = 0;                          // count of EOL codes
     recvBadLineCount = 0;                      // rows with a decoding error
index b996c9e87a93421ee915dc2491951c68977812cd..6f88d18f071093b414a25c82f7a1605421dc04ee 100644 (file)
@@ -508,8 +508,31 @@ faxQueueApp::prepareJob(Job& job, FaxRequest& req,
      * (based on the capabilities passed to us by faxgetty).
      */
     Class2Params params;
-    params.setVerticalRes(req.resolution > 150 && !info.getSupportsHighRes() ?
-       98 : req.resolution);
+    // use the highest resolution the client supports
+    params.vr = VR_NORMAL;
+    if (req.usexvres) {
+       if (info.getSupportsVRes() & VR_200X100 && job.modem->supportsVR(VR_200X100))
+           params.vr = VR_200X100;
+       if (info.getSupportsVRes() & VR_FINE && job.modem->supportsVR(VR_FINE))
+           params.vr = VR_FINE;
+       if (info.getSupportsVRes() & VR_200X200 && job.modem->supportsVR(VR_200X200))
+           params.vr = VR_200X200;
+       if (info.getSupportsVRes() & VR_R8 && job.modem->supportsVR(VR_R8))
+           params.vr = VR_R8;
+       if (info.getSupportsVRes() & VR_200X400 && job.modem->supportsVR(VR_200X400))
+           params.vr = VR_200X400;
+       if (info.getSupportsVRes() & VR_300X300 && job.modem->supportsVR(VR_300X300))
+           params.vr = VR_300X300;
+       if (info.getSupportsVRes() & VR_R16 && job.modem->supportsVR(VR_R16))
+           params.vr = VR_R16;
+    } else {
+       if (info.getSupportsVRes() & VR_200X100 && job.modem->supportsVR(VR_200X100))
+           params.vr = VR_200X100;
+       if (info.getSupportsVRes() & VR_FINE && req.resolution > 150 && job.modem->supportsVR(VR_FINE))
+           params.vr = VR_FINE;
+       if (info.getSupportsVRes() & VR_200X200 && req.resolution > 150 && job.modem->supportsVR(VR_200X200))
+           params.vr = VR_200X200;
+    }
     params.setPageWidthInMM(
        fxmin((u_int) req.pagewidth, (u_int) info.getMaxPageWidthInMM()));
     params.setPageLengthInMM(
@@ -741,22 +764,23 @@ faxQueueApp::setupParams(TIFF* tif, Class2Params& params, const FaxMachineInfo&
      * We, however, can depend on the info in images that
      * we generate 'cuz we're careful to include valid info.
      */
-    float yres;
-    if (TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres)) {
+    float yres, xres;
+    if (TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres) && TIFFGetField(tif, TIFFTAG_YRESOLUTION, &xres)) {
        uint16 resunit;
        TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
        if (resunit == RESUNIT_CENTIMETER)
            yres *= 25.4;
-       params.setVerticalRes((u_int) yres);
+           xres *= 25.4;
+       params.setRes((u_int) xres, (u_int) yres);
     } else {
        /*
-        * No vertical resolution is specified, try
+        * No resolution is specified, try
         * to deduce one from the image length.
         */
        uint32 l;
        TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &l);
        // B4 at 98 lpi is ~1400 lines
-       params.setVerticalRes(l < 1450 ? 98 : 196);
+       params.setRes(204, (l < 1450 ? 98 : 196));
     }
 
     /*
@@ -830,9 +854,9 @@ void
 MemoryDecoder::scanPageForBlanks(u_int fillorder, const Class2Params& params)
 {
     setupDecoder(fillorder,  params.is2D());
-    u_int rowpixels = params.pageWidth();      // NB: assume rowpixels <= 2432
-    tiff_runlen_t runs[2*2432];                        // run arrays for cur+ref rows
-    setRuns(runs, runs+2432, rowpixels);
+    u_int rowpixels = params.pageWidth();      // NB: assume rowpixels <= 4864
+    tiff_runlen_t runs[2*4864];                        // run arrays for cur+ref rows
+    setRuns(runs, runs+4864, rowpixels);
 
     if (!RTCraised()) {
        /*
index 8674d340fda734821193870f0e9c729a0f546922..876793bc5d55f44aec54625438b4d19d397a9047 100644 (file)
@@ -112,6 +112,7 @@ main()
     hash("desireddf");
     hash("desiredtl");
     hash("useccover");
+    hash("usexvres");
     hash("tts");
     hash("killtime");
     hash("retrytime");
index 91eb16a0ab914d145b10d921642bdd1cd7d72a55..6958c56f83c9afb374a2cfe106f3578a4bf295c7 100644 (file)
@@ -236,8 +236,8 @@ imageTagLine(u_char* buf, u_int fillorder, const Class2Params& params)
      */
     MemoryDecoder dec(buf);
     dec.setupDecoder(fillorder,  params.is2D());
-    tiff_runlen_t runs[2*2432];                // run arrays for cur+ref rows
-    dec.setRuns(runs, runs+2432, w);
+    tiff_runlen_t runs[2*4864];                // run arrays for cur+ref rows
+    dec.setRuns(runs, runs+4864, w);
 
     u_int row;
     for (row = 0; row < th; row++) {
@@ -271,7 +271,7 @@ imageTagLine(u_char* buf, u_int fillorder, const Class2Params& params)
      */
     u_int look_ahead = roundup(dec.getPendingBits(),8) / 8;
     u_int decoded = dec.current() - look_ahead - buf;
-    if (params.vr == VR_NORMAL) {
+    if (params.vr == VR_NORMAL or params.vr == VR_200X100) {
        /*
         * Scale text vertically before encoding.  Note the
         * ``or'' used to generate the final samples. 
@@ -436,7 +436,7 @@ main(int argc, char* argv[])
        uint32 l;
        TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &l);
        params.vr = (l < 1500 ? VR_NORMAL : VR_FINE);
-       TIFFSetField(otif, TIFFTAG_XRESOLUTION, 204.);
+       TIFFSetField(otif, TIFFTAG_XRESOLUTION, (float) params.horizontalRes());
        TIFFSetField(otif, TIFFTAG_YRESOLUTION, (float) params.verticalRes());
        TIFFSetField(otif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
        TIFFSetField(otif, TIFFTAG_IMAGELENGTH, l);
index de9faf93c27a3938dae671326d90ea3597c92a56..eff749567661ff9947336e7c7e2a4166312df7df 100644 (file)
@@ -117,7 +117,7 @@ enum Token {
     T_RETRYTIME, T_SCHEDPRI,   T_SENDTIME,     T_STATE,        T_STATUS,
     T_SUBADDR,  T_TAGLINE,     T_TOTDIALS,     T_TOTPAGES,     T_TOTTRIES,
     T_TO_COMPANY,T_TO_LOCATION,        T_TO_USER,      T_TO_VOICE,     T_USE_CONTCOVER,
-    T_USE_ECM,  T_USE_TAGLINE, T_USRKEY,       T_VRES,
+    T_USE_ECM,  T_USE_TAGLINE, T_USE_XVRES,    T_USRKEY,       T_VRES,
     /*
      * SNPP tokens.
      */
index aed2767ed63b4b3c286ed3faa8dafae022c06240..63e63a7b497198e73399f63e3810932cccd1a590 100644 (file)
@@ -142,6 +142,7 @@ static const struct {
     { T_USE_CONTCOVER, A_RUSR|A_RADM|A_WADM|A_ROTH },
     { T_USE_ECM,       A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH },
     { T_USE_TAGLINE,   A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH },
+    { T_USE_XVRES,     A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH },
     { T_USRKEY,                A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH },
     { T_VRES,          A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH },
     { T_NIL,           0 },
@@ -389,6 +390,9 @@ HylaFAXServer::replyJobParamValue(Job& job, int code, Token t)
     case T_USE_TAGLINE:
        replyBoolean(code, job.desiredtl);
        return;
+    case T_USE_XVRES:
+       replyBoolean(code, job.usexvres);
+       return;
     case T_USE_CONTCOVER:
        replyBoolean(code, job.useccover);
        return;
@@ -514,6 +518,8 @@ HylaFAXServer::jstatCmd(const Job& job)
        jstatLine(T_USE_ECM,    "%s", boolString(job.desiredec));
     if (checkAccess(job, T_USE_TAGLINE, A_READ))
        jstatLine(T_USE_TAGLINE,"%s", boolString(job.desiredtl));
+    if (checkAccess(job, T_USE_XVRES, A_READ))
+       jstatLine(T_USE_XVRES,"%s", boolString(job.usexvres));
     if (checkAccess(job, T_USE_CONTCOVER, A_READ))
        jstatLine(T_USE_CONTCOVER,"%s", boolString(job.useccover));
     u_int i, n;
@@ -749,6 +755,9 @@ HylaFAXServer::setJobParameter(Job& job, Token t, bool b)
        case T_USE_TAGLINE:
            job.desiredtl = b;
            return (true);
+       case T_USE_XVRES:
+           job.usexvres = b;
+           return (true);
        case T_USE_CONTCOVER:
            job.useccover = b;
            return (true);
@@ -802,6 +811,7 @@ HylaFAXServer::initDefaultJob(void)
     defJob.desiredec   = EC_ENABLE;
     defJob.desireddf   = DF_2DMMR;
     defJob.desiredtl   = false;
+    defJob.usexvres    = false;
     defJob.useccover   = true;
     defJob.pagechop    = FaxRequest::chop_default;
     defJob.notify      = FaxRequest::no_notice;// FAX_DEFNOTIFY
@@ -884,6 +894,7 @@ HylaFAXServer::newJob(fxStr& emsg)
     job->desiredec = curJob->desiredec;
     job->desireddf = curJob->desireddf;
     job->desiredtl = curJob->desiredtl;
+    job->usexvres = curJob->usexvres;
     job->useccover = curJob->useccover;
     job->pagechop = curJob->pagechop;
     job->notify = curJob->notify;
@@ -1601,7 +1612,8 @@ static const char jformat[] = {
     'u',               // w (pagewidth)
     'u',               // x (maxdials)
     'u',               // y (total pages)
-    's'                        // z (tts)
+    's',               // z (tts)
+    'c',               // 0 (usexvres as symbol)
 };
 
 /*
@@ -1816,6 +1828,9 @@ HylaFAXServer::Jprintf(FILE* fd, const char* fmt, const Job& job)
            case 'z':
                fprintf(fd, fspec, compactTime(job.tts));
                break;
+           case '0':
+               fprintf(fd, fspec, "N "[job.usexvres]);
+               break;
            }
        } else
            putc(*cp, fd);
index c8e0b5eb12bc0827d0847b94c49ef6e146e606fd..9b5cf528dfc0d3f1dc3ce88f78275ac7599e4555 100644 (file)
@@ -172,6 +172,7 @@ static const tab parmtab[] = {
 { "TOUSER",       T_TO_USER,     false, true, "[<string>]" },
 { "TOVOICE",      T_TO_VOICE,    false,false, "[<string>]" },
 { "USECONTCOVER", T_USE_CONTCOVER,false, true, "[YES|NO]" },
+{ "USEXVRES",     T_USE_XVRES,   false, true, "[YES|NO]" },
 { "USEECM",       T_USE_ECM,     false, true, "[YES|NO]" },
 { "USETAGLINE",   T_USE_TAGLINE,  false, true, "[YES|NO]" },
 { "USRKEY",       T_USRKEY,      false, true, "[<string>]" },
@@ -1125,6 +1126,16 @@ HylaFAXServer::param_cmd(Token t)
            return (true);
        }
        break;
+    case T_USE_XVRES:
+       if (opt_CRLF()) {
+           replyJobParamValue(*curJob, 213, t);
+           return (true);
+       } else if (boolean_param(b) &&
+         setJobParameter(*curJob, t, b)) {
+           reply(213, "%s set to %s.", parmToken(t), b ? "YES" : "NO");
+           return (true);
+       }
+       break;
     case T_CHOPTHRESH:
        if (opt_CRLF()) {
            replyJobParamValue(*curJob, 213, t);
index 2c5bee35d1350372833fe7cd704ecd20aaed1f1b..5c2198922bdc8acfa1b1ade1ada948643ba60730 100644 (file)
@@ -119,7 +119,16 @@ HylaFAXServer::getRecvDocStatus(RecvInfo& ri)
        if (resunit == RESUNIT_NONE)
            vres /= 720.0;                              // postscript units ?
     }
-    ri.params.setVerticalRes((u_int) vres);            // resolution
+    float hres = 8.03;                                 // XXX default
+    if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &hres)) {
+       uint16 resunit = RESUNIT_INCH;                  // TIFF spec default
+       TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
+       if (resunit == RESUNIT_INCH)
+           hres /= 25.4;
+       if (resunit == RESUNIT_NONE)
+           hres /= 720.0;                              // postscript units ?
+    }
+    ri.params.setRes((u_int) hres, (u_int) vres);      // resolution
     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &v);
     ri.params.setPageWidthInPixels((u_int) v);         // page width
     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &v);
index 753d65ec357ea968bbf5c6c58b578c4631c531bc..9831e1937b5e9e220bb63289c63c9cbc3ceabcd7 100644 (file)
@@ -134,6 +134,7 @@ totpages    integer total pages to transmit
 tottries       integer total number of attempts to send job
 tts    integer time to send job
 useccover      integer whether or not to use a continuation cover page
+usexvres       integer whether or not to use highest vertical resolution
 .fi
 .RE
 .SH "PARAMETERS"
@@ -531,6 +532,10 @@ process as soon as possible.
 .B useccover
 1 if the job should use a continuation cover page during
 retransmission, 0 otherwise.
+.TP 14
+.B usexvres
+1 if the job should use the highest possible vertical
+resolution, 0 otherwise.
 See 
 .IR hylafax-server (${MANNUM4_5})
 for a description of continuation cover pages.
index 8a1424ec1ce1937a1be9478fe812ed43db9705c4..330ebce01c14634ecdd6dd20a0eb365c4db74c2f 100644 (file)
@@ -68,7 +68,7 @@ calledBefore  boolean device has previously answered at this number
 dialFailures   number  count of consecutive failed dial operations
 lastDialFailure        string  reason for last failed dial operation
 lastSendFailure        string  reason for last failed send attempt
-maxPageWidth   number  maximum page width in pixels
+maxPageWidth   number  maximum page width in pixels in normal resolution
 maxPageLength  number  maximum page length in millimeters
 maxSignallingRate      string  maximum signalling rate (bits/sec) to use
 minScanlineTime        string  minimum scanline time
@@ -80,7 +80,8 @@ pageSource    string  parameter to tell the paging central who we are
 pagingProtocol string  protocol (IXO or UCP) for this provider
 remoteCSI      string  remote device Called Subscriber Identification
 sendFailures   number  count of consecutive failed send attempts
-supportsHighRes        boolean accepts 196 line/inch images
+supportsHighRes        boolean accepts 196 line/inch images (obsolete)
+supportsVRes   number  vertical resolution support bitmask
 supports2DEncoding     boolean accepts Group 3 2D encoding
 supportsMMR    boolean accepts Group 4 encoding
 supportsPostScript     boolean accepts Adobe \*(Ps transfer protocol
index f635ad09ad9dc49d7f995dec101e6b97b7867248..f94739ea831364b45534a2e056993013e7a0d1c7 100644 (file)
@@ -357,6 +357,15 @@ one should always include proper identification (e.g. a phone
 number) in the imaged taglines.\fP
 .IR 
 .TP 12
+.B \-G
+Enable usage of any extended resolutions supported by the receiver.
+.B \-G
+supercedes the usage of any
+.B \-l
+or
+.B \-m
+options.  Beware that increased resolution will increase transmission time.
+.TP 12
 .BI \-h " \fR[\fPmodem\fR@]\fPhost\fR[\fP:port\fR]\fP"
 Force the jobs to be processed on a specific
 .I host
index 1014e17ac070bc6eb2277cb48950a66938c8dbe5..b641c4216202bfb31900b668dca4f87fd529ec21 100644 (file)
@@ -134,6 +134,7 @@ totpages    integer total pages to transmit
 tottries       integer total number of attempts to send job
 tts    integer time to send job
 useccover      integer whether or not to use a continuation cover page
+usexvres       integer whether or not to use highest vertical resolution
 .fi
 .RE
 .SH "PARAMETERS"
@@ -535,6 +536,10 @@ process as soon as possible.
 .B useccover
 1 if the job should use a continuation cover page during
 retransmission, 0 otherwise.
+.TP 14
+.B usexvres
+1 if the job should use the highest possible vertical
+resolution, 0 otherwise.
 See 
 .IR hylafax-server (${MANNUM4_5})
 for a description of continuation cover pages.
index aa9c2796c31014a979cf33110bac37dcdc46127a..4c2d92fd9a16ef1cbcc2de4200dca11f08a8a702 100644 (file)
@@ -91,7 +91,7 @@ sendFaxApp::run(int argc, char** argv)
     int verbose = 0;
     SendFaxJob& proto = getProtoJob();
     db = new FaxDB(tildeExpand(dbName));
-    while ((c = Sys::getopt(argc, argv, "a:b:B:c:C:d:f:F:h:i:I:k:M:P:r:s:t:T:U:V:W:x:X:y:Y:z:123lmnpvwADENR")) != -1) {
+    while ((c = Sys::getopt(argc, argv, "a:b:B:c:C:d:f:F:h:i:I:k:M:P:r:s:t:T:U:V:W:x:X:y:Y:z:123lmnpvwADEGNR")) != -1) {
         if (c != 'h')
             optionsUsed = false;
         switch (c) {
@@ -138,6 +138,9 @@ sendFaxApp::run(int argc, char** argv)
         case 'f':                      // sender's identity
             setFromIdentity(optarg);
             break;
+        case 'G':                      // extended resolutions
+            proto.setUseXVRes(true);
+            break;
         case 'h':                      // server's host
             setHost(optarg);
             break;
@@ -156,7 +159,7 @@ sendFaxApp::run(int argc, char** argv)
         case 'M':                      // desired min-scanline time
             proto.setDesiredMST(optarg);
             break;
-        case 'm':                      // medium resolution
+        case 'm':                      // fine resolution
             proto.setVResolution(196.);
             break;
         case 'n':                      // no cover sheet
index 1a93aa42488e91e93fcaed1ff6f1272aa2215c7e..97e0fd935ba473c3894f4e7353e8d0fb23cb9a91 100644 (file)
@@ -100,7 +100,7 @@ Class2Params::is2D() const
  */
 u_int Class2Params::vrDISTab[2] = {
     0,                         // VR_NORMAL
-    DIS_7MMVRES                        // VR_FINE
+    DIS_7MMVRES,               // VR_FINE
 };
 u_int Class2Params::dfDISTab[4] = {
     0,                         // 1-D MR
@@ -233,7 +233,18 @@ u_int Class2Params::DISstTab[8] = {
 void
 Class2Params::setFromDIS(u_int dis, u_int xinfo)
 {
+    // VR is a bitmap of available settings, not a maximum
     vr = DISvrTab[(dis & DIS_7MMVRES) >> 9];
+    if (xinfo & DIS_METRES) {
+       if (xinfo & DIS_200X400) vr |= VR_R8;
+       if (xinfo & DIS_400X400) vr |= VR_R16;
+    }
+    if (xinfo & DIS_INCHRES) {
+       vr |= VR_200X100;
+       if (dis & DIS_7MMVRES) vr |= VR_200X200;
+       if (xinfo & DIS_200X400) vr |= VR_200X400;
+       if (xinfo & DIS_300X300) vr |= VR_300X300;
+    }
     /*
      * Beware that some modems (e.g. the Supra) indicate they
      * support the V.17 bit rates, but not the normal V.27+V.29
@@ -285,7 +296,20 @@ void
 Class2Params::setFromDCS(u_int dcs, u_int xinfo)
 {
     setFromDIS(dcs, xinfo);
-    br = DCSbrTab[(dcs & DCS_SIGRATE) >> 10];  // override DIS setup
+    // override DIS setup
+    br = DCSbrTab[(dcs & DCS_SIGRATE) >> 10];
+    if (xinfo & DCS_INCHRES) {
+       if (xinfo & DCS_300X300) vr = VR_300X300;
+       else if (xinfo & DCS_200X400) vr = VR_200X400;
+       else if (dcs & DCS_7MMVRES) vr = VR_200X200;
+       else vr = VR_200X100;
+    } else {                   // bit 44 of DCS is 0
+       // some manufacturers don't send DCS_INCHRES with DCS_300X300
+       if (xinfo & DCS_300X300) vr = VR_300X300;
+       else if (xinfo & DCS_400X400) vr = VR_R16;
+       else if (xinfo & DCS_200X400) vr = VR_R8;
+       else vr = DISvrTab[(dcs & DCS_7MMVRES) >> 9];
+    }
 }
 
 /*
@@ -296,11 +320,13 @@ Class2Params::getDCS() const
 {
     u_int dcs = DCS_T4RCVR
            | vrDISTab[vr&1]
+           | vrDISTab[(vr>>4)&1]       // check for VR_200X200
            | brDCSTab[br&15]
            | wdDISTab[wd&7]
            | lnDISTab[ln&3]
            | dfDISTab[df&3]
            | stDCSTab[st&7]
+           | DCS_XTNDFIELD
            ;
     return (dcs);
 }
@@ -311,7 +337,16 @@ Class2Params::getDCS() const
 u_int
 Class2Params::getXINFO() const
 {
-    return (0);                                        // for now
+    // include support for extended resolutions
+    u_int dcs_xinfo = (1<<24) | (1<<16) | (1<<8)       // extension flags for 3 more bytes
+       | (vr & VR_R8 ? DCS_200X400 : 0)
+       | (vr & VR_R16 ? DCS_400X400 : 0)
+       | (vr & VR_200X100 ? DCS_INCHRES : 0)
+       | (vr & VR_200X200 ? DCS_INCHRES : 0)           // DCS_7MMVRES set in getDCS()
+       | (vr & VR_200X400 ? (DCS_200X400 | DCS_INCHRES) : 0)
+       | (vr & VR_300X300 ? (DCS_300X300 | DCS_INCHRES) : 0)
+       ;
+    return (dcs_xinfo);
 }
 
 /*
@@ -337,7 +372,7 @@ Class2Params::minScanlineSize() const
     static const u_int stTimes[8] =
        { 0, 5, 10, 10, 20, 20, 40, 40 };
     u_int ms = stTimes[st&7];
-    if ((st & 1) == 0 && vr == VR_FINE)
+    if ((st & 1) == 0 && vr > VR_NORMAL)
        ms /= 2;
     return transferSize(ms);
 }
@@ -345,7 +380,7 @@ Class2Params::minScanlineSize() const
 u_int
 Class2Params::pageWidth() const
 {
-    static const u_int widths[8] = {
+    u_int widths[8] = {
        1728,   // 1728 in 215 mm line
        2048,   // 2048 in 255 mm line
        2432,   // 2432 in 303 mm line
@@ -355,23 +390,56 @@ Class2Params::pageWidth() const
        1728,   // undefined
        1728,   // undefined
     };
+    switch (vr) {
+       case VR_300X300: 
+           widths[0] = 2592;
+           break;  
+       case VR_R16:
+           widths[0] = 3456;
+           widths[1] = 4096;
+           widths[2] = 4864;
+           widths[3] = 2432;
+           widths[4] = 1728;
+           break;
+       case VR_NORMAL:
+       case VR_FINE:
+       case VR_R8:
+       case VR_200X100:
+       case VR_200X200:
+       case VR_200X400:
+           // nothing
+           break;
+    }
     return (widths[wd&7]);
 }
 
 void
 Class2Params::setPageWidthInMM(u_int w)
 {
+    // This function is unused and doesn't support VR_300X300 and VR_R16.
     wd = (w == 255 ? WD_2048 : w == 303 ? WD_2432 : WD_1728);
 }
 
 void
 Class2Params::setPageWidthInPixels(u_int w)
 {
+    /*
+     * Here we attempt to determine the WD parameter with
+     * a pixel width which is impossible to be perfect
+     * because there are colliding values.  However,
+     * since we don't use > WD_2432, this is fine.
+     */
     wd = (w == 1728 ? WD_1728 :
          w == 2048 ? WD_2048 :
          w == 2432 ? WD_2432 :
          w == 1216 ? WD_1216 :
          w ==  864 ? WD_864 :
+         w == 3456 ? WD_1728 :
+         w == 4096 ? WD_2048 :
+         w == 4864 ? WD_2432 :
+       //w == 2432 ? WD_1216 :         // collision
+       //w == 1728 ? WD_864 :          // collision
+         w == 2592 ? WD_1728 :
                      WD_1728);
 }
 
@@ -396,22 +464,57 @@ Class2Params::setPageLengthInMM(u_int l)
                             LN_B4);
 }
 
+u_int
+Class2Params::horizontalRes() const
+{
+    /*
+     * Technically horizontal resolution depends upon the
+     * the number of pixels across the page and the page width.
+     * But, these are just used for writing TIFF tags for 
+     * received faxes, so we do this to accomodate the session
+     * parameters, even though it may be slightly off.
+     */
+    return (vr == VR_NORMAL ? 204 :
+           vr == VR_FINE ? 204 :
+           vr == VR_R8 ? 204 :
+           vr == VR_R16 ? 408 :
+           vr == VR_200X100 ? 200 :
+           vr == VR_200X200 ? 200 :
+           vr == VR_200X400 ? 200 :
+           vr == VR_300X300 ? 300 :
+           (u_int) -1);
+}
+
 u_int
 Class2Params::verticalRes() const
 {
-    return (vr == VR_NORMAL ? 98 : vr == VR_FINE ? 196 : (u_int) -1);
+    return (vr == VR_NORMAL ? 98 :
+           vr == VR_FINE ? 196 :
+           vr == VR_R8 ? 391 :
+           vr == VR_R16 ? 391 :
+           vr == VR_200X100 ? 100 :
+           vr == VR_200X200 ? 200 :
+           vr == VR_200X400 ? 400 :
+           vr == VR_300X300 ? 300 :
+           (u_int) -1);
 }
 
 void
-Class2Params::setVerticalRes(u_int res)
+Class2Params::setRes(u_int xres, u_int yres)
 {
-    vr = (res > 150 ? VR_FINE : VR_NORMAL);
+    vr = (xres > 300 && yres > 391 ? VR_R16 : 
+       xres > 204 && yres > 250 ? VR_300X300 :
+       yres > 391 ? VR_200X400 : 
+       yres > 250 ? VR_R8 : 
+       yres > 196 ? VR_200X200 :
+       yres > 150 ? VR_FINE : 
+       yres > 98 ? VR_200X100 : VR_NORMAL);
 }
 
 fxStr
 Class2Params::encodePage() const
 {
-    int v = (vr&1) | ((wd&7)<<1) | ((ln&3)<<4) | ((df&3)<<6);
+    int v = (vr&3) | ((wd&7)<<1) | ((ln&3)<<4) | ((df&3)<<6);
     return fxStr(v, "%02x");
 }
 
@@ -430,7 +533,7 @@ Class2Params::decodePage(const char* s)
 u_int
 Class2Params::encode() const
 {
-    return  ((vr&7)<<0)
+    return  (vr > 4 ? ((vr>>4)&7)<<0 : (vr&7)<<0)      // push inch resolutions
          | ((br&15)<<3)
          | ((wd&7)<<9)
          | ((ln&3)<<12)
@@ -446,7 +549,7 @@ void
 Class2Params::decode(u_int v)
 {
     if (v>>21 == 1) {          // check version
-       vr = (v>>0) & 7;
+       vr = ((v>>0) & 7);      // VR is a bitmap
        br = (v>>3) & 15;
        wd = (v>>9) & 7;
        ln = (v>>12) & 3;
@@ -501,12 +604,37 @@ Class2Params::decodeCaps(u_int v)
 /*
  * Routines for printing some Class 2 capabilities.
  */
-const char* Class2Params::verticalResNames[2] = {
+const char* Class2Params::verticalResNames[65] = {
     "3.85 line/mm",
     "7.7 line/mm",
+    "15.4 line/mm", "",
+    "R16 x 15.4 line/mm", "", "", "",
+    "200 x 100 dpi", "", "", "", "", "", "", "",
+    "200 x 200 dpi", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+    "200 x 400 dpi", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+    "300 x 300 dpi"
 };
+
 const char* Class2Params::verticalResName() const
-    { return (verticalResNames[vr&1]); }
+    { return (verticalResNames[vr & VR_ALL]); }
+
+const char* Class2Params::bestVerticalResName() const
+{
+    /*
+     * "Best" is determined by comparing pixels per square
+     * area of image.  Thus 300x300 is "better" than 200x400.
+     */
+    u_int res = VR_NORMAL;     // required default
+    if (vr & VR_200X100)       res = VR_200X100;
+    if (vr & VR_FINE)          res = VR_FINE;
+    if (vr & VR_200X200)       res = VR_200X200;
+    if (vr & VR_R8)            res = VR_R8;
+    if (vr & VR_200X400)       res = VR_200X400;
+    if (vr & VR_300X300)       res = VR_300X300;
+    if (vr & VR_R16)           res = VR_R16;
+    return(verticalResNames[res]);
+}
+
 
 const char* Class2Params::bitRateNames[16] = {
     "2400 bit/s",              // BR_2400
@@ -562,11 +690,11 @@ const char* Class2Params::dataFormatName() const
      { return (dataFormatNames[df&3]); }
 
 const char* Class2Params::pageWidthNames[8] = {
-    "page width 1728 pixels in 215 mm",
-    "page width 2048 pixels in 255 mm",
-    "page width 2432 pixels in 303 mm",
-    "page width 1216 pixels in 151 mm",
-    "page width 864 pixels in 107 mm",
+    "A4 page width (215 mm)",
+    "B4 page width (255 mm)",
+    "A3 page width (303 mm)",
+    "page width 151 mm",
+    "page width 107 mm",
     "undefined page width (wd=5)",
     "undefined page width (wd=6)",
     "undefined page width (wd=7)",
index 3df0e0bfadceb78d6b05b1f81106d6390f770e7e..1449eef15ee186986ccfc5055ee6243501e5eb2b 100644 (file)
@@ -36,7 +36,7 @@ private:
 // XXX these exist solely for FaxModem
     static const char* pageWidthNames[8];
     static const char* pageLengthNames[4];
-    static const char* verticalResNames[2];
+    static const char* verticalResNames[65];
     static const char* scanlineTimeNames[8];
     static const char* dataFormatNames[4];
     static const char* ecmNames[4];
@@ -91,7 +91,8 @@ public:
     u_int pageLength() const;          // page length in mm
     void setPageLengthInMM(u_int l);
     u_int verticalRes() const;         // lines/inch
-    void setVerticalRes(u_int res);
+    u_int horizontalRes() const;       // dpi
+    void setRes(u_int xres, u_int yres);
 
     static const char* bitRateNames[16];       // XXX needed by Class 1 driver
 
@@ -100,6 +101,7 @@ public:
     const char* bitRateName() const;
     u_int bitRate() const;             // bits/second value
     const char* verticalResName() const;
+    const char* bestVerticalResName() const;
     const char* scanlineTimeName() const;
     const char* dataFormatName() const;
     const char* ecmName() const;
index 1e2ab001b937b582fedfd2d3bfc834bf72f5c8cc..eccd582f88f59a324c608f6771aabc82f6ca9915 100644 (file)
@@ -1629,6 +1629,7 @@ const FaxClient::FaxFmtHeader FaxClient::jobFormats[] = {
     { 'x',     "MaxDials" },   // x (maxdials)
     { 'y',     "TotPages" },   // y (totpages)
     { 'z',     "TTS" },        // z (tts)
+    { '0',     "UseXVres" },   // 0 (usexvres as symbol)
     { '\0' },
 };
 void FaxClient::getJobStatusHeader(fxStr& header)
index 000488d9e37cd74ae9e19d87fe5b41bfe43c754c..f3ebf6f3eb180469af1ecd3163fac1982e1d7551 100644 (file)
@@ -73,6 +73,7 @@ SendFaxJob::SendFaxJob(const SendFaxJob& other)
     autoCover = other.autoCover;
     coverIsTemp = other.coverIsTemp;
     sendTagLine = other.sendTagLine;
+    useXVRes = other.useXVRes;
     retryTime = other.retryTime;
     hres = other.hres;
     vres = other.vres;
@@ -145,6 +146,7 @@ SendFaxJob::setupConfig()
 
     autoCover = true;
     sendTagLine = false;               // default is to use server config
+    useXVRes = false;                  // default is to use normal or fine
     notify = FAX_DEFNOTIFY;            // default notification
     mailbox = "";
     priority = FAX_DEFPRIORITY;                // default transmit priority
@@ -186,6 +188,8 @@ SendFaxJob::setConfigItem(const char* tag, const char* value)
        setDesiredMST(value);
     else if (streq(tag, "desiredec"))
        setDesiredEC(FaxConfig::getBoolean(value));
+    else if (streq(tag, "usexvres"))
+       setUseXVRes(FaxConfig::getBoolean(value));
     else if (streq(tag, "desireddf"))
        setDesiredDF(value);
     else if (streq(tag, "retrytime"))
@@ -379,6 +383,7 @@ SendFaxJob::setDesiredMST(const char* v)
 }
 void SendFaxJob::setDesiredMST(int v)                  { desiredst = v; }
 void SendFaxJob::setDesiredEC(bool b)                  { desiredec = b; }
+void SendFaxJob::setUseXVRes(bool b)                   { useXVRes = b; }
 void
 SendFaxJob::setDesiredDF(const char* v)
 {
@@ -497,6 +502,9 @@ SendFaxJob::createJob(SendFaxClient& client, fxStr& emsg)
        CHECKPARM("USETAGLINE", true)
        CHECKPARM("TAGLINE", tagline)
     }
+    if (useXVRes) {
+       CHECKPARM("USEXVRES", true)
+    }
     if (doneop == "archive") {
        CHECKPARM("DONEOP", "archive")
     }
index 1990584d3a41d49d127e7a2c4703b80687d7b5d5..c3f520443188d5a0e6f7a6e00d252a2a57429018 100644 (file)
@@ -93,6 +93,7 @@ private:
     fxStr      fromcompany;            // rec. from company for cover page
 
     bool       sendTagLine;            // if true, use custom tagline format
+    bool       useXVRes;               // if true, use extended resolutions
     fxStr      killTime;               // job's time to be killed
     fxStr      sendTime;               // job's time to be sent
     u_int      retryTime;              // retry time for failures (secs)
@@ -250,6 +251,8 @@ public:
     int getDesiredMST() const;
     void setDesiredEC(bool b); // desired use of Error Correction mode
     bool getDesiredEC() const;
+    void setUseXVRes(bool b);          // desired use of extended resolutions
+    bool getUseXVRes() const;
     void setDesiredDF(int);            // desired data format
     void setDesiredDF(const char*);
     int getDesiredDF() const;
@@ -303,6 +306,7 @@ inline int SendFaxJob::getMinSpeed() const          { return minsp; }
 inline int SendFaxJob::getDesiredSpeed() const         { return desiredbr; }
 inline int SendFaxJob::getDesiredMST() const           { return desiredst; }
 inline bool SendFaxJob::getDesiredEC() const           { return desiredec; }
+inline bool SendFaxJob::getUseXVRes() const            { return useXVRes; }
 inline int SendFaxJob::getDesiredDF() const            { return desireddf; }
 inline const fxStr& SendFaxJob::getTagLineFormat() const{ return tagline; }
 inline u_int SendFaxJob::getChopHandling() const       { return pagechop; }
index fff8ebf63684003555833775e8bfb0ec7e32f986..425060b1ca8904f07681c8f30c60368513957df4 100644 (file)
@@ -53,16 +53,15 @@ const u_short SERVICE_VOICE  = BIT(8);      // voice service (ZyXEL extension)
 const u_short SERVICE_ALL       = BIT(9)-1;
 
 // t.30 session subparameter codes
-// NB: only the first two are used
-const u_int VR_NORMAL  = 0;            // 98 lpi
-const u_int VR_FINE    = 1;            // 196 lpi
-const u_int VR_R8              = 2;            // R8  x 15.4 l/mm
-const u_int VR_R16     = 4;            // R16 x 15.4 l/mm
-const u_int VR_200X100 = 8;            // 200 dpi x 100 l/25.4mm
-const u_int VR_200X200 = 10;           // 200 dpi x 200 l/25.4mm
-const u_int VR_200X400 = 20;           // 200 dpi x 400 l/25.4mm
-const u_int VR_300X300 = 40;           // 300 dpi x 300 l/25.4mm
-const u_int VR_ALL     = BIT(VR_FINE+1)-1;
+const u_int VR_NORMAL  = 0x00;         // 98 lpi
+const u_int VR_FINE    = 0x01;         // 196 lpi
+const u_int VR_R8      = 0x02;         // R8  x 15.4 l/mm
+const u_int VR_R16     = 0x04;         // R16 x 15.4 l/mm
+const u_int VR_200X100 = 0x08;         // 200 dpi x 100 l/25.4mm
+const u_int VR_200X200 = 0x10;         // 200 dpi x 200 l/25.4mm
+const u_int VR_200X400 = 0x20;         // 200 dpi x 400 l/25.4mm
+const u_int VR_300X300 = 0x40;         // 300 dpi x 300 l/25.4mm
+const u_int VR_ALL     = 0x7F;
 
 const u_short BR_2400  = 0;            // 2400 bit/s
 const u_short BR_4800  = 1;            // 4800 bit/s
index 991aba735c546177f0bb64b8b7eb48b1780b2c4a..00f19df693dd861e87741769cf15c7e387626f88 100644 (file)
@@ -95,12 +95,29 @@ main(int argc, char** argv)
 
     Class2Params params;
     uint32 v;
+    float vres = 3.85;                                 // XXX default
+    float hres = 8.03;
 #ifdef TIFFTAG_FAXRECVPARAMS
-    if (TIFFGetField(tif, TIFFTAG_FAXRECVPARAMS, &v))
+    if (TIFFGetField(tif, TIFFTAG_FAXRECVPARAMS, &v)) {
        params.decode((u_int) v);                       // page transfer params
-    else {
+       // inch & metric resolutions overlap and are distinguished by yres
+       TIFFGetField(tif, TIFFTAG_YRESOLUTION, &vres);
+       switch ((u_int) vres) {
+           case 100:
+               params.vr = VR_200X100;
+               break;
+           case 200:
+               params.vr = VR_200X200;
+               break;
+           case 400:
+               params.vr = VR_200X400;
+               break;
+           case 300:
+               params.vr = VR_300X300;
+               break;
+       }
+    } else {
 #endif
-    float vres = 3.85;                                 // XXX default
     if (TIFFGetField(tif, TIFFTAG_YRESOLUTION, &vres)) {
        uint16 resunit = RESUNIT_INCH;                  // TIFF spec default
        TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
@@ -108,8 +125,14 @@ main(int argc, char** argv)
            vres /= 25.4;
        if (resunit == RESUNIT_NONE)
            vres /= 720.0;                              // postscript units ?
+       if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &hres)) {
+           if (resunit == RESUNIT_INCH)
+               hres /= 25.4;
+           if (resunit == RESUNIT_NONE)
+               hres /= 720.0;                          // postscript units ?
+        }
     }
-    params.setVerticalRes((u_int) vres);               // resolution
+    params.setRes((u_int) hres, (u_int) vres);         // resolution
     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &v);
     params.setPageWidthInPixels((u_int) v);            // page width
     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &v);
@@ -145,9 +168,21 @@ main(int argc, char** argv)
        date = buf;
     }
     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &v);
-    float h = v / (params.verticalRes() < 100 ? 3.85 : 7.7);
+    float h = v / (params.vr == VR_NORMAL ? 3.85 : 
+       params.vr == VR_200X100 ? 3.94 : 
+       params.vr == VR_FINE ? 7.7 :
+       params.vr == VR_200X200 ? 7.87 : 
+       params.vr == VR_R8 ? 15.4 : 
+       params.vr == VR_200X400 ? 12.81 : 
+       params.vr == VR_300X300 ? 9.14 : 15.4);
     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &v);
-    float w = (v / 204.) * 25.4;
+    float w = v / (params.vr == VR_NORMAL ? 8.0 : 
+       params.vr == VR_200X100 ? 8.00 : 
+       params.vr == VR_FINE ? 8.00 :
+       params.vr == VR_200X200 ? 8.00 : 
+       params.vr == VR_R8 ? 8.00 : 
+       params.vr == VR_200X400 ? 8.00 : 
+       params.vr == VR_300X300 ? 12.01 : 16.01);
     time_t time = 0;
     u_int npages = 0;                                  // page count
     do {
@@ -160,10 +195,14 @@ main(int argc, char** argv)
     TIFFClose(tif);
 
     printf("%11s %u\n", "Pages:", npages);
-    if (params.verticalRes() == 98)
+    if (params.vr == VR_NORMAL)
        printf("%11s Normal\n", "Quality:");
-    else if (params.verticalRes() == 196)
+    else if (params.vr == VR_FINE)
        printf("%11s Fine\n", "Quality:");
+    else if (params.vr == VR_R8)
+       printf("%11s Superfine\n", "Quality:");
+    else if (params.vr == VR_R16)
+       printf("%11s Hyperfine\n", "Quality:");
     else
        printf("%11s %u lines/inch\n", "Quality:", params.verticalRes());
     PageSizeInfo* info = PageSizeInfo::getPageSizeBySize(w, h);
index 19c6752cbf10461b7c64ea9427138266b2c700b7..7106c284ae59a336d3016b35d95d1c4bd071f8e3 100644 (file)
@@ -72,7 +72,7 @@ do
     -o)        shift; out="$1" ;;
     -w) shift; pagewidth="$1" ;;
     -l) shift; pagelength="$1" ;;
-    -r)        shift; vres="$1" ;;
+    -r) shift; vres="$1" ;;
     -m) shift;;                                # NB: not implemented
     -1) device=tiffg3 ;;
     -2) ($PS -h | grep tiffg32d >/dev/null 2>&1) \
@@ -90,9 +90,9 @@ do
 done
 test -z "$fil" && fil="-"              # read from stdin
 case "${pagewidth}x${pagelength}" in
-1728x280|1728x279)             # 279.4mm is actually correct...
+1728x280|1728x279|2592x280|2592x279|3456x280|3456x279) # 279.4mm is actually correct...
     paper=letter;;
-1728x364) 
+1728x364|2592x364|3456x364
     paper=legal;;
 *x296|*x297)                   # more roundoff problems...
     paper=a4;;
@@ -103,6 +103,29 @@ case "${pagewidth}x${pagelength}" in
     exit 254;;                 # causes document to be rejected
 esac
 
+# The image must end up with a pixel width according to T.32 Table 21.
+# Ghostscript contains code to fixate a4 and letter to 1728 pixels
+# when using 196-204 dpi, but not for the others, thus the floats.
+case "$paper" in
+    a4)
+       case "$pagewidth" in
+           2592) hres=313.65;;         # VR_R300X300
+           3456) hres=418.20;;         # VR_R16
+           *) hres=209.10;;            # everything else, 1728 pixels
+       esac;;
+    b4)                                        # no 300x300 available with B4
+       case "$pagewidth" in
+           4096) hres=415.95;;         # VR_R16
+           *) hres=207.98;;            # everything else, 2048 pixels
+       esac;;
+    *)                                 # letter, legal
+       case "$pagewidth" in
+           2592) hres=304.94;;         # VR_R300X300
+           3456) hres=406.59;;         # VR_R16
+           *) hres=203.29;;            # everything else, 1728 pixels
+       esac;;
+esac
+
 #
 # The sed work fixes bug in Windows-generated
 # PostScript that causes certain international
@@ -123,6 +146,6 @@ $PS -q \
     -sPAPERSIZE=$paper \
     -dFIXEDMEDIA \
     -dBATCH \
-    -r204x$vres \
+    -r$hres\x$vres \
     "-sOutputFile=$out" \
     $fil
index e7cdd497659578251498e0f6f2106e123574136e..eb138e67fff6b73c3c426be8ae70ba25c8dcc896 100644 (file)
@@ -90,9 +90,9 @@ do
 done
 test -z "$fil" && fil="-"              # read from stdin
 case "${pagewidth}x${pagelength}" in
-1728x280|1728x279)             # 279.4mm is actually correct...
+1728x280|1728x279|2592x280|2592x279|3456x280|3456x279) # 279.4mm is actually correct...
     paper=letter;;
-1728x364) 
+1728x364|2592x364|3456x364
     paper=legal;;
 *x296|*x297)                   # more roundoff problems...
     paper=a4;;
@@ -103,6 +103,29 @@ case "${pagewidth}x${pagelength}" in
     exit 254;;                 # causes document to be rejected
 esac
 
+# The image must end up with a pixel width according to T.32 Table 21.
+# Ghostscript contains code to fixate a4 and letter to 1728 pixels
+# when using 196-204 dpi, but not for the others, thus the floats.
+case "$paper" in
+    a4)
+       case "$pagewidth" in
+           2592) hres=313.65;;         # VR_R300X300
+           3456) hres=418.20;;         # VR_R16
+           *) hres=209.10;;            # everything else, 1728 pixels
+       esac;;
+    b4)                                        # no 300x300 available with B4
+       case "$pagewidth" in
+           4096) hres=415.95;;         # VR_R16
+           *) hres=207.98;;            # everything else, 2048 pixels
+       esac;;
+    *)                                 # letter, legal
+       case "$pagewidth" in
+           2592) hres=304.94;;         # VR_R300X300
+           3456) hres=406.59;;         # VR_R16
+           *) hres=203.29;;            # everything else, 1728 pixels
+       esac;;
+esac
+
 #
 # The sed work fixes bug in Windows-generated
 # PostScript that causes certain international
@@ -122,6 +145,6 @@ $CAT $fil | $PS -q \
     -dSAFER=true \
     -sPAPERSIZE=$paper \
     -dFIXEDMEDIA \
-    -r204x$vres \
+    -r$hres\x$vres \
     "-sOutputFile=$out" \
     -