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

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: cqtest.c++,v 1.3 2006/06/22 04:11:37 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1994-1996 Sam Leffler
  4.  * Copyright (c) 1994-1996 Silicon Graphics, Inc.
  5.  * HylaFAX is a trademark of Silicon Graphics
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26. /*
  27.  * Program for testing copy quality support.
  28.  *
  29.  * cqtest [-m maxbad] [-o output.tif] [-p %good] input.tif
  30.  */
  31. #include "config.h"
  32. #include "Sys.h"
  33. #include "StackBuffer.h"
  34. #include "G3Decoder.h"
  35. #include "Class2Params.h"
  36. #include "Str.h"
  37. #include "FaxTrace.h"
  38. #include "tiffio.h"
  39. struct CQDecoder : public G3Decoder {
  40.     u_int cblc; // current count of consecutive bad lines
  41.     bool lastRowBad; // last decoded row was bad
  42.     u_long recvEOLCount; // EOL count for received page
  43.     u_long recvBadLineCount;
  44.     u_long recvConsecutiveBadLineCount;
  45.     tstrip_t recvStrip; // current strip number during receive
  46.     u_char* recvRow; // current receive row raster
  47.     fxStackBuffer* recvBuf;
  48.     u_char* cp;
  49.     u_int cc;
  50.     u_int percentGoodLines;
  51.     u_int maxConsecutiveBadLines;
  52.     uint16 recvFillOrder;
  53.     uint32 group3opts;
  54.     void recvSetupTIFF(TIFF* tif, long group3opts, int fillOrder,
  55.     const Class2Params& params);
  56.     void flushEncodedData(TIFF*, tstrip_t, u_char*, u_int);
  57.     void flushRawData(TIFF*, tstrip_t, u_char*, u_int);
  58.     void invalidCode(const char* type, int x);
  59.     void badPixelCount(const char* type, int got, int expected);
  60.     void badDecodingState(const char* type, int x);
  61.     void recvTrace(const char* fmt, ...);
  62.     void serverTrace(const char* fmt ...);
  63.     void copyQualityTrace(const char* fmt, ...);
  64.     bool recvPageDLEData(TIFF* tif, bool checkQuality,
  65.     const Class2Params& params, fxStr& emsg);
  66.     void abortPageRecv();
  67.     int nextByte();
  68.     bool checkQuality();
  69.     bool isQualityOK(const Class2Params&);
  70.     CQDecoder();
  71.     ~CQDecoder();
  72. };
  73. CQDecoder::CQDecoder()
  74. {
  75.     percentGoodLines = 95;
  76.     maxConsecutiveBadLines = 5;
  77.     group3opts = 0;
  78. }
  79. CQDecoder::~CQDecoder() {}
  80. void CQDecoder::abortPageRecv() {}
  81. void
  82. vtraceStatus(int, const char* fmt, va_list ap)
  83. {
  84.     vfprintf(stdout, fmt, ap);
  85.     putchar('n');
  86. }
  87. #define RCVBUFSIZ (32*1024) // XXX
  88. /*
  89.  * Prepare for the reception of page data by setting the
  90.  * TIFF tags to reflect the data characteristics.
  91.  */
  92. void
  93. CQDecoder::recvSetupTIFF(TIFF* tif, long, int fillOrder, const Class2Params& params)
  94. {
  95.     TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
  96.     TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32) params.pageWidth());
  97.     TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1);
  98.     TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
  99.     TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
  100.     TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
  101.     TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, (uint32) -1);
  102.     TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  103.     TIFFSetField(tif, TIFFTAG_FILLORDER, (uint16) fillOrder);
  104.     TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float) params.horizontalRes());
  105.     TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float) params.verticalRes());
  106.     TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
  107.     TIFFSetField(tif, TIFFTAG_SOFTWARE, HYLAFAX_VERSION);
  108. #ifdef notdef
  109.     TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, (const char*) tsi);
  110. #endif
  111.     char dateTime[24];
  112.     time_t now = Sys::now();
  113.     strftime(dateTime, sizeof (dateTime), "%Y:%m:%d %H:%M:%S",
  114. localtime(&now));
  115.     TIFFSetField(tif, TIFFTAG_DATETIME,     dateTime);
  116. #ifdef notdef
  117.     TIFFSetField(tif, TIFFTAG_MAKE,     (const char*) getManufacturer());
  118.     TIFFSetField(tif, TIFFTAG_MODEL,     (const char*) getModel());
  119.     TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, (const char*) server.hostname);
  120. #endif
  121. }
  122. /*
  123.  * Receive Phase C data with or without copy
  124.  * quality checking and erroneous row fixup.
  125.  */
  126. bool
  127. CQDecoder::recvPageDLEData(TIFF* tif, bool checkQuality,
  128.     const Class2Params& params, fxStr& emsg)
  129. {
  130.     setupDecoder(recvFillOrder, params.is2D(), (params.df == DF_2DMMR));
  131.     u_int rowpixels = params.pageWidth(); // NB: assume rowpixels <= 4864
  132.     tiff_runlen_t runs[2*4864]; // run arrays for cur+ref rows
  133.     setRuns(runs, runs+4864, rowpixels);
  134.     recvEOLCount = 0; // count of EOL codes
  135.     recvBadLineCount = 0; // rows with a decoding error
  136.     recvConsecutiveBadLineCount = 0; // max consecutive bad rows
  137.     /*
  138.      * Data destined for the TIFF file is buffered in buf.
  139.      * recvRow points to the next place in buf where data
  140.      * (decoded or undecoded) is to be placed.  Beware
  141.      * that this is not an automatic variable because our
  142.      * use of setjmp/longjmp to deal with EOF and RTC detection
  143.      * does not guarantee correct values being restored to
  144.      * automatic variables when the stack is unwound.
  145.      */
  146.     u_char buf[RCVBUFSIZ]; // output buffer
  147.     recvRow = buf; // current decoded row
  148.     recvStrip = 0; // TIFF strip number
  149.     if (EOFraised()) {
  150. abortPageRecv();
  151. emsg = "Missing EOL after 5 seconds";
  152. recvTrace("%s", (const char*) emsg);
  153. return (false);
  154.     }
  155.     if (checkQuality) {
  156. /*
  157.  * Receive a page of data w/ copy quality checking.
  158.  * Note that since we decode and re-encode we can
  159.  * trivially do transcoding by just changing the
  160.  * TIFF tag values setup for each received page.  This
  161.  * may however be too much work for some CPUs.
  162.  */
  163. tsize_t rowSize = TIFFScanlineSize(tif);// scanline buffer size
  164. /*
  165.  * Doing copy quality checking; since we decode
  166.  * and re-encode we can choose any compression
  167.  * we want for the data that's eventually written
  168.  * to the file.
  169.  */
  170. TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
  171. /*
  172.  * When copy quality checking is done we generate multi-strip
  173.  * images where the strip size is dependent on the size of the
  174.  * receive buffer used to buffer decoded image data.  There is
  175.  * a balance here between reducing i/o, minimizing encoding
  176.  * overhead, and minimizing delays that occur in the middle of
  177.  * page data receive operations.  If the receive buffer is made
  178.  * too large then a modem with little buffering may have a
  179.  * data underrun occur.  On the other hand encoding each row of
  180.  * data adds to the overhead both in setup time for the encoder
  181.  * and in various accounting work done by the TIFF library when
  182.  * images are grown row-by-row.  All this is also dependent on
  183.  * the speed of the host CPU and i/o performance.
  184.  */
  185. TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, RCVBUFSIZ / rowSize);
  186. u_char* curGood = buf; // last good row
  187. memset(curGood, 0, (size_t) rowSize); // initialize to all white
  188. recvBuf = NULL; // don't need raw data
  189. lastRowBad = false; // no previous row
  190. cblc = 0; // current bad line run
  191. if (!RTCraised()) {
  192.     for (;;) {
  193. /*
  194.  * Decode the next row of data into the raster.  If
  195.  * an error is encountered, replicate the last good
  196.  * row and continue.  We track statistics on bad
  197.  * lines and consecutive bad lines; these are used
  198.  * later for deciding whether or not the page quality
  199.  * is acceptable.
  200.  */
  201. bool decodeOK = decodeRow(recvRow, rowpixels);
  202. if (seenRTC()) // seen RTC, flush everything
  203.     continue;
  204. if (decodeOK) {
  205.     curGood = recvRow; // reset last good
  206.     if (lastRowBad) { // reset run statistics
  207. lastRowBad = false;
  208. if (cblc > recvConsecutiveBadLineCount)
  209.     recvConsecutiveBadLineCount = cblc;
  210. cblc = 0;
  211.     }
  212. } else {
  213.     memcpy(recvRow, curGood, (size_t) rowSize);
  214. // replicate last good
  215.     recvBadLineCount++;
  216.     cblc++;
  217.     lastRowBad = true;
  218. }
  219. /*
  220.  * Advance forward a scanline and if necessary
  221.  * flush the buffer.  Note that we leave the
  222.  * pointer to the last good row of data at the
  223.  * last decoded line near the end of the buffer.
  224.  * We assume the buffer is large enough that we
  225.  * don't have to worry about overlapping with the
  226.  * next decoded scanline.
  227.  */
  228. recvRow += rowSize;
  229. recvEOLCount++;
  230. if (recvRow + rowSize >= &buf[RCVBUFSIZ]) {
  231.     flushEncodedData(tif, recvStrip++, buf, recvRow - buf);
  232.     recvRow = buf;
  233. }
  234.     }
  235. }
  236. if (seenRTC()) { // RTC found in data stream
  237.     /*
  238.      * Adjust everything to reflect the location
  239.      * at which RTC was found in the data stream.
  240.      */
  241.     copyQualityTrace("Adjusting for RTC found at row %u", getRTCRow());
  242. // # EOL's in recognized RTC
  243.     u_int n = (u_int) (recvEOLCount - getRTCRow());
  244.     if ((recvRow -= n*rowSize) < buf)
  245. recvRow = buf;
  246.     recvBadLineCount -= n; // deduct RTC
  247.     recvEOLCount = getRTCRow(); // adjust row count
  248. } else if (lastRowBad) {
  249.     /*
  250.      * Adjust the received line count to deduce the last
  251.      * consecutive bad line run since the RTC is often not
  252.      * readable and/or is followed by line noise or random
  253.      * junk from the sender.
  254.      */
  255.     copyQualityTrace("adjusting for trailing noise (%lu run)", cblc);
  256.     recvEOLCount -= cblc;
  257.     recvBadLineCount -= cblc;
  258.     if ((recvRow -= cblc*rowSize) < buf)
  259. recvRow = buf;
  260. }
  261. recvTrace("%lu total lines, %lu bad lines, %lu consecutive bad lines"
  262.     , recvEOLCount
  263.     , recvBadLineCount
  264.     , recvConsecutiveBadLineCount
  265. );
  266. if (recvRow > &buf[0])
  267.     flushEncodedData(tif, recvStrip, buf, recvRow - buf);
  268.     } else {
  269. /*
  270.  * Receive a page of data w/o doing copy quality analysis.
  271.  *
  272.  * NB: the image is written as a single strip of data.
  273.  */
  274. /*
  275.  * Not doing copy quality checking so compression and
  276.  * Group3Options must reflect the negotiated session
  277.  * parameters for the forthcoming page data.
  278.  */
  279. switch (params.df) {
  280. case DF_2DMMR:
  281.     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
  282.     break;
  283. case DF_2DMRUNCOMP:
  284.     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
  285.     TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS,
  286. group3opts | GROUP3OPT_2DENCODING|GROUP3OPT_UNCOMPRESSED);
  287.     break;
  288. case DF_2DMR:
  289.     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
  290.     TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS,
  291. group3opts | GROUP3OPT_2DENCODING);
  292.     break;
  293. case DF_1DMH:
  294.     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
  295.     TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS,
  296. group3opts &~ GROUP3OPT_2DENCODING);
  297.     break;
  298. }
  299. /*
  300.  * NB: There is a potential memory leak here if the
  301.  * stack buffer gets expanded, such that memory gets
  302.  * malloc'd, and EOF is raised.  In that case the destructor
  303.  * may not be invoked (in fact it almost certainly won't).
  304.  * This is an unlikely scenario so for now we'll leave
  305.  * the code the way it is.
  306.  */
  307. fxStackBuffer raw; // XXX may leak
  308. recvBuf = &raw;
  309. if (!RTCraised()) {
  310.     for (;;) {
  311. raw.reset();
  312. (void) decodeRow(NULL, rowpixels);
  313. if (seenRTC())
  314.     continue;
  315. u_int n = raw.getLength();
  316. if (recvRow + n >= &buf[RCVBUFSIZ]) {
  317.     flushRawData(tif, 0, buf, recvRow - buf);
  318.     recvRow = buf;
  319. }
  320. memcpy(recvRow, (const char*) raw, n);
  321. recvRow += n;
  322. recvEOLCount++;
  323.     }
  324. }
  325. if (recvRow > &buf[0])
  326.     flushRawData(tif, 0, buf, recvRow - buf);
  327. if (seenRTC()) { // RTC found in data stream
  328.     /*
  329.      * Adjust the received line count to reflect the
  330.      * location at which RTC was found in the data stream.
  331.      */
  332.     copyQualityTrace("Adjusting for RTC found at row %u", getRTCRow());
  333.     recvEOLCount = getRTCRow();
  334. }
  335.     }
  336.     return (true);
  337. }
  338. void
  339. CQDecoder::flushEncodedData(TIFF* tif, tstrip_t strip, u_char* buf, u_int cc)
  340. {
  341.     TIFFSetField(tif, TIFFTAG_IMAGELENGTH, recvEOLCount);
  342.     if (TIFFWriteEncodedStrip(tif, strip, buf, cc) == -1)
  343. serverTrace("RECV: %s: write error", TIFFFileName(tif));
  344. }
  345. /*
  346.  * Write a strip of raw data to the receive file.
  347.  */
  348. void
  349. CQDecoder::flushRawData(TIFF* tif, tstrip_t strip, u_char* buf, u_int cc)
  350. {
  351.     recvTrace("%u bytes of data, %lu total lines", cc, recvEOLCount);
  352.     if (TIFFWriteRawStrip(tif, strip, buf, cc) == -1)
  353. serverTrace("RECV: %s: write error", TIFFFileName(tif));
  354. }
  355. /*
  356.  * Check if the configuration parameters indicate if
  357.  * copy quality checking should be done on recvd pages.
  358.  */
  359. bool
  360. CQDecoder::checkQuality()
  361. {
  362.     return (percentGoodLines != 0 && maxConsecutiveBadLines != 0);
  363. }
  364. /*
  365.  * Check the statistics accumulated during a page recived
  366.  * against the configuration parameters and return an
  367.  * indication of whether or not the page quality is acceptable.
  368.  */
  369. bool
  370. CQDecoder::isQualityOK(const Class2Params& params)
  371. {
  372.     if (percentGoodLines != 0 && recvEOLCount != 0) {
  373. u_long percent = 100 * (recvEOLCount - recvBadLineCount) / recvEOLCount;
  374. if (percent < percentGoodLines) {
  375.     serverTrace("RECV: REJECT page quality, %u%% good lines (%u%% required)",
  376. percent, percentGoodLines);
  377.     return (false);
  378. }
  379.     }
  380.     u_int cblc = maxConsecutiveBadLines;
  381.     if (cblc != 0) {
  382. if (params.vr == VR_FINE)
  383.     cblc *= 2;
  384. if (recvConsecutiveBadLineCount > cblc) {
  385.     serverTrace("RECV: REJECT page quality, %u-line run (max %u)",
  386. recvConsecutiveBadLineCount, cblc);
  387.     return (false);
  388. }
  389.     }
  390.     return (true);
  391. }
  392. int
  393. CQDecoder::nextByte()
  394. {
  395.     if (cc == 0)
  396. raiseRTC();
  397.     cc--;
  398.     int b = getBitmap()[*cp++];
  399.     if (recvBuf)
  400. recvBuf->put(b);
  401.     return (b);
  402. }
  403. /*
  404.  * Trace a protocol-receive related activity.
  405.  */
  406. void
  407. CQDecoder::recvTrace(const char* fmt ...)
  408. {
  409.     va_list ap;
  410.     va_start(ap, fmt);
  411.     static const fxStr recv("RECV: ");
  412.     vtraceStatus(FAXTRACE_PROTOCOL, recv | fmt, ap);
  413.     va_end(ap);
  414. }
  415. /*
  416.  * Trace a protocol-receive related activity.
  417.  */
  418. void
  419. CQDecoder::serverTrace(const char* fmt ...)
  420. {
  421.     va_list ap;
  422.     va_start(ap, fmt);
  423.     vtraceStatus(FAXTRACE_SERVER, fmt, ap);
  424.     va_end(ap);
  425. }
  426. /*
  427.  * Note an invalid G3 code word.
  428.  */
  429. void
  430. CQDecoder::invalidCode(const char* type, int x)
  431. {
  432.     if (!seenRTC())
  433. copyQualityTrace("Invalid %s code word, row %u, x %d",
  434.     type, getReferenceRow(), x);
  435. }
  436. /*
  437.  * Note a row decode that gives the wrong pixel count.
  438.  */
  439. void
  440. CQDecoder::badPixelCount(const char* type, int got, int expected)
  441. {
  442.     if (!seenRTC())
  443. copyQualityTrace("Bad %s pixel count, row %u, got %d, expected %d",
  444.     type, getReferenceRow(), got, expected);
  445. }
  446. void
  447. CQDecoder::badDecodingState(const char* type, int x)
  448. {
  449.     copyQualityTrace("Panic, bad %s decoding state, row %u, x %d",
  450. type, getReferenceRow(), x);
  451. }
  452. /*
  453.  * Trace a copy quality-reated activity.
  454.  */
  455. void
  456. CQDecoder::copyQualityTrace(const char* fmt ...)
  457. {
  458.     va_list ap;
  459.     va_start(ap, fmt);
  460.     static const fxStr cq("RECV/CQ: ");
  461.     vtraceStatus(FAXTRACE_COPYQUALITY, cq | fmt, ap);
  462.     va_end(ap);
  463. }
  464. const char* appName;
  465. void
  466. usage()
  467. {
  468.     fprintf(stderr, "usage: %s [-m maxbad] [-p %%good] [-o output.tif] input.tifn", appName);
  469.     _exit(-1);
  470. }
  471. int
  472. main(int argc, char* argv[])
  473. {
  474.     const char* outFile = "cq.tif";
  475.     extern int optind;
  476.     extern char* optarg;
  477.     int c;
  478.     CQDecoder cq;
  479.     appName = argv[0];
  480.     while ((c = Sys::getopt(argc, argv, "m:o:p:")) != -1)
  481. switch (c) {
  482. case 'm':
  483.     cq.maxConsecutiveBadLines = (u_int) strtoul(optarg, NULL, 0);
  484.     break;
  485. case 'o':
  486.     outFile = optarg;
  487.     break;
  488. case 'p':
  489.     cq.percentGoodLines = (u_int) strtoul(optarg, NULL, 0);
  490.     break;
  491. case '?':
  492.     usage();
  493.     /*NOTREACHED*/
  494. }
  495.     if (argc - optind != 1)
  496. usage();
  497.     TIFF* tif = TIFFOpen(argv[optind], "r");
  498.     if (!tif) {
  499. fprintf(stderr, "%s: Cannot open, or not a TIFF filen", argv[optind]);
  500. return (-1);
  501.     }
  502.     TIFF* tifout = TIFFOpen(outFile, "w");
  503.     if (!tifout) {
  504. fprintf(stderr, "%s: Cannot create TIFF filen", outFile);
  505. return (-1);
  506.     }
  507.     Class2Params params;
  508.     do {
  509. uint32 w;
  510. TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
  511. params.setPageWidthInPixels((u_int) w);
  512. uint32 l;
  513. TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &l);
  514. params.ln = LN_A4;
  515. if (l < 1500)
  516.     params.vr = VR_NORMAL;
  517. else
  518.     params.vr = VR_FINE;
  519. uint32 opts = 0;
  520. TIFFGetField(tif, TIFFTAG_GROUP3OPTIONS, &opts);
  521. params.df = (opts & GROUP3OPT_2DENCODING) ? DF_2DMR : DF_1DMH;
  522. TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &cq.recvFillOrder);
  523. printf("%u x %u, %s, %s, %sn"
  524.     , params.pageWidth()
  525.     , params.pageLength()
  526.     , params.verticalResName()
  527.     , params.dataFormatName()
  528.     , cq.recvFillOrder == FILLORDER_LSB2MSB ? "lsb-to-msb" : "msb-to-lsb"
  529. );
  530. cq.recvSetupTIFF(tifout, 0, cq.recvFillOrder, params);
  531. uint32* stripbytecount;
  532. (void) TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &stripbytecount);
  533. for (u_int strip = 0; strip < TIFFNumberOfStrips(tif); strip++) {
  534.     u_int totbytes = (u_int) stripbytecount[strip];
  535.     if (totbytes > 0) {
  536. u_char* data = new u_char[totbytes];
  537. if (TIFFReadRawStrip(tif, strip, data, totbytes) >= 0) {
  538.     fxStr emsg;
  539.     cq.cp = data;
  540.     cq.cc = totbytes;
  541.     (void) cq.recvPageDLEData(tifout,
  542. cq.checkQuality(), params, emsg);
  543. } else
  544.     printf("Read error on strip %un", strip);
  545. delete data;
  546.     }
  547. }
  548. TIFFSetField(tifout, TIFFTAG_IMAGELENGTH, cq.recvEOLCount);
  549.     } while (TIFFReadDirectory(tif) && TIFFWriteDirectory(tifout));
  550.     TIFFClose(tifout);
  551.     TIFFClose(tif);
  552.     return (0);
  553. }