]> git.ipfire.org Git - thirdparty/HylaFAX.git/commitdiff
Class2: Preliminary JBIG support (per T.32 A)
authorAidan Van Dyk <aidan@ifax.com>
Fri, 11 May 2007 15:33:11 +0000 (15:33 +0000)
committerAidan Van Dyk <aidan@ifax.com>
Fri, 11 May 2007 15:33:11 +0000 (15:33 +0000)
From Lee:
| commit 332db6d3e20c5ec212a6d00ff72e39f90d513ece
| Author: Lee Howard <faxguy@howardsilvan.com>
| Date:   Fri Feb 16 06:04:17 2007 +0000
|
|   adds preliminary JBIG support for Class 2 devices (that also support it per
T.32 A)

CHANGES
faxd/Class2.c++
faxd/Class2Send.c++
faxd/CopyQuality.c++
faxd/FaxModem.h

diff --git a/CHANGES b/CHANGES
index 0c4cf961b1a4df7aff4fbdb93653c2c08658ca90..adb7636a3aa54230cb6bf459cc173d98593d5937 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,7 @@
 
 Changelog since HylaFAX 4.3.3
 
+* Add preliminary Class2 JBIG Support (11 May 2007)
 * Change socklen_t configure/detection for HP-UX 11 (11 May 2007)
 * Faxmail overhaul - make handle documents independantly, just like
   sendfax (9 May 2007)
index 42034242a75a440f2a8498ea2e33e6fdd9417d0b..f396068cf820d1c662751c13bfaa729b62208e70 100644 (file)
@@ -376,7 +376,6 @@ Class2Modem::setupDCC(bool enableV34, bool enableV17)
     params.wd = getBestPageWidth();
     params.ln = getBestPageLength();
     params.df = useExtendedDF ? modemParams.df : getBestDataFormat();
-    params.df &= ~BIT(DF_JBIG);                // let's not actually do JBIG yet
     params.ec = getBestECM();
     params.bf = BF_DISABLE;
     params.st = getBestScanlineTime();
@@ -668,9 +667,7 @@ Class2Modem::parseRange(const char* cp, Class2Params& p)
         * are not.
         */
        useExtendedDF = true;
-       // No Class 2 modem is known to actually *work* with JBIG yet.
-       //p.df = BIT(DF_1DMH) | BIT(DF_2DMR) | BIT(DF_2DMMR) | BIT(DF_JBIG);
-       p.df = BIT(DF_1DMH) | BIT(DF_2DMR) | BIT(DF_2DMMR);
+       p.df = BIT(DF_1DMH) | BIT(DF_2DMR) | BIT(DF_2DMMR) | BIT(DF_JBIG);
     } else
        p.df &= DF_ALL;
     p.ec &= EC_ALL;
index a2fffb0ad61705f7f273515dc48c2fa8635d43b1..b38d3e52235205ee81adf2ae50b8697e9af8dda0 100644 (file)
@@ -496,6 +496,7 @@ Class2Modem::sendPageData(TIFF* tif, u_int pageChop)
            }
            dp = convertPhaseCData(dp, totdata, fillorder, params, newparams, rows);
        }
+       params = newparams;             // revert back
 
         /*
          * correct broken Phase C (T.4/T.6) data if necessary
@@ -503,8 +504,6 @@ Class2Modem::sendPageData(TIFF* tif, u_int pageChop)
         if (params.df <= DF_2DMMR)
            lastByte = correctPhaseCData(dp, &totdata, fillorder, (conf.class2RTFCC ? params : newparams), rows);
 
-       params = newparams;             // revert back
-
        beginTimedTransfer();
        rc = putModemDLEData(dp, (u_int) totdata, bitrev, getDataTimeout());
        endTimedTransfer();
index 6966d1cf0ea7f7bf9d0826ad94901be1fb23937e..6e96c5595ed038855b5773a03e7ff8e29aba8441 100644 (file)
@@ -344,6 +344,52 @@ FaxModem::recvPageDLEData(TIFF* tif, bool checkQuality,
         * NB: the image is written as a single strip of data.
         */
        setupStartPage(tif, params);
