]> git.ipfire.org Git - thirdparty/HylaFAX.git/commitdiff
Bug 224: add JBIG send support (via RTFCC), improve dataformat logging
authorLee Howard <faxguy@howardsilvan.com>
Tue, 27 Sep 2005 18:38:21 +0000 (18:38 +0000)
committerLee Howard <faxguy@howardsilvan.com>
Tue, 27 Sep 2005 18:38:21 +0000 (18:38 +0000)
         and handling

25 files changed:
CHANGES
config.h.in
configure
defs.in
faxd/Class1.c++
faxd/Class1.h
faxd/Class1Send.c++
faxd/Class2Send.c++
faxd/CopyQuality.c++
faxd/FaxModem.c++
faxd/FaxModem.h
faxd/FaxSend.c++
faxd/MemoryDecoder.c++
faxd/MemoryDecoder.h
faxd/Modem.c++
faxd/Modem.h
faxd/ModemConfig.c++
faxd/ModemConfig.h
faxd/NSF.c++
man/hylafax-config.4f
util/Class2Params.c++
util/Class2Params.h
util/class2.h
util/recvstats.sh.in
util/xferfaxstats.sh.in

diff --git a/CHANGES b/CHANGES
index a9c31f7633f224372a95efe837cd8cca8d62f1fd..f5d6da7cd45e6ae976576ed151bf2e51af148be2 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,8 @@
 
 Changelog for HylaFAX
 
+* improve dataformat reporting and handling (27 Sep 2005)
+* add JBIG send support (27 Sep 2005)
 * add hasV17Trouble detection on sending (27 Sep 2005)
 * improve NSF station ID detection (27 Sep 2005)
 * session logging improvements (27 Sep 2005)
index de5e35055109bee3efcac49f336665f8b878e8aa..f9749c8e754b4770084d32b914e7e7fe6f7a0bba 100644 (file)
  */
 @HAVE_PAM@
 
+/*
+ * JBIG library support
+ */
+@HAVE_JBIG@
+
 #endif
index aa2b42e8b1c5b52a881861c9e91d70917509525c..3f9fca36e5381f83c99a5f20fc3683bfc3366ede 100755 (executable)
--- a/configure
+++ b/configure
@@ -181,7 +181,9 @@ LLDOPTS
 LN
 LN_S
 HAVE_PAM
-PAMLIBS"
+PAMLIBS
+HAVE_JBIG
+LIBJBIG"
 
 VAR2="MACHDEPLIBS
 MAKECXXOVERRIDE
@@ -1618,6 +1620,23 @@ if [ "$DISABLE_PAM" != "yes" ]; then
 else
        Note "Disabling PAM support"
 fi
+HAVE_JBIG="/*#define HAVE_JBIG 1*/"
+LIBJBIG=""
+if [ "$DISABLE_JBIG" != "yes" ]; then
+       Note "Checking for JBIG library support"
+       CheckForLibrary jbg_enc_init -ljbig &&
+               CheckForIncludeFile jbig.h && {
+                       HAVE_JBIG="#define HAVE_JBIG 1"
+                       LIBJBIG="-ljbig"
+               }
+       if [ "x$LIBJBIG" = "x" ]; then
+               Note "... not found. Disabling JBIG support"
+       else
+               Note "... found. Enabling JBIG support"
+       fi
+else
+       Note "Disabling JBIG support"
+fi
 CheckForLibrary crypt -lc || {
     #
     # FreeBSD-2.1 in particular needs -lcrypt.
diff --git a/defs.in b/defs.in
index c55175e1c1653a4a60a6a361cf4541640fe1f6a9..50fc21ffdbaadd08d5836a37631b9fc8cc78df30 100644 (file)
--- a/defs.in
+++ b/defs.in
@@ -134,7 +134,7 @@ CVERSION    = @ENVOPTS@
 C++FILE                = @CXXFILE@
 
 # default definitions for programs--overide them as desired
-LIBS           = ${LIBUTIL} @PAMLIBS@
+LIBS           = ${LIBUTIL} @PAMLIBS@ @LIBJBIG@
 LLDLIBS                = ${LIBS} ${LIBTIFF} ${LIBZ} ${LIBREGEX} ${LIBPORT} ${MACHDEPLIBS}
 #
 # Override this definition to eliminate shared library use.
index 51b9f56b19d505b23f7598216aa37ba2984b9845..d7450349dd1f2f7e69fda7d87a29c3645fba78c7 100644 (file)
@@ -238,6 +238,7 @@ Class1Modem::pokeConfig()
     if (conf.class1ECMSupport) {
        modemParams.ec = BIT(EC_DISABLE) | BIT(EC_ENABLE64) | BIT(EC_ENABLE256);
        modemParams.df |= BIT(DF_2DMMR);
+       if (conf.class1JBIGSupport) modemParams.df |= BIT(DF_JBIG);
     } else
        modemParams.ec = BIT(EC_DISABLE);
 }
