diff options
Diffstat (limited to 'converter/pbm/g3topbm.c')
-rw-r--r-- | converter/pbm/g3topbm.c | 196 |
1 files changed, 138 insertions, 58 deletions
diff --git a/converter/pbm/g3topbm.c b/converter/pbm/g3topbm.c index 5d98fcb2..80b7b37d 100644 --- a/converter/pbm/g3topbm.c +++ b/converter/pbm/g3topbm.c @@ -21,6 +21,8 @@ #define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */ #define _BSD_SOURCE /* Make nstring.h define strcaseeq() */ +#include <assert.h> + #include "pm_c_util.h" #include "pbm.h" #include "shhopt.h" @@ -71,10 +73,6 @@ The receiver may be less patient. It may opt to disconnect if one row is not received within 5 seconds. */ -static G3TableEntry * whash[HASHSIZE]; -static G3TableEntry * bhash[HASHSIZE]; - - struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. @@ -85,6 +83,7 @@ struct CmdlineInfo { unsigned int stretch; unsigned int stop_error; unsigned int expectedLineSize; + unsigned int correctlong; }; @@ -97,7 +96,6 @@ parseCommandLine(int argc, const char ** const argv, was passed to us as the argv array. -----------------------------------------------------------------------------*/ optEntry * option_def; /* malloc'ed */ - /* Instructions to OptParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; @@ -120,12 +118,14 @@ parseCommandLine(int argc, const char ** const argv, &widthSpec, 0); OPTENT3(0, "paper_size", OPT_STRING, &paperSize, &paper_sizeSpec, 0); + OPTENT3(0, "correctlong", OPT_FLAG, NULL, &cmdlineP->correctlong, + 0); opt.opt_table = option_def; opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ opt.allowNegNum = FALSE; /* We may have parms that are negative numbers */ - pm_optParseOptions3(&argc, (char**)argv, opt, sizeof(opt), 0); + pm_optParseOptions4(&argc, argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (widthSpec && paper_sizeSpec) @@ -163,6 +163,11 @@ parseCommandLine(int argc, const char ** const argv, +typedef struct { + const G3TableEntry * whash[HASHSIZE]; + const G3TableEntry * bhash[HASHSIZE]; +} BwHash; + struct BitStream { FILE * fileP; @@ -243,6 +248,7 @@ readBitAndDetectEol(struct BitStream * const bitStreamP, } + static void initBitStream(struct BitStream * const bitStreamP, FILE * const fileP, @@ -275,16 +281,16 @@ skipToNextLine(struct BitStream * const bitStreamP) { static void -addtohash(G3TableEntry * hash[], - G3TableEntry table[], - unsigned int const n, - int const a, - int const b) { +addtohash(const G3TableEntry ** const hash, + const G3TableEntry * const table, + unsigned int const n, + int const a, + int const b) { unsigned int i; for (i = 0; i < n; ++i) { - G3TableEntry * const teP = &table[i*2]; + const G3TableEntry * const teP = &table[i*2]; unsigned int const pos = ((teP->length + a) * (teP->code + b)) % HASHSIZE; if (hash[pos]) @@ -295,38 +301,51 @@ addtohash(G3TableEntry * hash[], -static G3TableEntry * -hashfind(G3TableEntry * hash[], - int const length, - int const code, - int const a, - int const b) { +static const G3TableEntry * +hashfind(const G3TableEntry * const * const hash, + unsigned int const length, + int const code, + int const a, + int const b) { - unsigned int pos; - G3TableEntry * te; + unsigned int const pos = ((length + a) * (code + b)) % HASHSIZE; + const G3TableEntry * const teP = hash[pos]; - pos = ((length + a) * (code + b)) % HASHSIZE; - te = hash[pos]; - return ((te && te->length == length && te->code == code) ? te : NULL); + return ((teP && teP->length == length && teP->code == code) ? teP : NULL); } -static void -buildHashes(G3TableEntry * (*whashP)[HASHSIZE], - G3TableEntry * (*bhashP)[HASHSIZE]) { +static BwHash * +newBwHash() { - unsigned int i; + BwHash * bwHashP; - for (i = 0; i < HASHSIZE; ++i) - (*whashP)[i] = (*bhashP)[i] = NULL; + MALLOCVAR(bwHashP); - addtohash(*whashP, &g3ttable_table[0], 64, WHASHA, WHASHB); - addtohash(*whashP, &g3ttable_mtable[2], 40, WHASHA, WHASHB); + if (!bwHashP) + pm_error("Unable to allocate memory for hashes"); + else { + unsigned int i; + /* Initialize */ + for (i = 0; i < HASHSIZE; ++i) + bwHashP->whash[i] = bwHashP->bhash[i] = NULL; - addtohash(*bhashP, &g3ttable_table[1], 64, BHASHA, BHASHB); - addtohash(*bhashP, &g3ttable_mtable[3], 40, BHASHA, BHASHB); + addtohash(bwHashP->whash, &g3ttable_table [0], 64, WHASHA, WHASHB); + addtohash(bwHashP->whash, &g3ttable_mtable[2], 40, WHASHA, WHASHB); + addtohash(bwHashP->bhash, &g3ttable_table [1], 64, BHASHA, BHASHB); + addtohash(bwHashP->bhash, &g3ttable_mtable[3], 40, BHASHA, BHASHB); + } + return bwHashP; +} + + + +static void +freeBwHash(BwHash * const bwHashP) { + + free(bwHashP); } @@ -342,10 +361,11 @@ makeRowWhite(unsigned char * const packedBitrow, -static G3TableEntry * -g3code(unsigned int const curcode, - unsigned int const curlen, - bit const color) { +static const G3TableEntry * +g3code(unsigned int const curcode, + unsigned int const curlen, + bit const color, + const BwHash * const bwHashP) { /*---------------------------------------------------------------------------- Return the position in the code tables mtable and ttable of the G3 code which is the 'curlen' bits long with value 'curcode'. @@ -353,20 +373,20 @@ g3code(unsigned int const curcode, Note that it is the _position_ in the table that determines the meaning of the code. The contents of the table entry do not. -----------------------------------------------------------------------------*/ - G3TableEntry * retval; + const G3TableEntry * retval; switch (color) { case PBM_WHITE: if (curlen < 4) retval = NULL; else - retval = hashfind(whash, curlen, curcode, WHASHA, WHASHB); + retval = hashfind(bwHashP->whash, curlen, curcode, WHASHA, WHASHB); break; case PBM_BLACK: if (curlen < 2) retval = NULL; else - retval = hashfind(bhash, curlen, curcode, BHASHA, BHASHB); + retval = hashfind(bwHashP->bhash, curlen, curcode, BHASHA, BHASHB); break; default: pm_error("INTERNAL ERROR: color is not black or white"); @@ -481,6 +501,7 @@ formatBadCodeException(const char ** const exceptionP, static void readFaxRow(struct BitStream * const bitStreamP, unsigned char * const packedBitrow, + BwHash * const bwHashP, unsigned int * const lineLengthP, const char ** const exceptionP, const char ** const errorP) { @@ -552,17 +573,16 @@ readFaxRow(struct BitStream * const bitStreamP, curcode = (curcode << 1) | bit; ++curlen; - if (curlen > 11 && curcode == 0x00) { - if (++fillbits > MAXFILLBITS) - pm_error("Encountered %u consecutive fill bits. " - "Aborting", fillbits); - } - else if (curlen - fillbits > 13) { + if (curlen > 11 && curcode == 0x00) { + if (++fillbits > MAXFILLBITS) + pm_error("Encountered %u consecutive fill bits. " + "Aborting", fillbits); + } else if (curlen - fillbits > 13) { formatBadCodeException(exceptionP, col, curlen, curcode); done = TRUE; } else if (curcode != 0) { const G3TableEntry * const teP = - g3code(curcode, curlen, currentColor); + g3code(curcode, curlen, currentColor, bwHashP); /* Address of structure that describes the current G3 code. Null means 'curcode' isn't a G3 code yet (probably just the beginning of one) @@ -645,16 +665,21 @@ typedef struct { */ bool warned; /* We have warned the user that he has a line length problem */ + bool tolerateErrors; /* Try to continue when we detect a line size error, as opposed to aborting the program. */ -} lineSizeAnalyzer; + unsigned int lineSizeCt[MAXCOLS+1]; + /* Histogram of line sizes in image -- lineSizeCt[i] is the number + of lines we've seen of size i. + */ +} LineSizeAnalyzer; static void -initializeLineSizeAnalyzer(lineSizeAnalyzer * const analyzerP, +initializeLineSizeAnalyzer(LineSizeAnalyzer * const analyzerP, unsigned int const expectedLineSize, bool const tolerateErrors) { @@ -663,12 +688,19 @@ initializeLineSizeAnalyzer(lineSizeAnalyzer * const analyzerP, analyzerP->maxLineSize = 0; analyzerP->warned = FALSE; + + { + unsigned int i; + + for (i = 0; i < MAXCOLS; ++i) + analyzerP->lineSizeCt[i] = 0; + } } static void -analyzeLineSize(lineSizeAnalyzer * const analyzerP, +analyzeLineSize(LineSizeAnalyzer * const analyzerP, unsigned int const thisLineSize) { const char * error; @@ -701,6 +733,45 @@ analyzeLineSize(lineSizeAnalyzer * const analyzerP, pm_strfree(error); } analyzerP->maxLineSize = MAX(thisLineSize, analyzerP->maxLineSize); + + assert(thisLineSize <= MAXCOLS); + ++analyzerP->lineSizeCt[thisLineSize]; +} + + + +static unsigned int +imageLineSize(const LineSizeAnalyzer * const lineSizeAnalyzerP, + bool const mustCorrectLongLine) { +/*---------------------------------------------------------------------------- + The width of the fax in pixels, based on the analysis of the image + *lineSizeAnalyzerP. + + Zero if the fax contains no lines. +-----------------------------------------------------------------------------*/ + unsigned int retval; + + if (mustCorrectLongLine) { + /* Assume that long lines are actually concatenation of two + lines because the EOL code that was supposed to separate them + got lost. + + Assume the most common line length in the image is the correct line + length for the image and that other line lengths are due to + corruption + */ + unsigned int modeSoFar; + unsigned int i; + + for (i = 0, modeSoFar = 0; i <= MAXCOLS; ++i) { + if (lineSizeAnalyzerP->lineSizeCt[i] > modeSoFar) + modeSoFar = i; + } + retval = modeSoFar; + } else { + retval = lineSizeAnalyzerP->maxLineSize; + } + return retval; } @@ -718,12 +789,14 @@ static void readFax(struct BitStream * const bitStreamP, bool const stretch, unsigned int const expectedLineSize, - bool const tolerateErrors, + bool const mustTolerateErrors, + bool const mustCorrectLongLine, + BwHash * const bwHashP, unsigned char *** const packedBitsP, unsigned int * const colsP, unsigned int * const rowsP) { - lineSizeAnalyzer lineSizeAnalyzer; + LineSizeAnalyzer lineSizeAnalyzer; unsigned char ** packedBits; const char * error; bool eof; @@ -732,7 +805,7 @@ readFax(struct BitStream * const bitStreamP, MALLOCARRAY_NOFAIL(packedBits, MAXROWS); initializeLineSizeAnalyzer(&lineSizeAnalyzer, - expectedLineSize, tolerateErrors); + expectedLineSize, mustTolerateErrors); eof = FALSE; error = NULL; @@ -748,10 +821,10 @@ readFax(struct BitStream * const bitStreamP, const char * exception; packedBits[row] = pbm_allocrow_packed(MAXCOLS); - readFaxRow(bitStreamP, packedBits[row], + readFaxRow(bitStreamP, packedBits[row], bwHashP, &lineSize, &exception, &error); - handleRowException(exception, error, row, tolerateErrors); + handleRowException(exception, error, row, mustTolerateErrors); if (!error) { if (lineSize == 0) { @@ -775,7 +848,8 @@ readFax(struct BitStream * const bitStreamP, } } *rowsP = row; - *colsP = lineSizeAnalyzer.maxLineSize; + *colsP = imageLineSize(&lineSizeAnalyzer, mustCorrectLongLine); + *packedBitsP = packedBits; } @@ -789,6 +863,7 @@ main(int argc, const char * argv[]) { struct BitStream bitStream; unsigned int rows, cols; unsigned char ** packedBits; + BwHash * bwHashP; pm_proginit(&argc, argv); @@ -806,10 +881,10 @@ main(int argc, const char * argv[]) { } skipToNextLine(&bitStream); - buildHashes(&whash, &bhash); + bwHashP = newBwHash(); readFax(&bitStream, cmdline.stretch, cmdline.expectedLineSize, - !cmdline.stop_error, + !cmdline.stop_error, !!cmdline.correctlong, bwHashP, &packedBits, &cols, &rows); pm_close(ifP); @@ -826,5 +901,10 @@ main(int argc, const char * argv[]) { freeBits(packedBits, rows, cmdline.stretch); + freeBwHash(bwHashP); + return 0; } + + + |