+       if (params.df == DF_JBIG) {
+           int cc = 0, c;
+           bool fin = false;
+           for (; cc < 20; cc++) {
+               c = getModemChar(30000);
+               if (c == EOF || wasTimeout()) {
+                   fin = true;
+                   break;
+               }
+               if (c == DLE) {
+                   c = getModemChar(30000);
+                   if (c == EOF || c == ETX || wasTimeout()) {
+                       fin = true;
+                       break;
+                   }
+               }
+               buf[cc] = c;
+           }
+           parseJBIGBIH(buf);
+           flushRawData(tif, 0, (const u_char*) buf, cc);
+           if (!fin) {
+               do {
+                   cc = 0;
+                   do {
+                       c = getModemChar(30000);
+                       if (c == EOF || wasTimeout()) {
+                           fin = true;
+                           break;
+                       }
+                       if (c == DLE) {
+                           c = getModemChar(30000);
+                           if (c == EOF || c == ETX || wasTimeout()) {
+                               fin = true;
+                               break;
+                           }
+                       }
+                       parseJBIGStream(c);
+                       buf[cc++] = c;
+                   } while (cc < RCVBUFSIZ && !fin);
+                   flushRawData(tif, 0, (const u_char*) buf, cc);
+               } while (!fin);
+               clearSDNORMCount();
+           }
+           recvEndPage(tif, params);
+           return (true);
+       }
        /*
         * NB: There is a potential memory leak here if the
         * stack buffer gets expanded, such that memory gets
@@ -493,6 +539,127 @@ FaxModem::flushRawData(TIFF* tif, tstrip_t strip, const u_char* buf, u_int cc)
        serverTrace("RECV: %s: write error", TIFFFileName(tif));
 }
 
+void
+FaxModem::clearSDNORMCount()
+{
+    if (parserCount[1]) {
+       copyQualityTrace("Found %d SDNORM Marker Segments in BID", parserCount[1]);
+       parserCount[1] = 0;
+    }
+}
+
+void
+FaxModem::parseJBIGStream(u_char c)
+{
+    /*
+     * parserCount[n]
+     *   n = 0, bytes since last marker
+     *   n = 1, SDNORM marker counter
+     *   n = 2, framelength bypass countdown
+     */
+    parserCount[0]++;
+    if (parserCount[2]) {
+       // just skipping bytes
+       parserCount[2]--;
+       return;
+    }
+    u_long framelength = 0;
+
+    memcpy(parserBuf+1, parserBuf, 15);
+    parserBuf[0] = c;
+
+    if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] == 0x04) {
+       clearSDNORMCount();
+       copyQualityTrace("Found ABORT Marker Segment in BID");
+       parserCount[0] = 0;
+       return;
+    }
+    if (parserCount[0] >= 8 && parserBuf[7] == 0xFF && parserBuf[6] == 0x06) {
+       clearSDNORMCount();
+       copyQualityTrace("Found ATMOVE Marker Segment in BID, Yat %d, tx %d, ty %d",
+           256*256*256*parserBuf[5]+256*256*parserBuf[4]+256*parserBuf[3]+parserBuf[2], parserBuf[1], parserBuf[0]);
+       parserCount[0] = 0;
+       return;
+    }
+    if (parserCount[0] >= 6 && parserBuf[5] == 0xFF && parserBuf[4] == 0x07) {
+       clearSDNORMCount();
+       parserCount[2] = 256*256*256*parserBuf[3]+256*256*parserBuf[2]+256*parserBuf[1]+parserBuf[0];
+       copyQualityTrace("Found COMMENT Marker Segment in BID");
+       parserCount[0] = 0;
+       return;
+    }
+    if (parserCount[0] >= 6 && parserBuf[5] == 0xFF && parserBuf[4] == 0x05) {
+       clearSDNORMCount();
+       framelength = 256*256*256*parserBuf[3];
+       framelength += 256*256*parserBuf[2];
+       framelength += 256*parserBuf[1];
+       framelength += parserBuf[0];
+       copyQualityTrace("Found NEWLEN Marker Segment in BID, Yd = %d", framelength);
+       // T.82: "The new Yd shall never be greater than the original"
+       if (framelength < 65535 && (!recvEOLCount || framelength < recvEOLCount)) recvEOLCount = framelength;
+       parserCount[0] = 0;
+       return;
+    }
+    if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] == 0x01) {
+       clearSDNORMCount();
+       copyQualityTrace("Found RESERVE Marker Segment in BID");
+       parserCount[0] = 0;
+       return;
+    }
+    if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] == 0x02) {
+       parserCount[1]++;       // SDNORM
+       parserCount[0] = 0;
+       return;
+    }
+    if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] == 0x03) {
+       clearSDNORMCount();
+       copyQualityTrace("Found SDRST Marker Segment in BID");
+       parserCount[0] = 0;
+       return;
+    }
+    if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] != 0x00) { // not STUFF
+       clearSDNORMCount();
+       copyQualityTrace("Found Unknown Marker %#x Segment in BID", parserBuf[0]);
+       parserCount[0] == 0;
+       return;
+    }
+}
+
+void
+FaxModem::parseJBIGBIH(u_char* buf)
+{
+    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.
+     *
+     * See T.82 6.6.2
+     * These three integers are coded most significant byte first. In
+     * other words, XD is the sum of 256^3 times the fifth byte in BIH, 256^2
+     * times the sixth byte, 256 times the seventh byte, and the eighth byte.
+     */
+    u_long framelength = 0;
+    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 "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);
+}
+
 /*
  * In ECM mode the ECM module provides the line-counter.
  */