@@ -1565,8 +1566,10 @@ Class1Modem::modemDIS() const
 
     if (conf.class1ECMSupport) {
        // JBIG
-       if (conf.class1JBIGBasicSupport)
+       if (conf.class1JBIGSupport) {
            dis_caps.setBit(FaxParams::BITNUM_JBIG_BASIC, true);
+           dis_caps.setBit(FaxParams::BITNUM_JBIG_L0, true);   // JBIG library can handle L0 = 1-Yd
+       }
 /* - disabled for now
        // JBIG grey/color requires JPEG grey/color
        if (conf.class1GreyJBIGSupport || conf.class1ColorJBIGSupport) {
@@ -1576,7 +1579,6 @@ Class1Modem::modemDIS() const
        if (conf.class1ColorJBIGSupport)
            dis_caps.setBit(FaxParams::BITNUM_FULLCOLOR, true);
 */
-
        // JPEG
        if (conf.class1GreyJPEGSupport || conf.class1ColorJPEGSupport)
            dis_caps.setBit(FaxParams::BITNUM_JPEG, true);
index d774cb0ad43f1a5ef3c5b753672e8c500f042b90..ceb6bfc1904f08eec677f51c0781cc8bd72408e9 100644 (file)
@@ -126,7 +126,7 @@ protected:
     bool       sendTCF(const Class2Params&, u_int ms);
     bool       sendPage(TIFF* tif, Class2Params&, u_int, u_int, fxStr& emsg);
     bool       sendPageData(u_char* data, u_int cc, const u_char* bitrev, bool ecm, fxStr& emsg);
-    bool       sendRTC(Class2Params params, u_int ppmcmd, int lastbyte, fxStr& emsg);
+    bool       sendRTC(Class2Params params, u_int ppmcmd, int lastbyte, uint32 rowsperstrip, fxStr& emsg);
     bool       sendPPM(u_int ppm, HDLCFrame& mcf, fxStr& emsg);
     bool       decodePPM(const fxStr& pph, u_int& ppm, fxStr& emsg);
 // reception support
index e9b32c718edb67170af5fa9abecf144ce8f1a3c3..3854222fe52829187582aa603f00249bbd14d036 100644 (file)
@@ -1570,8 +1570,20 @@ Class1Modem::sendPageData(u_char* data, u_int cc, const u_char* bitrev, bool ecm
  * send all the data they are presented.
  */
 bool
-Class1Modem::sendRTC(Class2Params params, u_int ppmcmd, int lastbyte, fxStr& emsg)
+Class1Modem::sendRTC(Class2Params params, u_int ppmcmd, int lastbyte, uint32 rows, fxStr& emsg)
 {
+    if (params.df == DF_JBIG) {
+       /*
+        * If we ever needed to send NEWLEN or other JBIG-terminating
+        * markers this is where we would do it.
+        */
+       //u_char newlen[8] = { 0xFF, 0x05, 
+       //    (rows>>24)&0xFF, (rows>>16)&0xFF, (rows>>8)&0xFF, rows&0xFF,
+       //    0xFF, 0x02 };     // SDNORM is added per spec
+       //return sendClass1ECMData(newlen, 8, rtcRev, true, ppmcmd, emsg);
+       return sendClass1ECMData(NULL, 0, rtcRev, true, ppmcmd, emsg);
+    }
+
     // determine the number of trailing zeros on the last byte of data
     u_short zeros = 0;
     for (short i = 7; i >= 0; i--) {
@@ -1686,6 +1698,7 @@ Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppm
     protoTrace("SEND begin page");
 
     tstrip_t nstrips = TIFFNumberOfStrips(tif);
+    uint32 rowsperstrip = 0;
     if (nstrips > 0) {
 
        /*
@@ -1738,7 +1751,6 @@ Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppm
                off += (u_int) sbc;
        }
        totdata -= pageChop;            // deduct trailing white space not sent
-       uint32 rowsperstrip;
        TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
        if (rowsperstrip == (uint32) -1)
            TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &rowsperstrip);
@@ -1756,6 +1768,12 @@ Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppm
        } else
            dp = data;
 
+       /*
+        * After a page chop rowsperstrip is no longer valid, as the strip will
+        * be shorter.  Therefore, convertPhaseCData (for the benefit of JBIG) and 
+        * correctPhaseCData deliberately update rowsperstrip.
+        */
+
        if (conf.softRTFCC && params.df != newparams.df) {
            switch (params.df) {
                case DF_1DMH:
@@ -1768,14 +1786,15 @@ Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppm
                    protoTrace("Reading MMR-compressed image file");
                    break;
            }
-           dp = convertPhaseCData(dp, totdata, fillorder, params, newparams);
+           dp = convertPhaseCData(dp, totdata, fillorder, params, newparams, rowsperstrip);
        }
        params = newparams;             // revert back
 
         /*
          * correct broken Phase C (T.4/T.6) data if neccessary 
          */
-       lastbyte = correctPhaseCData(dp, &totdata, fillorder, params);
+       if (params.df <= DF_2DMMR)
+           lastbyte = correctPhaseCData(dp, &totdata, fillorder, params, rowsperstrip);
 
        /*
         * Send the page of data.  This is slightly complicated
@@ -1789,7 +1808,7 @@ Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppm
         * modem wants the data in MSB2LSB order, but for now we'll
         * avoid the temptation to optimize.
         */
-       if (fillorder != FILLORDER_LSB2MSB) {
+       if (params.df <= DF_2DMMR && fillorder != FILLORDER_LSB2MSB) {
            TIFFReverseBits(dp, totdata);
            lastbyte = frameRev[lastbyte];
        }
@@ -1887,7 +1906,7 @@ Class1Modem::sendPage(TIFF* tif, Class2Params& params, u_int pageChop, u_int ppm
        delete data;
     }
     if (rc || abortRequested())
-       rc = sendRTC(params, ppmcmd, lastbyte, emsg);
+       rc = sendRTC(params, ppmcmd, lastbyte, rowsperstrip, emsg);
     protoTrace("SEND end page");
     if (params.ec == EC_DISABLE) {
        // these were already done by ECM protocol
index 42f4855aec94363eccf686a400e92956d3580758..2abe82b4cc6a5998ecc5fe382829e4361ef596e8 100644 (file)
@@ -481,6 +481,7 @@ Class2Modem::sendPageData(TIFF* tif, u_int pageChop)
        } else
            dp = data;
 
+       uint32 rows = 0;
        if (conf.softRTFCC && !conf.class2RTFCC && params.df != newparams.df) {
            switch (params.df) {
                case DF_1DMH:
@@ -493,13 +494,13 @@ Class2Modem::sendPageData(TIFF* tif, u_int pageChop)
                    protoTrace("Reading MMR-compressed image file");
                    break;
            }
-           dp = convertPhaseCData(dp, totdata, fillorder, params, newparams);
+           dp = convertPhaseCData(dp, totdata, fillorder, params, newparams, rows);
        }
 
         /*
          * correct broken Phase C (T.4/T.6) data if necessary
          */
-       lastByte = correctPhaseCData(dp, &totdata, fillorder, (conf.class2RTFCC ? params : newparams));
+       lastByte = correctPhaseCData(dp, &totdata, fillorder, (conf.class2RTFCC ? params : newparams), rows);
 
        params = newparams;             // revert back
 
index 8458c2b2857e57495d29fbb1352cbb280cec61aa..d4e8d2e93d65ea8d2cc0c1bd32630cfc19bbaa27 100644 (file)
@@ -380,7 +380,7 @@ setupCompression(TIFF* tif, u_int df, uint32 opts)
     case DF_JPEG_COLOR:
        TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
        break;
-    case DF_JBIG_BASIC:
+    case DF_JBIG:
        TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_JBIG);
        break;
     case DF_2DMMR:
@@ -504,9 +504,10 @@ FaxModem::writeECMData(TIFF* tif, u_char* buf, u_int cc, const Class2Params& par
                }
                break;
 
-           case DF_JBIG_BASIC:
+           case DF_JBIG:
                {
                    setupStartPage(tif, params);
+                   copyQualityTrace("BIH: Dl %d, D %d, P %d, fill %d", buf[0], buf[1], buf[2], buf[3]);
                    /*
                     * Parse JBIG BIH to get the image length.
                     *
@@ -516,19 +517,26 @@ FaxModem::writeECMData(TIFF* tif, u_char* buf, u_int cc, const Class2Params& par
                     * times the sixth byte, 256 times the seventh byte, and the eighth byte.
                     */
                    u_long framelength = 0;
-                   //Yd is byte 9, 10, 11, and 12
-                   framelength = 256*256*256*buf[9-1];
-                   framelength += 256*256*buf[10-1];
-                   framelength += 256*buf[11-1];
-                   framelength += buf[12-1];
-
-                   protoTrace("RECV: Yd field in BIH is %d", framelength);
+                   framelength = 256*256*256*buf[8];
+                   framelength += 256*256*buf[9];
+                   framelength += 256*buf[10];
+                   framelength += buf[11];
                    /*
-                    * Senders commonly use 0xFFFF and 0xFFFFFFFF as empty fill.  We ignore such large 
+                    * Senders commonly use 0xFFFF and 0xFFFFFFFF as "maximum Yd".  We ignore such large 
                     * values because if we use them and no NEWLEN marker is received, then the page
                     * length causes problems for viewers (specifically libtiff).
                     */
                    if (framelength < 65535 && framelength > recvEOLCount) recvEOLCount = framelength;
+                   copyQualityTrace("BIH: Xd %d, Yd %d, L0 %d, Mx %d, My %d",
+                       256*256*256*buf[4]+256*256*buf[5]+256*buf[6]+buf[7],
+                       framelength,
+                       256*256*256*buf[12]+256*256*buf[13]+256*buf[14]+buf[15],
+                       buf[16], buf[17]);
+                   copyQualityTrace("BIH: fill %d, HITOLO %d, SEQ %d, ILEAVE %d, SMID %d", 
+                       (buf[18]&0xF0)>>4, (buf[18]&0x8)>>3, (buf[18]&0x4)>>2, (buf[18]&0x2)>>1, buf[18]&0x1);
+                   copyQualityTrace("BIH: fill %d, LRLTWO %d, VLENGTH %d, TPDON %d, TPBON %d, DPON %d, DPPRIV %u, DPLAST %u", 
+                       (buf[19]&0x80)>>7, (buf[19]&0x40)>>6, (buf[19]&0x20)>>5, (buf[19]&0x10)>>4, (buf[19]&0x8)>>3, 
+                       (buf[19]&0x4)>>2, (buf[19]&0x2)>>1, buf[19]&0x1);
                }
                break;
 
@@ -568,20 +576,93 @@ FaxModem::writeECMData(TIFF* tif, u_char* buf, u_int cc, const Class2Params& par
            }
            break;
 
-       case DF_JBIG_BASIC:
-           //search for NEWLEN Marker Segment in JBIG Bi-Level Image Data
+       case DF_JBIG:
+           // search for Marker Segments in JBIG Bi-Level Image Data
            {
                u_long framelength = 0;
-               for (u_int i = 0; i < cc-2; i++) {
-                   if (buf[i] == 0xFF && buf[i+1] == 0x05) {
+               u_int sdnormcount = 0, i = 0;
+               if (seq & 1) i += 20;           // skip BIH
+               for (; i < cc; i++) {
+                   if (i+1 < cc && buf[i] == 0xFF && buf[i+1] == 0x04) {
+                       if (sdnormcount) {
+                           copyQualityTrace("Found %d SDNORM Marker Segments in BID", sdnormcount);
+                           sdnormcount = 0;
+                       }
+                       copyQualityTrace("Found ABORT Marker Segment in BID");
+                       i += 1;
+                       continue;
+                   }
+                   if (i+7 < cc && buf[i] == 0xFF && buf[i+1] == 0x06) {
+                       if (sdnormcount) {
+                           copyQualityTrace("Found %d SDNORM Marker Segments in BID", sdnormcount);
+                           sdnormcount = 0;
+                       }
+                       copyQualityTrace("Found ATMOVE Marker Segment in BID, Yat %d, tx %d, ty %d", 
+                           256*256*256*buf[i+2]+256*256*buf[i+3]+256*buf[i+4]+buf[i+5], buf[i+6], buf[i+7]);
+                       i += 7;
+                       continue;
+                   }
+                   if (i+6 < cc && buf[i] == 0xFF && buf[i+1] == 0x07) {
+                       if (sdnormcount) {
+                           copyQualityTrace("Found %d SDNORM Marker Segments in BID", sdnormcount);
+                           sdnormcount = 0;
+                       }
+                       u_long clength = 256*256*256*buf[i+2]+256*256*buf[i+3]+256*buf[i+4]+buf[i+5];
+                       fxStr comment = "";
+                       for (u_long cpos = 0; i+6+cpos < cc && cpos < clength; cpos++) comment.append(buf[i+6+cpos]);
+                       copyQualityTrace("Found COMMENT Marker Segment in BID, \"%s\"", (const char*) comment);
+                       i = i + clength + 5;
+                       continue;
+                   }
+                   if (i+5 < cc && buf[i] == 0xFF && buf[i+1] == 0x05) {
+                       if (sdnormcount) {
+                           copyQualityTrace("Found %d SDNORM Marker Segments in BID", sdnormcount);
+                           sdnormcount = 0;
+                       }
                        framelength = 256*256*256*buf[i+2];
                        framelength += 256*256*buf[i+3];   
                        framelength += 256*buf[i+4];
                        framelength += buf[i+5];
-
-                       protoTrace("RECV: Found NEWLEN Marker Segment in BID, Yd = %d", framelength);
+                       copyQualityTrace("Found NEWLEN Marker Segment in BID, Yd = %d", framelength);
                        if (framelength < 65535) recvEOLCount = framelength;
+                       i += 5;
+                       continue;
+                   }
+                   if (i+1 < cc && buf[i] == 0xFF && buf[i+1] == 0x01) {
+                       if (sdnormcount) {
+                           copyQualityTrace("Found %d SDNORM Marker Segments in BID", sdnormcount);
+                           sdnormcount = 0;
+                       }
+                       copyQualityTrace("Found RESERVE Marker Segment in BID");
+                       i += 1;
+                       continue;
                    }
+                   if (i+1 < cc && buf[i] == 0xFF && buf[i+1] == 0x02) {
+                       sdnormcount++;
+                       i += 1;
+                       continue;
+                   }
+                   if (i+1 < cc && buf[i] == 0xFF && buf[i+1] == 0x03) {
+                       if (sdnormcount) {
+                           copyQualityTrace("Found %d SDNORM Marker Segments in BID", sdnormcount);
+                           sdnormcount = 0;
+                       }
+                       copyQualityTrace("Found SDRST Marker Segment in BID");
+                       i += 1;
+                       continue;
+                   }
+                   if (i+1 < cc && buf[i] == 0xFF && buf[i+1] != 0x00) {       // not STUFF
+                       if (sdnormcount) {
+                           copyQualityTrace("Found %d SDNORM Marker Segments in BID", sdnormcount);
+                           sdnormcount = 0;
+                       }
+                       copyQualityTrace("Found Unknown Marker %#x Segment in BID", buf[i+1]);
+                       i +=1;
+                       continue;
+                   }
+               }
+               if (sdnormcount) {
+                   copyQualityTrace("Found %d SDNORM Marker Segments in BID", sdnormcount);
                }
            }
            break;
@@ -597,13 +678,13 @@ FaxModem::writeECMData(TIFF* tif, u_char* buf, u_int cc, const Class2Params& par
                        framelength += buf[i+6];
                        framewidth = 256*buf[i+7];
                        framewidth += buf[i+8];
-                       protoTrace("RECV: Found Start of Frame (SOF) Marker, size: %lu x %lu", framewidth, framelength);
+                       copyQualityTrace("Found Start of Frame (SOF) Marker, size: %lu x %lu", framewidth, framelength);
                        if (framelength < 65535 && framelength > recvEOLCount) recvEOLCount = framelength;
                    }
                    if (buf[i] == 0xFF && buf[i+1] == 0xDC) {
                        framelength = 256*buf[i+4];
                        framelength += buf[i+5];
-                       protoTrace("RECV: Found Define Number of Lines (DNL) Marker, lines: %lu", framelength);
+                       copyQualityTrace("Found Define Number of Lines (DNL) Marker, lines: %lu", framelength);
                        if (framelength < 65535) recvEOLCount = framelength;
                    }
                }
index 44e0593854cfafdbb26f42e30f82b3973cbe1428..3da9e99e186c08b49355f01f2ef3dd4e5d2ddcd0 100644 (file)
@@ -425,6 +425,15 @@ FaxModem::supportsMMR() const
     return (modemParams.df & BIT(DF_2DMMR)) != 0;
 }
 
+/*
+ * Return whether or not the modem supports JBIG.
+ */
+bool
+FaxModem::supportsJBIG() const
+{
+    return (modemParams.df & BIT(DF_JBIG)) != 0;
+}
+
 /*
  * Return whether or not received EOLs are byte aligned.
  */
@@ -728,7 +737,7 @@ FaxModem::notifyPageSent(TIFF* tif)
 
 int
 FaxModem::correctPhaseCData(u_char* buf, u_long* pBufSize,
-                            u_int fillorder, const Class2Params& params)
+                            u_int fillorder, const Class2Params& params, uint32& rows)
 {
     u_char* endOfData;
     int lastbyte = 0;
@@ -736,6 +745,7 @@ FaxModem::correctPhaseCData(u_char* buf, u_long* pBufSize,
        MemoryDecoder dec1(buf, params.pageWidth(), *pBufSize, fillorder, params.is2D(), true);
        endOfData = dec1.cutExtraEOFB();
        lastbyte = dec1.getLastByte();
+       rows = dec1.getRows();
     } else {
        MemoryDecoder dec1(buf, params.pageWidth(), *pBufSize, fillorder, params.is2D(), false);
        dec1.fixFirstEOL();
@@ -744,6 +754,7 @@ FaxModem::correctPhaseCData(u_char* buf, u_long* pBufSize,
         */
        MemoryDecoder dec2(buf, params.pageWidth(), *pBufSize, fillorder, params.is2D(), false);
        endOfData = dec2.cutExtraRTC();
+       rows = dec2.getRows();
     }
     if( endOfData )
         *pBufSize = endOfData - buf;
@@ -752,10 +763,11 @@ FaxModem::correctPhaseCData(u_char* buf, u_long* pBufSize,
 
 u_char*
 FaxModem::convertPhaseCData(u_char* buf, u_long& totdata, u_int fillorder, 
-                           const Class2Params& params, const Class2Params& newparams)
+                           const Class2Params& params, const Class2Params& newparams, uint32& rows)
 {
     MemoryDecoder dec(buf, params.pageWidth(), totdata, fillorder, params.is2D(), (params.df == DF_2DMMR));
     u_char* data = dec.convertDataFormat(newparams);
     totdata = dec.getCC();
+    rows = dec.getRows();
     return (data);
 }
index 7744d510f4e81ec96d25b898576db42d4e6a6f4c..a1c125e5b02e0cb1086e5716931871317a0d73df 100644 (file)
@@ -159,12 +159,12 @@ protected:
  * Correct if neccessary Phase C (T.4/T.6) data (remove extra RTC/EOFB etc.)
  */
     int                correctPhaseCData(u_char* buf, u_long* pBufSize,
-                                  u_int fillorder, const Class2Params& params);
+                                  u_int fillorder, const Class2Params& params, uint32& rows);
 /*
  * Convert Phase C data...
  */
     u_char*    convertPhaseCData(u_char* buf, u_long& totdata, u_int fillorder,
-                            const Class2Params& params, const Class2Params& newparams);
+                            const Class2Params& params, const Class2Params& newparams, uint32& rows);
 public:
     enum {                     // FaxModem::RTNHandling
         RTN_RETRANSMIT = 0,         // retransmit page after RTN until MCF/MPS
@@ -183,6 +183,7 @@ public:
 // methods for querying modem capabilities
     virtual bool supports2D() const;
     virtual bool supportsMMR() const;
+    virtual bool supportsJBIG() const;
     virtual bool supportsEOLPadding() const;
     virtual bool supportsVRes(float res) const;
     virtual bool supportsPageWidth(u_int w, u_int r) const;
index 51a3ce3c78463af65d6549373c832c83012b9927..17586e833ec139d5f7f22c5b8b2b55241b26de13 100644 (file)
@@ -538,15 +538,15 @@ FaxServer::sendClientCapabilitiesOK(FaxRequest& fax, FaxMachineInfo& clientInfo,
      * use in pre-formatting documents sent in future conversations.
      */
     clientInfo.setSupportsVRes(clientCapabilities.vr);
-    clientInfo.setSupports2DEncoding(clientCapabilities.df >= DF_2DMR);
-    clientInfo.setSupportsMMR(clientCapabilities.df >= DF_2DMMR);
+    clientInfo.setSupports2DEncoding(clientCapabilities.df & BIT(DF_2DMR));
+    clientInfo.setSupportsMMR(clientCapabilities.df & BIT(DF_2DMMR));
     clientInfo.setMaxPageWidthInPixels(clientCapabilities.pageWidth());
     clientInfo.setMaxPageLengthInMM(clientCapabilities.pageLength());
     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.bestVerticalResName());
-    traceProtocol("REMOTE best format %s", clientCapabilities.dataFormatName());
+    traceProtocol("REMOTE format support: %s", (const char*) clientCapabilities.dataFormatsName());
     if (clientCapabilities.ec != EC_DISABLE)
        traceProtocol("REMOTE supports %s", clientCapabilities.ecmName());
     traceProtocol("REMOTE best %s", clientCapabilities.scanlineTimeName());
@@ -597,14 +597,31 @@ FaxServer::sendSetupParams1(TIFF* tif,
      * requested.  So, RTFCC defeats requested data formatting. :-(
      */
     if (class2RTFCC || softRTFCC) {
-       params.df = fxmin(params.df, clientCapabilities.df);
+       /*
+        * Determine the "maximum" compression.
+        *
+        * params.df prior to here represents how faxq formatted the image.
+        * clientCapabilities.df represents what formats the remote supports.
+        *
+        * Ignore what faxq did and send with the "highest" (monochrome) 
+        * compression that both the modem and the remote supports.
+        */
+       params.df = 0;
+       u_int bits = clientCapabilities.df;
+       bits &= BIT(DF_JBIG+1)-1;               // cap at JBIG, only deal with monochrome
+       while (bits) {
+           bits >>= 1;
+           if (bits) params.df++;
+       }
+       if (params.df == DF_JBIG && (!modem->supportsJBIG() || (params.ec == EC_DISABLE)))
+               params.df = DF_2DMMR;
        // even if RTFCC supported uncompressed mode (and it doesn't)
        // it's likely that the remote was incorrect in telling us it does
        if (params.df == DF_2DMRUNCOMP) params.df = DF_2DMR;
        // don't let RTFCC cause problems with restricted modems...
        if (params.df == DF_2DMMR && (!modem->supportsMMR() || (params.ec == EC_DISABLE)))
                params.df = DF_2DMR;
-       if (params.df == DF_2DMR && !modem->supports2D())
+       if (params.df == DF_2DMR && (!modem->supports2D() || !(clientCapabilities.df & BIT(DF_2DMR))))
                params.df = DF_1DMH;
     } else {
        if (compression == COMPRESSION_CCITTFAX4) {
index 921d71a95f0454ecbdb52cdda9641a617d0b58e8..00b4868848075b0528e56a49c019a6a19c768be4 100644 (file)
@@ -30,6 +30,7 @@
 #include "MemoryDecoder.h"
 #include "G3Encoder.h"
 #include "StackBuffer.h"
+#include "config.h"
 
 MemoryDecoder::MemoryDecoder(u_char* data, u_long n)
 {
@@ -39,6 +40,7 @@ MemoryDecoder::MemoryDecoder(u_char* data, u_long n)
     nblanks = 0;
     runs = NULL;
     rowBuf = NULL;
+    rows = 0;
 }
 
 MemoryDecoder::MemoryDecoder(u_char* data, u_int wid, u_long n,
@@ -48,6 +50,7 @@ MemoryDecoder::MemoryDecoder(u_char* data, u_int wid, u_long n,
     width      = wid;
     byteWidth  = howmany(width, 8);
     cc         = n;
+    rows       = 0;
     
     fillorder  = order;
     is2D       = twoDim;
@@ -250,6 +253,7 @@ u_char* MemoryDecoder::cutExtraRTC()
     }
         
     endOfData = NULL;
+    rows = 0;
     if(!RTCraised()) {
         /*
          * syncronize to the next EOL and calculate pointer to it
@@ -268,6 +272,7 @@ u_char* MemoryDecoder::cutExtraRTC()
             }
             if( seenRTC() )
                 break;
+           rows++;
         }
     }
     return endOfData;
@@ -279,6 +284,7 @@ u_char* MemoryDecoder::cutExtraEOFB()
      * MMR requires us to decode the entire image...
      */
     endOfData = NULL;
+    rows = 0;
     if(!RTCraised()) {
        endOfData = current();
         for (;;) {
@@ -287,6 +293,7 @@ u_char* MemoryDecoder::cutExtraEOFB()
             }
             if( seenRTC() )
                 break;
+           rows++;
         }
     }
     if (seenRTC() && *(endOfData - 1) == 0x00)
@@ -402,6 +409,18 @@ u_char* MemoryDecoder::encodeTagLine(u_long* raster, u_int th, u_int slop)
     }
 }
 
+#ifdef HAVE_JBIG
+extern "C" {
+#include "jbig.h"
+}
+fxStackBuffer resultBuffer;
+
+void bufferJBIGData(unsigned char *start, size_t len, void *file)
+{
+    resultBuffer.put((const char*) start, len);
+}
+#endif /* HAVE_JBIG */
+
 u_char* MemoryDecoder::convertDataFormat(const Class2Params& params)
 {
     /*
@@ -409,44 +428,96 @@ u_char* MemoryDecoder::convertDataFormat(const Class2Params& params)
      * been set up, and we don't need to worry about decoder operation here.  
      * These params are for the encoder to use.
      */
-    fxStackBuffer result;
-    G3Encoder enc(result);
-    enc.setupEncoder(fillorder, params.is2D(), (params.df == DF_2DMMR));
+    rows = 0;
+    if (params.df <= DF_2DMMR) {
+       fxStackBuffer result;
+       G3Encoder enc(result);
+       enc.setupEncoder(fillorder, params.is2D(), (params.df == DF_2DMMR));
 
-    u_char* refrow = new u_char[byteWidth*sizeof(u_char)];     // reference row
-    memset(refrow, 0, byteWidth*sizeof(u_char));               // clear to white
+       u_char* refrow = new u_char[byteWidth*sizeof(u_char)];  // reference row
+       memset(refrow, 0, byteWidth*sizeof(u_char));            // clear to white
 
-    /*
-     * For MR we encode a 1-D or 2-D line according to T.4 4.2.1.
-     * We understand that "standard" resolution means VR_NORMAL.
-     */
-    u_short k = 0;
+       /*
+        * For MR we encode a 1-D or 2-D line according to T.4 4.2.1.
+        * We understand that "standard" resolution means VR_NORMAL.
+        */
+       u_short k = 0;
 
-    if (!RTCraised()) {
-       for (;;) {
-           (void) decodeRow(rowBuf, width);
-           if(seenRTC())
-               break;
-           // encode the line specific to the desired format
-           if (params.df == DF_2DMMR) {
-               enc.encode(rowBuf, width, 1, (unsigned char*) refrow);
-           } else if (params.df == DF_2DMR) {
-               if (k) {
-                   enc.encode(rowBuf, width, 1, (unsigned char*) refrow);      // 2-D
-               } else {
-                   enc.encode(rowBuf, width, 1);                               // 1-D
-                   k = (params.vr == VR_NORMAL || params.vr == VR_200X100) ? 2 : 4;
+       if (!RTCraised()) {
+           for (;;) {
+               (void) decodeRow(rowBuf, width);
+               if(seenRTC())
+                   break;
+               rows++;
+               // encode the line specific to the desired format
+               if (params.df == DF_2DMMR) {
+                   enc.encode(rowBuf, width, 1, (unsigned char*) refrow);
+               } else if (params.df == DF_2DMR) {
+                   if (k) {
+                       enc.encode(rowBuf, width, 1, (unsigned char*) refrow);  // 2-D
+                   } else {
+                       enc.encode(rowBuf, width, 1);                           // 1-D
+                       k = (params.vr == VR_NORMAL || params.vr == VR_200X100) ? 2 : 4;
+                   }
+                   k--;
+               } else {        // DF_1DMH
+                   enc.encode(rowBuf, width, 1);
                }
-               k--;
-           } else {    // DF_1DMH
-               enc.encode(rowBuf, width, 1);
+               memcpy(refrow, rowBuf, byteWidth*sizeof(u_char));
            }
-           memcpy(refrow, rowBuf, byteWidth*sizeof(u_char));
        }
+       enc.encoderCleanup();
+       cc = result.getLength();
+       u_char* dst = new u_char[cc];
+       memcpy(dst, (const unsigned char*) result, cc);
+       return (dst);
+    } else if (params.df == DF_JBIG) {
+#ifdef HAVE_JBIG
+       char* decodedrow = new char[byteWidth];
+       fxStackBuffer raster;
+       resultBuffer = raster;          // initialize resultBuffer
+       if (!RTCraised()) {
+           for (;;) {
+               (void) decodeRow(decodedrow, width);
+               if(seenRTC())
+                   break;
+               raster.put(decodedrow, byteWidth*sizeof(u_char));
+               rows++;
+           }
+       }
+       delete decodedrow;
+       // bitmap raster is prepared, pass through JBIG encoding...
+       cc = raster.getLength();
+       u_char* rasterdst = new u_char[cc];
+       memcpy(rasterdst, (const unsigned char*) raster, cc);
+       unsigned char *pmap[1] = { rasterdst };
+       struct jbg_enc_state jbigstate;
+       jbg_enc_init(&jbigstate, width, rows, 1, pmap, bufferJBIGData, NULL);
+       /*
+        * T.85 requires "single-progressive sequential coding" and thus:
+        *
+        * Dl = 0, D = 0, P = 1 are required
+        * L0 = 128 is suggested (and appears to be standard among senders)
+        * Mx = 0 to 127 (and 0 appears to be standard)
+        * My = 0, HITOLO = 0, SEQ = 0, ILEAVE = 0, SMID = 0
+        * TPDON = 0, DPON = 0, DPPRIV = 0, DPLAST = 0
+        *
+        * As these settings vary from the library's defaults, we carefully
+        * specify all of them.
+        */
+       jbg_enc_options(&jbigstate, 0, 0, 128, 0, 0);
+       jbg_enc_out(&jbigstate);
+       jbg_enc_free(&jbigstate);
+       delete rasterdst;
+       // image is now encoded into JBIG
+       //resultBuffer[19] |= 0x20;     // set VLENGTH = 1, if someday we want to transmit NEWLEN
+       cc = resultBuffer.getLength();
+       u_char* dst = new u_char[cc];
+       memcpy(dst, (const unsigned char*) resultBuffer, cc);
+       return (dst);
+#else
+       printf("Attempt to convert Phase C data to JBIG without JBIG support.  This should not happen.\n");
+       return (NULL);
+#endif /* HAVE_JBIG */
     }
-    enc.encoderCleanup();
-    cc = result.getLength();
-    u_char* dst = new u_char[cc];
-    memcpy(dst, (const unsigned char*) result, cc);
-    return (dst);
 }
index c233994455b1fa3fa4c9bb7cc6e5748bd3716a4a..84066d9fb3e46ec9e222668b4eb242dbe0406aef 100644 (file)
@@ -36,6 +36,7 @@ private:
     u_int      width;
     u_int      byteWidth;
     u_long     cc;
+    uint32     rows;
     u_int      fillorder;
     bool       is2D, isG4;
     u_char*    endOfData;      // used by cutExtraRTC
@@ -64,6 +65,7 @@ public:
     const u_char* getEndOfPage()                       { return endOfData; }
     u_int getLastBlanks()                              { return nblanks; }
     u_long getCC()                                     { return cc; }
+    uint32 getRows()                                   { return rows; }
 };
 
 #endif
index aeb124e613e60240b9828f42a1c046d7f9ab77ae..3e9572aa853ad2e2c61a0ec3e1a3e20fb5d11802 100644 (file)
@@ -404,6 +404,15 @@ Modem::supportsMMR() const
     return caps.df & BIT(DF_2DMMR);
 }
 
+/*
+ * Return whether or not the modem supports JBIG.
+ */
+bool
+Modem::supportsJBIG() const
+{
+    return caps.df & BIT(DF_JBIG);
+}
+
 /*
  * Return whether or not the modem supports the
  * specified page length.  As above for vertical
index 36a918bab2663ca82c59974ebfd1b89ce4d139cd..ce24497efd545379448dee72dfa9f269aa427a29 100644 (file)
@@ -125,6 +125,7 @@ public:
     bool isCapable(const Job& job) const;
     bool supports2D() const;           // modem supports 2D-encoded fax
     bool supportsMMR() const;          // modem supports 2D-MMR encoding
+    bool supportsJBIG() const;         // modem supports JBIG encoding
     bool supportsVRes(float) const;    // modem supports vertical resolution
     bool supportsVR(u_int) const;      // modem supports VR setting
     // modem support fax page width
index b9af66ec139ec60b13cba02bdbd45fd23f998574..5730f32db919095aaa12bd16f3172247af460c4f 100644 (file)
@@ -247,7 +247,11 @@ ModemConfig::setupConfig()
     class1ECMSupport   = true;                 // support for ECM
     class1GreyJPEGSupport = false;             // support for greyscale JPEG
     class1ColorJPEGSupport = false;            // support for full color JPEG
-    class1JBIGBasicSupport = false;            // support for monochrome JBIG
+#ifdef HAVE_JBIG
+    class1JBIGSupport  = true;                 // support for monochrome JBIG
+#else
+    class1JBIGSupport  = false;                // support for monochrome JBIG
+#endif
     class1Resolutions  = VR_ALL;               // resolutions support
     class1PersistentECM        = true;                 // continue to correct
     class1TCFRecvHack  = false;                // historical behavior
@@ -654,8 +658,10 @@ ModemConfig::setConfigItem(const char* tag, const char* value)
        class1GreyJPEGSupport = getBoolean(value);
     else if (streq(tag, "class1colorjpegsupport"))
        class1ColorJPEGSupport = getBoolean(value);
-    else if (streq(tag, "class1jbigbasicsupport"))
-       class1JBIGBasicSupport = getBoolean(value);
+#ifdef HAVE_JBIG
+    else if (streq(tag, "class1jbigsupport"))
+       class1JBIGSupport = getBoolean(value);
+#endif
     else if (streq(tag, "class1persistentecm"))
        class1PersistentECM = getBoolean(value);
     else if (streq(tag, "class1extendedres"))
index 11ce9033165846e5b6374fcd27323025bb00c177..c6e4cd755b5f711f68c9d7ae2e8222b97756d730 100644 (file)
@@ -164,7 +164,7 @@ public:
     u_int      class1ECMFrameSize;     // ECM frame size for transmission
     bool       class1GreyJPEGSupport;  // Greyscale JPEG support
     bool       class1ColorJPEGSupport; // Full-color JPEG support
-    bool       class1JBIGBasicSupport; // Basic (monochrome) JBIG support
+    bool       class1JBIGSupport;      // monochrome JBIG support
     bool       class1ECMSupport;       // support T.30-A ECM
     bool       class1PersistentECM;    // continue to correct
     bool       class1TCFRecvHack;      // deliberately look for V.21 disconnect
index d1393a507f3af09c661df457b8729fe2441fc784..5c4956103e788ac84462a20512da3b1c0fcb7866 100644 (file)
@@ -53,6 +53,7 @@ static const ModelData Canon[] =
 {{"\x80\x00\x80\x48\x00", "Faxphone B640"},
  {"\x80\x00\x80\x49\x10", "Fax B100"},
  {"\x80\x00\x8A\x49\x10", "Laser Class 9000 Series"},
+ {"\x80\x00\x8A\x48\x00", "Laser Class 2060"},
  {NULL}};
   
 
@@ -209,7 +210,6 @@ static const NSFData KnownNSF[] =
     {"\x00\xD0\x00", "USC",       false },
     {"\x00\xE0\x00", "Hiboshi",   false },
     {"\x00\xF0\x00", "Sumitomo Electric", false },
-    {"\x20\x41\x59", "Siemens",   false },
     {"\x59\x59\x01", NULL,        false },
     {"\xB4\x00\xB0", "DCE",       false },
     {"\xB4\x00\xB1", "Hasler",    false },
@@ -297,9 +297,12 @@ static const NSFData KnownNSF[] =
      *
      * Thus, country code x61 (Korea) turns into x86 (Papua New Guinea),
      * code xB5 (USA) turns into xAD (Tunisia), code x26 (China) turns
-     * into x64 (Lebanon), and code x3D (France) turns into xBC (Vietnam).
+     * into x64 (Lebanon), code x04 (Germany) turns into x20 (Canada), 
+     * and code x3D (France) turns into xBC (Vietnam).
      * Therefore, we need to convert these to produce a legible station ID.
      */
+    {"\x20\x41\x59", "Siemens", false },
+    {"\x20\xD1\xC0", "Ferrari Electronic", false },
     {"\x64\x00\x00", "unknown - China 00 00", false },
     {"\x64\x01\x00", "unknown - China 01 00", false },
     {"\x64\x01\x01", "unknown - China 01 01", false },
index 331f38c83f5e79f7c4ce74178f8cd800d9b5140b..54fd74a3b228d6b8edac72a5ae62e49fe9481925 100644 (file)
@@ -288,6 +288,7 @@ Class1ExtendedRes   boolean \-      Class 1/1.0: enable extended resolution support
 Class1HFLOCmd  string  \-      Class 1/1.0: command to set hardware flow control
 Class1FrameOverhead    integer \s-14\s+1       Class 1/1.0: extra bytes in a received \s-1HDLC\s+1 frame
 Class1GreyJPEGSupport  boolean \s-1No\s+1      Class 1/1.0: to enable grey JPEG fax support
+Class1JBIGSupport      boolean \s-1\fIsee below\fP\s+1 Class 1/1.0: to enable monochrome JBIG fax support
 Class1NFLOCmd  string  \-      Class 1/1.0: command to set no flow control
 Class1RecvAbortOK      integer \s-1200\s+1     Class 1/1.0: max wait (ms) for ``\s-1OK\s+1'' after recv abort
 Class1RecvIdentTimer   integer \s-140000\s+1   Class 1/1.0: max wait (ms) for initial ident frame
@@ -2294,9 +2295,16 @@ number should be 4 (the default).
 .B Class1GreyJPEGSupport
 Whether or not to enable support for T.30-E greyscale facsimile
 with JPEG compression.  This is always enabled if
-.B Class1GreyJPEGSupport
+.B Class1ColorJPEGSupport
 is enabled.
 .TP
+.B Class1JBIGSupport
+Whether or not to enable support for T.85 monochrome facsimile
+with JBIG compression.  This defaults to true if, during the build process
+a compatible JBIG library was found; otherwise
+.B Class1JBIGSupport
+defaults to false.
+.TP
 .B Class1HFLOCmd
 The command to setup hardware (\s-1RTS/CTS\s+1)
 flow control between
index 24fbcfcca2a29fe490a62b908d3fa86a6eeb97fe..662a3c477a4ff62d093dcb41b9233d8020b8072c 100644 (file)
@@ -171,6 +171,9 @@ u_int Class2Params::DCSbrTab[16] = {
 
 /*
  * Convert a T.30 DIS to a Class 2 parameter block.
+ *
+ * Note that DIS is a list of *capabilities* and not necessarily maximums.
+ * Thus the values here can be set to bitmaps rather than settings.
  */  
 void
 Class2Params::setFromDIS(FaxParams& dis_caps)
@@ -189,6 +192,16 @@ Class2Params::setFromDIS(FaxParams& dis_caps)
     xinfo |= getByte(6) << 0;
 
     setFromDIS(dis, xinfo);
+
+    if (ec != EC_DISABLE) {
+       if (dis_caps.isBitEnabled(FaxParams::BITNUM_JBIG_BASIC)) df |= BIT(DF_JBIG);
+       if (dis_caps.isBitEnabled(FaxParams::BITNUM_JPEG)) df |= BIT(DF_JPEG_GREY);
+       //if (dis_caps.isBitEnabled(FaxParams::BITNUM_JBIG)) df |= BIT(DF_JBIG_GREY);
+       if (dis_caps.isBitEnabled(FaxParams::BITNUM_FULLCOLOR)) {
+           if (df & BIT(DF_JPEG_GREY)) df |= BIT(DF_JPEG_COLOR);
+           //if (df & BIT(DF_JBIG_GREY)) df |= BIT(DF_JBIG_COLOR);
+       }
+    }
 }
 
 /*
@@ -223,12 +236,16 @@ Class2Params::setFromDIS(u_int dis, u_int xinfo)
        br = DISbrTab[(dis & DIS_SIGRATE) >> 10];
     wd = DISwdTab[(dis & DIS_PAGEWIDTH) >> 6];
     ln = DISlnTab[(dis & DIS_PAGELENGTH) >> 4];
+
+    // DF here is a bitmap
+    df = BIT(DF_1DMH);         // required support for all G3 facsimile
     if ((xinfo & DIS_G4COMP) && (xinfo & DIS_ECMODE))  // MMR requires ECM
-       df = DF_2DMMR;
-    else if (xinfo & DIS_2DUNCOMP)
-       df = DF_2DMRUNCOMP;
-    else
-       df = DISdfTab[(dis & DIS_2DENCODE) >> 8];
+       df |= BIT(DF_2DMMR);
+    if (xinfo & DIS_2DUNCOMP)
+       df |= BIT(DF_2DMRUNCOMP);
+    if (dis & DIS_2DENCODE)
+       df |= BIT(DF_2DMR);
+
     if (xinfo & DIS_ECMODE)
        ec = (dis & DIS_FRAMESIZE) ? EC_ENABLE64 : EC_ENABLE256;
     else
@@ -258,7 +275,8 @@ Class2Params::setFromDCS(FaxParams& dcs_caps)
 
     setFromDCS(dcs, xinfo);
 
-    if (dcs_caps.isBitEnabled(FaxParams::BITNUM_JBIG_BASIC)) df = DF_JBIG_BASIC;
+    if (dcs_caps.isBitEnabled(FaxParams::BITNUM_JBIG_BASIC)) df = DF_JBIG;
+    if (dcs_caps.isBitEnabled(FaxParams::BITNUM_JBIG_L0)) df = DF_JBIG;
     if (dcs_caps.isBitEnabled(FaxParams::BITNUM_JPEG)) df = DF_JPEG_GREY;
     //if (dcs_caps.isBitEnabled(FaxParams::BITNUM_JBIG)) df = DF_JBIG_GREY;
     if (dcs_caps.isBitEnabled(FaxParams::BITNUM_FULLCOLOR)) {
@@ -289,6 +307,12 @@ Class2Params::setFromDCS(u_int dcs, u_int xinfo)
        else if (xinfo & DCS_200X400) vr = VR_R8;
        else vr = DISvrTab[(dcs & DCS_7MMVRES) >> 9];
     }
+
+    // DF here is a setting, not a bitmap, max of DF_2DMMR (JPEG, JBIG set later)
+    if (df & BIT(DF_2DMMR)) df = DF_2DMMR;
+    else if (df & BIT(DF_2DMR)) df = DF_2DMR;
+    else df = DF_1DMH;
+
     if (xinfo & DCS_ECMODE)
        ec = (xinfo & DCSFRAME_64) ? EC_ENABLE64 : EC_ENABLE256;
     else
@@ -400,17 +424,18 @@ Class2Params::update(bool isDIS)
     /*
      * DATA FORMAT
      *
-     * Options: MH (required), MR, and MMR.
+     * Options: MH (required), MR, MMR, JBIG, JPEG.
      *
-     * ECM support is required for MMR.
+     * ECM support is required for MMR, JBIG, and JPEG.
      *
      * There are other data format options in T.30
-     * such as JPEG, JBIG, T.81, and T.43, but they're
-     * not discernable from Class2Params.
+     * such as T.81, and T.43.
      */
     if (CHECKPARAM(df, DF_2DMR, isDIS))  setBit(BITNUM_2DMR, true);
     if (CHECKPARAM(df, DF_2DMMR, isDIS) && (CHECKPARAM(ec, EC_ENABLE64, isDIS) || CHECKPARAM(ec, EC_ENABLE256, isDIS)))
        setBit(BITNUM_2DMMR, true);
+    if (CHECKPARAM(df, DF_JBIG, isDIS) && (CHECKPARAM(ec, EC_ENABLE64, isDIS) || CHECKPARAM(ec, EC_ENABLE256, isDIS)))
+       setBit(BITNUM_JBIG_BASIC, true);
 
     /*
      * MINIMUM SCANLINE TIME
@@ -824,13 +849,26 @@ const char* Class2Params::dataFormatNames[7] = {
     "2-D MR",                  // DF_2DMR
     "2-D Uncompressed Mode",   // DF_2DMRUNCOMP
     "2-D MMR",                 // DF_2DMMR
-    "JBIG Basic",              // DF_JBIG_BASIC
+    "JBIG",                    // DF_JBIG
     "JPEG Greyscale",          // DF_JPEG_GREY
     "JPEG Full-Color"          // DF_JPEG_COLOR
 };
 const char* Class2Params::dataFormatName() const
      { return (dataFormatNames[df]); }
 
+fxStr
+Class2Params::dataFormatsName()
+{
+    fxStr formats = "MH";
+    if (df & BIT(DF_2DMR)) formats.append(", MR");
+    if (df & BIT(DF_2DMMR)) formats.append(", MMR");
+    if (df & BIT(DF_JBIG)) formats.append(", JBIG");
+    // since color requires greyscale, just say one or the other
+    if (df & BIT(DF_JPEG_COLOR)) formats.append(", JPEG Full-Color");
+    else if (df & BIT(DF_JPEG_GREY))  formats.append(", JPEG Greyscale");
+    return (formats);
+}
+
 const char* Class2Params::pageWidthNames[8] = {
     "A4 page width (215 mm)",
     "B4 page width (255 mm)",
index decee94c839a323449b750947a508777580fe054..bd0ef26b5e60363d2bcef497cb1fa103579e770d 100644 (file)
@@ -109,6 +109,7 @@ public:
     const char* bestVerticalResName() const;
     const char* scanlineTimeName() const;
     const char* dataFormatName() const;
+    fxStr dataFormatsName();
     const char* ecmName() const;
 
     u_int encode() const;              // generate encoded params
index 5c5ab22e6e2bea7668eafd0c4355245ba32d3cc0..b227f175fe2a4fe483bb21f49ba8f082625eef63 100644 (file)
@@ -97,7 +97,7 @@ const u_short DF_1DMH = 0;            // 1-D Modified Huffman
 const u_short DF_2DMR  = 1;            // 2-D Modified Read
 const u_short DF_2DMRUNCOMP    = 2;            // 2-D Uncompressed Mode
 const u_short DF_2DMMR = 3;            // 2-D Modified Modified Read
-const u_short DF_JBIG_BASIC    = 4;    // Single-progression sequential coding (Rec. T.85)
+const u_short DF_JBIG  = 4;            // Single-progression sequential coding (Rec. T.85)
 const u_short DF_JPEG_GREY     = 5;    // Greyscale JPEG (T.4 Annex E and T.81)
 const u_short DF_JPEG_COLOR    = 6;    // Full-color JPEG (T.4 Annex E and T.81)
 const u_short DF_ALL   = BIT(DF_2DMMR+1)-1;
index be0f5119004cdf1d65b055b761b03af3108c7567..eac79b32c4f5d20f4005f45282b96aff05b0482d 100644 (file)
@@ -365,6 +365,8 @@ function getDFfromDCS(dcs)
            return dfNames[6];
        return dfNames[5];
     }
+    if (isBitSet(78, dcs) || isBitSet(79, dcs))
+       return dfNames[4];
     if (isBitSet(31, dcs))
        return dfNames[3];
     if (isBitSet(26, dcs))
@@ -415,7 +417,7 @@ function printRule(n, s)
 BEGIN          { FS="\t";
                  rates = "2400:4800:7200:9600:12000:14400:16800:19200:21600:24000:26400:28800:31200:33600";
                  setupMaps(rates, rateMap, brNames);
-                 datas = "1-D MH:2-D MR:2-D Uncompressed Mode:2-D MMR:JBIG Basic:JPEG Greyscale:JPEG Full-color";
+                 datas = "1-D MH:2-D MR:2-D Uncompressed Mode:2-D MMR:JBIG:JPEG Greyscale:JPEG Full-color";
                  setupMaps(datas, dataMap, dfNames);
                  setupDateTimeStuff();
                  if (SINCEDT == "")
index c30429d270b6682c8942e84efa34005fb6770321..f186021c3f1019430efd540e817a34fa696b5eed 100644 (file)
@@ -444,6 +444,8 @@ function getDFfromDCS(dcs)
            return dfNames[6]; 
        return dfNames[5];
     }
+    if (isBitSet(78, dcs) || isBitSet(79, dcs))
+       return dfNames[4];
     if (isBitSet(31, dcs))  
        return dfNames[3];
     if (isBitSet(26, dcs))
@@ -535,7 +537,7 @@ function printRule(n, s)
 BEGIN          { FS="\t";
                  rates = "2400:4800:7200:9600:12000:14400:16800:19200:21600:24000:26400:28800:31200:33600";
                  setupMaps(rates, rateMap, brNames);
-                 datas = "1-D MH:2-D MR:2-D Uncompressed Mode:2-D MMR:JBIG Basic:JPEG Greyscale:JPEG Full-color";
+                 datas = "1-D MH:2-D MR:2-D Uncompressed Mode:2-D MMR:JBIG:JPEG Greyscale:JPEG Full-color";
                  setupMaps(datas, dataMap, dfNames);
                  callFailed["busy signal"] = 1;
                  callFailed["unknown pro"] = 1;