@@ -574,36 +741,7 @@ FaxModem::writeECMData(TIFF* tif, u_char* buf, u_int cc, const Class2Params& par
            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.
-                    *
-                    * See T.82 6.6.2
-                    * These three integers are coded most significant byte first. In
-                    * other words, XD is the sum of 256^3 times the fifth byte in BIH, 256^2
-                    * times the sixth byte, 256 times the seventh byte, and the eighth byte.
-                    */
-                   u_long framelength = 0;
-                   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 "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);
+                   parseJBIGBIH(buf);
                }
                break;
 
@@ -646,96 +784,16 @@ FaxModem::writeECMData(TIFF* tif, u_char* buf, u_int cc, const Class2Params& par
        case DF_JBIG:
            // search for Marker Segments in JBIG Bi-Level Image Data
            {
-               u_long framelength = 0;
-               u_int sdnormcount = 0, i = 0;
+               parserCount[0] = 0;
+               parserCount[1] = 0;
+               parserCount[2] = 0;
+               memset(parserBuf, 0, 16);
+               u_int 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];
-                       if (clength >= cc - i - 5) clength = 0;         // bogus comment
-                       fxStr comment = "";
-                       for (u_long cpos = 0; i+6+cpos < cc && cpos < clength && cpos < 256; cpos++) {
-                           if (!isprint(buf[i+6+cpos])) break;         // only printables
-                           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];
-                       copyQualityTrace("Found NEWLEN Marker Segment in BID, Yd = %d", framelength);
-                       // T.82: "The new Yd shall never be greater than the original"
-                       if (framelength < 65535 && (!recvEOLCount || framelength < recvEOLCount)) 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);
+                   parseJBIGStream(buf[i]);
                }
+               clearSDNORMCount();
            }
            break;
 
index 39fa894cef1df48f736c56c01c865aed22bc11c1..a397b37878d3eddc41d599d4d1d2127cb6d279c4 100644 (file)
@@ -86,6 +86,8 @@ private:
     int                decoderFd[2];   // file descriptors for the decoder pipe
     int                counterFd[2];   // file descriptors for the counter pipe
     pid_t      decoderPid;     // process id for the decoding process
+    u_char     parserBuf[16];  // buffer used for parsing JBIG and JPEG
+    u_long     parserCount[3]; // counters used in parsing JBIG and JPEG
 
     void       flushEncodedData(TIFF*, tstrip_t, const u_char*, u_int);
     void       flushRawData(TIFF*, tstrip_t, const u_char*, u_int);
@@ -122,6 +124,9 @@ protected:
     void       copyQualityTrace(const char* fmt, ...);
     void       traceModemParams();
     void       traceFCF(const char* dir, u_int fcf);
+    void       parseJBIGStream(u_char c);
+    void       parseJBIGBIH(u_char* buf);
+    void       clearSDNORMCount();
 // server-related stuff
     bool       getHDLCTracing();
     bool       getECMTracing();