diff options
Diffstat (limited to 'converter')
-rw-r--r-- | converter/other/bmptopnm.c | 6 | ||||
-rw-r--r-- | converter/other/cameratopam/camera.c | 6 | ||||
-rw-r--r-- | converter/other/cameratopam/foveon.c | 2 | ||||
-rw-r--r-- | converter/other/fiasco/codec/approx.c | 563 | ||||
-rw-r--r-- | converter/other/pamtosvg/vector.c | 2 | ||||
-rw-r--r-- | converter/other/pamtotiff.c | 81 | ||||
-rw-r--r-- | converter/other/svgtopam.c | 253 | ||||
-rw-r--r-- | converter/other/tifftopnm.c | 2 | ||||
-rw-r--r-- | converter/pbm/g3.h | 297 | ||||
-rw-r--r-- | converter/pbm/g3topbm.c | 96 | ||||
-rw-r--r-- | converter/pbm/pbmtog3.c | 717 | ||||
-rw-r--r-- | converter/pbm/pbmtox10bm | 24 | ||||
-rw-r--r-- | converter/ppm/ppmtoarbtxt.c | 52 | ||||
-rw-r--r-- | converter/ppm/ppmtompeg/jrevdct.c | 44 | ||||
-rw-r--r-- | converter/ppm/ppmtompeg/mfwddct.c | 31 |
15 files changed, 1375 insertions, 801 deletions
diff --git a/converter/other/bmptopnm.c b/converter/other/bmptopnm.c index 49e730fd..018b8326 100644 --- a/converter/other/bmptopnm.c +++ b/converter/other/bmptopnm.c @@ -1400,8 +1400,8 @@ isValidBmpBpp(unsigned int const cBitCount) { static void readBmp(FILE * const ifP, unsigned char *** const bmpRasterP, - int * const colsP, - int * const rowsP, + unsigned int * const colsP, + unsigned int * const rowsP, bool * const grayPresentP, bool * const colorPresentP, unsigned int * const cBitCountP, @@ -1566,7 +1566,7 @@ main(int argc, const char ** argv) { black and white and whether it has colors other than black, white, and gray. */ - int cols, rows; + unsigned int cols, rows; unsigned char ** bmpRaster; /* The raster part of the BMP image, as a row x column array, with each element being a raw byte from the BMP raster. Note that diff --git a/converter/other/cameratopam/camera.c b/converter/other/cameratopam/camera.c index 503551f1..f6196777 100644 --- a/converter/other/cameratopam/camera.c +++ b/converter/other/cameratopam/camera.c @@ -1023,6 +1023,7 @@ static void sony_decrypt (unsigned *data, int len, int start, int key) { static uint32_t pad[128]; unsigned int p; + unsigned int i; if (start) { for (p=0; p < 4; p++) @@ -1047,8 +1048,9 @@ static void sony_decrypt (unsigned *data, int len, int start, int key) pad[p] = u.word; } } - while (len--) - *data++ ^= pad[p++ & 0x7f] = pad[(p+1) & 0x7f] ^ pad[(p+65) & 0x7f]; + for (i = 0, p = 0; i < len; ++i, ++p) { + *data++ ^= pad[p & 0x7f] = pad[(p+1) & 0x7f] ^ pad[(p+65) & 0x7f]; + } } void diff --git a/converter/other/cameratopam/foveon.c b/converter/other/cameratopam/foveon.c index a3e5449a..992f3883 100644 --- a/converter/other/cameratopam/foveon.c +++ b/converter/other/cameratopam/foveon.c @@ -1,6 +1,6 @@ /* This code is licensed to the public by its copyright owners under GPL. */ -#define _XOPEN_SOURCE /* get M_PI */ +#define _XOPEN_SOURCE 500 /* get M_PI in math.h */ #include <stdio.h> #include <assert.h> diff --git a/converter/other/fiasco/codec/approx.c b/converter/other/fiasco/codec/approx.c index d47bac62..d8fefcaa 100644 --- a/converter/other/fiasco/codec/approx.c +++ b/converter/other/fiasco/codec/approx.c @@ -294,9 +294,9 @@ static bool_t used [MAXSTATES]; static void matching_pursuit (mp_t *mp, bool_t full_search, real_t price, - unsigned max_edges, int y_state, const range_t *range, - const domain_pool_t *domain_pool, const coeff_t *coeff, - const wfa_t *wfa, const coding_t *c) + unsigned max_edges, int y_state, const range_t *range, + const domain_pool_t *domain_pool, const coeff_t *coeff, + const wfa_t *wfa, const coding_t *c) /* * Find an approximation of the current 'range' with a linear * combination of vectors of the 'domain_pool'. The linear @@ -320,303 +320,310 @@ matching_pursuit (mp_t *mp, bool_t full_search, real_t price, * vectors, factors, rate, distortion and costs are stored in 'mp' */ { - unsigned n; /* current vector of the OB */ - int index; /* best fitting domain image */ - unsigned domain; /* counter */ - real_t norm; /* norm of range image */ - real_t additional_bits; /* bits for mc, nd, and tree */ - word_t *domain_blocks; /* current set of domain images */ - const real_t min_norm = 2e-3; /* lower bound of norm */ - unsigned best_n = 0; - unsigned size = size_of_level (range->level); + unsigned n; /* current vector of the OB */ + int index; /* best fitting domain image */ + unsigned domain; /* counter */ + real_t norm; /* norm of range image */ + real_t additional_bits; /* bits for mc, nd, and tree */ + word_t *domain_blocks; /* current set of domain images */ + const real_t min_norm = 2e-3; /* lower bound of norm */ + unsigned best_n = 0; + unsigned size = size_of_level (range->level); - /* - * Initialize domain pool and inner product arrays - */ - domain_blocks = domain_pool->generate (range->level, y_state, wfa, - domain_pool->model); - for (domain = 0; domain_blocks [domain] >= 0; domain++) - { - used [domain] = NO; - rem_denominator [domain] /* norm of domain */ - = get_ip_state_state (domain_blocks [domain], domain_blocks [domain], - range->level, c); - if (rem_denominator [domain] / size < min_norm) - used [domain] = YES; /* don't use domains with small norm */ - else - rem_numerator [domain] /* inner product <s_domain, b> */ - = get_ip_image_state (range->image, range->address, - range->level, domain_blocks [domain], c); - if (!used [domain] && fabs (rem_numerator [domain]) < min_norm) - used [domain] = YES; - } + /* + * Initialize domain pool and inner product arrays + */ + domain_blocks = domain_pool->generate (range->level, y_state, wfa, + domain_pool->model); + for (domain = 0; domain_blocks [domain] >= 0; domain++) + { + used [domain] = NO; + rem_denominator [domain] = /* norm of domain */ + get_ip_state_state (domain_blocks [domain], domain_blocks [domain], + range->level, c); + if (rem_denominator [domain] / size < min_norm) + used [domain] = YES; /* don't use domains with small norm */ + else + rem_numerator [domain] /* inner product <s_domain, b> */ + = get_ip_image_state (range->image, range->address, + range->level, domain_blocks [domain], c); + if (!used [domain] && fabs (rem_numerator [domain]) < min_norm) + used [domain] = YES; + } - /* - * Exclude all domain blocks given in array 'mp->exclude' - */ - for (n = 0; isdomain (mp->exclude [n]); n++) - used [mp->exclude [n]] = YES; + /* + * Exclude all domain blocks given in array 'mp->exclude' + */ + for (n = 0; isdomain (mp->exclude [n]); n++) + used [mp->exclude [n]] = YES; - /* - * Compute the approximation costs if 'range' is approximated with - * no linear combination, i.e. the error is equal to the square - * of the image norm and the size of the automaton is determined by - * storing only zero elements in the current matrix row - */ - for (norm = 0, n = 0; n < size; n++) - norm += square (c->pixels [range->address * size + n]); - - additional_bits = range->tree_bits + range->mv_tree_bits - + range->mv_coord_bits + range->nd_tree_bits - + range->nd_weights_bits; - - mp->err = norm; - mp->weights_bits = 0; - mp->matrix_bits = domain_pool->bits (domain_blocks, NULL, range->level, - y_state, wfa, domain_pool->model); - mp->costs = (mp->matrix_bits + mp->weights_bits - + additional_bits) * price + mp->err; - - n = 0; - do - { - /* - * Current approximation is: b = d_0 o_0 + ... + d_(n-1) o_(n-1) - * with corresponding costs 'range->err + range->bits * p'. - * For all remaining state images s_i (used[s_i] == NO) set - * o_n : = s_i - \sum(k = 0, ... , n-1) {(<s_i, o_k> / ||o_k||^2) o_k} - * and try to beat current costs. - * Choose that vector for the next orthogonalization step, - * which has minimal costs: s_index. - * (No progress is indicated by index == -1) - */ - - real_t min_matrix_bits = 0; - real_t min_weights_bits = 0; - real_t min_error = 0; - real_t min_weight [MAXEDGES]; - real_t min_costs = full_search ? MAXCOSTS : mp->costs; - - for (index = -1, domain = 0; domain_blocks [domain] >= 0; domain++) - if (!used [domain]) - { - real_t matrix_bits, weights_bits; + /* + * Compute the approximation costs if 'range' is approximated with + * no linear combination, i.e. the error is equal to the square + * of the image norm and the size of the automaton is determined by + * storing only zero elements in the current matrix row + */ + for (norm = 0, n = 0; n < size; n++) + norm += square (c->pixels [range->address * size + n]); + + additional_bits = range->tree_bits + range->mv_tree_bits + + range->mv_coord_bits + range->nd_tree_bits + + range->nd_weights_bits; + + mp->err = norm; + mp->weights_bits = 0; + mp->matrix_bits = domain_pool->bits (domain_blocks, NULL, range->level, + y_state, wfa, domain_pool->model); + mp->costs = (mp->matrix_bits + mp->weights_bits + + additional_bits) * price + mp->err; + + n = 0; + do + { /* - * To speed up the search through the domain images, - * the costs of using domain image 'domain' as next vector - * can be approximated in a first step: - * improvement of image quality - * <= square (rem_numerator[domain]) / rem_denominator[domain] + * Current approximation is: b = d_0 o_0 + ... + d_(n-1) o_(n-1) + * with corresponding costs 'range->err + range->bits * p'. + * For all remaining state images s_i (used[s_i] == NO) set + * o_n : = s_i - \sum(k = 0, ... , n-1) {(<s_i, o_k> / ||o_k||^2) o_k} + * and try to beat current costs. + * Choose that vector for the next orthogonalization step, + * which has minimal costs: s_index. + * (No progress is indicated by index == -1) */ - { - word_t vectors [MAXEDGES + 1]; - word_t states [MAXEDGES + 1]; - real_t weights [MAXEDGES + 1]; - unsigned i, k; + + real_t min_matrix_bits = 0; + real_t min_weights_bits = 0; + real_t min_error = 0; + real_t min_weight [MAXEDGES]; + real_t min_costs = full_search ? MAXCOSTS : mp->costs; + + for (index = -1, domain = 0; domain_blocks [domain] >= 0; domain++) + if (!used [domain]) + { + real_t matrix_bits, weights_bits; + /* + * To speed up the search through the domain images, + * the costs of using domain image 'domain' as next vector + * can be approximated in a first step: + * improvement of image quality + * <= square (rem_numerator[domain]) / rem_denominator[domain] + */ + { + word_t vectors [MAXEDGES + 1]; + word_t states [MAXEDGES + 1]; + real_t weights [MAXEDGES + 1]; + unsigned i, k; - for (i = 0, k = 0; k < n; k++) - if (mp->weight [k] != 0) - { - vectors [i] = mp->indices [k]; - states [i] = domain_blocks [vectors [i]]; - weights [i] = mp->weight [k]; - i++; - } - vectors [i] = domain; - states [i] = domain_blocks [domain]; - weights [i] = 0.5; - vectors [i + 1] = -1; - states [i + 1] = -1; - - weights_bits = coeff->bits (weights, states, range->level, - coeff); - matrix_bits = domain_pool->bits (domain_blocks, vectors, - range->level, y_state, - wfa, domain_pool->model); - } - if (((matrix_bits + weights_bits + additional_bits) * price + - mp->err - - square (rem_numerator [domain]) / rem_denominator [domain]) - < min_costs) - { - /* - * 1.) Compute the weights (linear factors) c_i of the - * linear combination - * b = c_0 v_0 + ... + c_(n-1) v_(n-1) + c_n v_'domain' - * Use backward substitution to obtain c_i from the linear - * factors of the lin. comb. b = d_0 o_0 + ... + d_n o_n - * of the corresponding orthogonal vectors {o_0, ..., o_n}. - * Vector o_n of the orthogonal basis is obtained by using - * vector 'v_domain' in step n of the Gram Schmidt - * orthogonalization (see above for definition of o_n). - * Recursive formula for the coefficients c_i: - * c_n := <b, o_n> / ||o_n||^2 - * for i = n - 1, ... , 0: - * c_i := <b, o_i> / ||o_i||^2 + - * \sum (k = i + 1, ... , n){ c_k <v_k, o_i> - * / ||o_i||^2 } - * 2.) Because linear factors are stored with reduced precision - * factor c_i is rounded with the given precision in step i - * of the recursive formula. - */ - - unsigned k; /* counter */ - int l; /* counter */ - real_t m_bits; /* number of matrix bits to store */ - real_t w_bits; /* number of weights bits to store */ - real_t r [MAXEDGES]; /* rounded linear factors */ - real_t f [MAXEDGES]; /* linear factors */ - int v [MAXEDGES]; /* mapping of domains to vectors */ - real_t costs; /* current approximation costs */ - real_t m_err; /* current approximation error */ - - f [n] = rem_numerator [domain] / rem_denominator [domain]; - v [n] = domain; /* corresponding mapping */ - for (k = 0; k < n; k++) - { - f [k] = ip_image_ortho_vector [k] / norm_ortho_vector [k]; - v [k] = mp->indices [k]; - } + for (i = 0, k = 0; k < n; k++) + if (mp->weight [k] != 0) + { + vectors [i] = mp->indices [k]; + states [i] = domain_blocks [vectors [i]]; + weights [i] = mp->weight [k]; + i++; + } + vectors [i] = domain; + states [i] = domain_blocks [domain]; + weights [i] = 0.5; + vectors [i + 1] = -1; + states [i + 1] = -1; + + weights_bits = coeff->bits (weights, states, range->level, + coeff); + matrix_bits = domain_pool->bits (domain_blocks, vectors, + range->level, y_state, + wfa, domain_pool->model); + } + if (((matrix_bits + weights_bits + additional_bits) * price + + mp->err - + square (rem_numerator[domain]) / rem_denominator[domain]) + < min_costs) + { + /* + * 1.) Compute the weights (linear factors) c_i of the + * linear combination + * b = c_0 v_0 + ... + c_(n-1) v_(n-1) + c_n v_'domain' + * Use backward substitution to obtain c_i from the linear + * factors of the lin. comb. b = d_0 o_0 + ... + d_n o_n + * of the corresponding orthogonal vectors {o_0, ..., o_n}. + * Vector o_n of the orthogonal basis is obtained by using + * vector 'v_domain' in step n of the Gram Schmidt + * orthogonalization (see above for definition of o_n). + * Recursive formula for the coefficients c_i: + * c_n := <b, o_n> / ||o_n||^2 + * for i = n - 1, ... , 0: + * c_i := <b, o_i> / ||o_i||^2 + + * \sum (k = i + 1, ... , n){ c_k <v_k, o_i> + * / ||o_i||^2 } + * 2.) Because linear factors are stored with reduced + * precision factor c_i is rounded with the given + * precision in step i of the recursive formula. + */ + + unsigned k; /* counter */ + int l; /* counter */ + real_t m_bits; /* number of matrix bits to store */ + real_t w_bits; /* number of weights bits to store */ + real_t r [MAXEDGES]; /* rounded linear factors */ + real_t f [MAXEDGES]; /* linear factors */ + int v [MAXEDGES]; /* mapping of domains to vectors*/ + real_t costs; /* current approximation costs */ + real_t m_err; /* current approximation error */ + + f [n] = rem_numerator [domain] / rem_denominator [domain]; + v [n] = domain; /* corresponding mapping */ + for (k = 0; k < n; k++) + { + f[k] = ip_image_ortho_vector[k] / norm_ortho_vector[k]; + v [k] = mp->indices [k]; + } - for (l = n; l >= 0; l--) - { - rpf_t *rpf = domain_blocks [v [l]] - ? coeff->rpf : coeff->dc_rpf; + for (l = n; l >= 0; --l) { + rpf_t * const rpf = domain_blocks[v[l]] + ? coeff->rpf : coeff->dc_rpf; + + unsigned int k; - r [l] = f [l] = btor (rtob (f [l], rpf), rpf); + r[l] = f[l] = btor(rtob(f[l], rpf), rpf); + + { + real_t const fl = f[l]; - for (k = 0; k < (unsigned) l; k++) - f [k] -= f [l] * ip_domain_ortho_vector [v [l]][k] - / norm_ortho_vector [k] ; - } - - /* - * Compute the number of output bits of the linear combination - * and store the weights with reduced precision. The - * resulting linear combination is - * b = r_0 v_0 + ... + r_(n-1) v_(n-1) + r_n v_'domain' - */ - { - word_t vectors [MAXEDGES + 1]; - word_t states [MAXEDGES + 1]; - real_t weights [MAXEDGES + 1]; - int i; + for (k = 0; k < l; ++k) { + f[k] -= fl * ip_domain_ortho_vector[v[l]][k] + / norm_ortho_vector[k]; + } + } + } + + /* + * Compute the number of output bits of the linear + * combination and store the weights with reduced + * precision. The resulting linear combination is + * b = r_0 v_0 + ... + r_(n-1) v_(n-1) + r_n v_'domain' + */ + { + word_t vectors [MAXEDGES + 1]; + word_t states [MAXEDGES + 1]; + real_t weights [MAXEDGES + 1]; + int i; - for (i = 0, k = 0; k <= n; k++) - if (f [k] != 0) - { - vectors [i] = v [k]; - states [i] = domain_blocks [v [k]]; - weights [i] = f [k]; - i++; - } - vectors [i] = -1; - states [i] = -1; - - w_bits = coeff->bits (weights, states, range->level, coeff); - m_bits = domain_pool->bits (domain_blocks, vectors, - range->level, y_state, - wfa, domain_pool->model); - } + for (i = 0, k = 0; k <= n; k++) + if (f [k] != 0) + { + vectors [i] = v [k]; + states [i] = domain_blocks [v [k]]; + weights [i] = f [k]; + i++; + } + vectors [i] = -1; + states [i] = -1; + + w_bits = + coeff->bits(weights, states, range->level, coeff); + m_bits = domain_pool->bits (domain_blocks, vectors, + range->level, y_state, + wfa, domain_pool->model); + } - /* - * To compute the approximation error, the corresponding - * linear factors of the linear combination - * b = r_0 o_0 + ... + r_(n-1) o_(n-1) + r_n o_'domain' - * with orthogonal vectors must be computed with following - * formula: - * r_i := r_i + - * \sum (k = i + 1, ... , n) { r_k <v_k, o_i> - * / ||o_i||^2 } - */ - for (l = 0; (unsigned) l <= n; l++) - { - /* - * compute <v_n, o_n> - */ - real_t a; - - a = get_ip_state_state (domain_blocks [v [l]], - domain_blocks [domain], - range->level, c); - for (k = 0; k < n; k++) - a -= ip_domain_ortho_vector [v [l]][k] - / norm_ortho_vector [k] - * ip_domain_ortho_vector [domain][k]; - ip_domain_ortho_vector [v [l]][n] = a; - } - norm_ortho_vector [n] = rem_denominator [domain]; - ip_image_ortho_vector [n] = rem_numerator [domain]; + /* + * To compute the approximation error, the corresponding + * linear factors of the linear combination + * b = r_0 o_0 + ... + r_(n-1) o_(n-1) + r_n o_'domain' + * with orthogonal vectors must be computed with following + * formula: + * r_i := r_i + + * \sum (k = i + 1, ... , n) { r_k <v_k, o_i> + * / ||o_i||^2 } + */ + for (l = 0; (unsigned) l <= n; l++) + { + /* + * compute <v_n, o_n> + */ + real_t a; + + a = get_ip_state_state (domain_blocks [v [l]], + domain_blocks [domain], + range->level, c); + for (k = 0; k < n; k++) + a -= ip_domain_ortho_vector [v [l]][k] + / norm_ortho_vector [k] + * ip_domain_ortho_vector [domain][k]; + ip_domain_ortho_vector [v [l]][n] = a; + } + norm_ortho_vector [n] = rem_denominator [domain]; + ip_image_ortho_vector [n] = rem_numerator [domain]; - for (k = 0; k <= n; k++) - for (l = k + 1; (unsigned) l <= n; l++) - r [k] += ip_domain_ortho_vector [v [l]][k] * r [l] - / norm_ortho_vector [k]; - /* - * Compute approximation error: - * error := ||b||^2 + - * \sum (k = 0, ... , n){r_k^2 ||o_k||^2 - 2 r_k <b, o_k>} - */ - m_err = norm; - for (k = 0; k <= n; k++) - m_err += square (r [k]) * norm_ortho_vector [k] - - 2 * r [k] * ip_image_ortho_vector [k]; - if (m_err < 0) /* TODO: return MAXCOSTS */ - warning ("Negative image norm: %f" - " (current domain: %d, level = %d)", - (double) m_err, domain, range->level); - - costs = (m_bits + w_bits + additional_bits) * price + m_err; - if (costs < min_costs) /* found a better approximation */ - { - index = domain; - min_costs = costs; - min_matrix_bits = m_bits; - min_weights_bits = w_bits; - min_error = m_err; - for (k = 0; k <= n; k++) - min_weight [k] = f [k]; - } - } - } + for (k = 0; k <= n; k++) + for (l = k + 1; (unsigned) l <= n; l++) + r [k] += ip_domain_ortho_vector [v [l]][k] * r [l] + / norm_ortho_vector [k]; + /* + * Compute approximation error: + * error := ||b||^2 + + * \sum (k = 0, ... , n){r_k^2 ||o_k||^2 - 2 r_k <b, o_k>} + */ + m_err = norm; + for (k = 0; k <= n; k++) + m_err += square (r [k]) * norm_ortho_vector [k] + - 2 * r [k] * ip_image_ortho_vector [k]; + if (m_err < 0) /* TODO: return MAXCOSTS */ + warning ("Negative image norm: %f" + " (current domain: %d, level = %d)", + (double) m_err, domain, range->level); + + costs = (m_bits + w_bits + additional_bits) * price + m_err; + if (costs < min_costs) /* found a better approximation */ + { + index = domain; + min_costs = costs; + min_matrix_bits = m_bits; + min_weights_bits = w_bits; + min_error = m_err; + for (k = 0; k <= n; k++) + min_weight [k] = f [k]; + } + } + } - if (index >= 0) /* found a better approximation */ - { - if (min_costs < mp->costs) - { - unsigned k; + if (index >= 0) /* found a better approximation */ + { + if (min_costs < mp->costs) + { + unsigned k; - mp->costs = min_costs; - mp->err = min_error; - mp->matrix_bits = min_matrix_bits; - mp->weights_bits = min_weights_bits; + mp->costs = min_costs; + mp->err = min_error; + mp->matrix_bits = min_matrix_bits; + mp->weights_bits = min_weights_bits; - for (k = 0; k <= n; k++) - mp->weight [k] = min_weight [k]; + for (k = 0; k <= n; k++) + mp->weight [k] = min_weight [k]; - best_n = n + 1; - } + best_n = n + 1; + } - mp->indices [n] = index; - mp->into [n] = domain_blocks [index]; + mp->indices [n] = index; + mp->into [n] = domain_blocks [index]; - used [index] = YES; + used [index] = YES; - /* - * Gram-Schmidt orthogonalization step n - */ - orthogonalize (index, n, range->level, min_norm, domain_blocks, c); - n++; - } - } - while (n < max_edges && index >= 0); + /* + * Gram-Schmidt orthogonalization step n + */ + orthogonalize (index, n, range->level, min_norm, domain_blocks, c); + n++; + } + } + while (n < max_edges && index >= 0); - mp->indices [best_n] = NO_EDGE; + mp->indices [best_n] = NO_EDGE; - mp->costs = (mp->matrix_bits + mp->weights_bits + additional_bits) * price - + mp->err; + mp->costs = (mp->matrix_bits + mp->weights_bits + additional_bits) * price + + mp->err; - Free (domain_blocks); + Free (domain_blocks); } static void diff --git a/converter/other/pamtosvg/vector.c b/converter/other/pamtosvg/vector.c index 0a5ef3a9..771e5f27 100644 --- a/converter/other/pamtosvg/vector.c +++ b/converter/other/pamtosvg/vector.c @@ -1,6 +1,6 @@ /* vector.c: vector/point operations. */ -#define _XOPEN_SOURCE /* Make sure M_PI is in <math.h> */ +#define _XOPEN_SOURCE 500 /* get M_PI in math.h */ #include <math.h> #include <errno.h> #include <assert.h> diff --git a/converter/other/pamtotiff.c b/converter/other/pamtotiff.c index 32057e55..139b1fd7 100644 --- a/converter/other/pamtotiff.c +++ b/converter/other/pamtotiff.c @@ -136,6 +136,44 @@ validateTagList(struct optNameValue const taglist[]) { static void +parseIndexbits(bool const indexbitsSpec, + char ** const indexbits, + CmdlineInfo * const cmdlineP) { + + if (indexbitsSpec) { + unsigned int i; + + /* Set initial values */ + cmdlineP->indexsizeAllowed.b1 = FALSE; + cmdlineP->indexsizeAllowed.b2 = FALSE; + cmdlineP->indexsizeAllowed.b4 = FALSE; + cmdlineP->indexsizeAllowed.b8 = FALSE; + + for (i = 0; indexbits[i]; ++i) { + const char * const thisItem = indexbits[i]; + if (streq(thisItem, "1")) + cmdlineP->indexsizeAllowed.b1 = TRUE; + else if (streq(thisItem, "2")) + cmdlineP->indexsizeAllowed.b2 = TRUE; + else if (streq(thisItem, "4")) + cmdlineP->indexsizeAllowed.b4 = TRUE; + else if (streq(thisItem, "8")) + cmdlineP->indexsizeAllowed.b8 = TRUE; + else + pm_error("Invalid item in -indexbits list: '%s'. " + "We recognize only 1, 2, 4, and 8", thisItem); + } + } else { + cmdlineP->indexsizeAllowed.b1 = FALSE; + cmdlineP->indexsizeAllowed.b2 = FALSE; + cmdlineP->indexsizeAllowed.b4 = FALSE; + cmdlineP->indexsizeAllowed.b8 = TRUE; + } +} + + + +static void parseCommandLine(int argc, const char ** const argv, CmdlineInfo * const cmdlineP) { @@ -149,7 +187,7 @@ parseCommandLine(int argc, unsigned int none, packbits, lzw, g3, g4, msb2lsb, lsb2msb, opt_2d, fill; unsigned int flate, adobeflate; - char * indexbits; + char ** indexbits; char * resolutionunit; unsigned int appendSpec, outputSpec, predictorSpec, rowsperstripSpec, @@ -192,7 +230,7 @@ parseCommandLine(int argc, &yresolutionSpec, 0); OPTENT3(0, "resolutionunit", OPT_STRING, &resolutionunit, &resolutionunitSpec, 0); - OPTENT3(0, "indexbits", OPT_STRING, &indexbits, + OPTENT3(0, "indexbits", OPT_STRINGLIST, &indexbits, &indexbitsSpec, 0); OPTENT3(0, "tag", OPT_NAMELIST, &cmdlineP->taglist, &tagSpec, 0); @@ -302,35 +340,16 @@ parseCommandLine(int argc, } else cmdlineP->resolutionunit = RESUNIT_INCH; - if (indexbitsSpec) { - if (strstr(indexbits, "1")) - cmdlineP->indexsizeAllowed.b1 = TRUE; - else - cmdlineP->indexsizeAllowed.b1 = FALSE; - if (strstr(indexbits, "2")) - cmdlineP->indexsizeAllowed.b2 = TRUE; - else - cmdlineP->indexsizeAllowed.b2 = FALSE; - if (strstr(indexbits, "4")) - cmdlineP->indexsizeAllowed.b4 = TRUE; - else - cmdlineP->indexsizeAllowed.b4 = FALSE; - if (strstr(indexbits, "8")) - cmdlineP->indexsizeAllowed.b8 = TRUE; - else - cmdlineP->indexsizeAllowed.b8 = FALSE; - } else { - cmdlineP->indexsizeAllowed.b1 = FALSE; - cmdlineP->indexsizeAllowed.b2 = FALSE; - cmdlineP->indexsizeAllowed.b4 = FALSE; - cmdlineP->indexsizeAllowed.b8 = TRUE; - } + parseIndexbits(indexbitsSpec, indexbits, cmdlineP); + + if (indexbitsSpec) + free(indexbits); if (tagSpec) validateTagList(cmdlineP->taglist); else { MALLOCARRAY_NOFAIL(cmdlineP->taglist, 1); - cmdlineP->taglist[0].name = NULL; + cmdlineP->taglist[0].name = NULL; cmdlineP->taglist[0].value = NULL; } @@ -346,6 +365,14 @@ parseCommandLine(int argc, static void +freeCmdline(CmdlineInfo const cmdline) { + + pm_optDestroyNameValueList(cmdline.taglist); +} + + + +static void fillRowOfSubBytePixels(struct pam * const pamP, const tuple * const tuplerow, unsigned char * const buf, @@ -1280,6 +1307,8 @@ main(int argc, const char *argv[]) { closeTiffGenerator(cmdline.writeMethod, tifP, ofd); pm_close(ifP); + freeCmdline(cmdline); + return 0; } diff --git a/converter/other/svgtopam.c b/converter/other/svgtopam.c index 09e3a24e..ca6f4dc7 100644 --- a/converter/other/svgtopam.c +++ b/converter/other/svgtopam.c @@ -147,36 +147,36 @@ typedef struct { unsigned int height; pixel ** pixels; pixval maxval; -} canvas; +} Canvas; typedef struct { pixel fillColor; -} style; +} Style; typedef struct { const char * pathText; /* This is e.g. "M0 0 L1 1 L9 8 Z" */ - style style; + Style style; /* This is the style as given by a 'style' attribute of <path> */ unsigned int pathTextLength; /* This is the length in characters of 'pathText'. It's redundant with 'pathText' and exists for convenience. */ -} path; +} Path; static void createPath(const char * const pathText, - style const style, - path ** const pathPP) { + Style const style, + Path ** const pathPP) { /*---------------------------------------------------------------------------- Create a path as described by a <path> element whose "style" attribute indicates style 'style' and whose "d" attribute indicates path data 'pathText'. -----------------------------------------------------------------------------*/ bool error; - path * pathP; + Path * pathP; MALLOCVAR(pathP); if (pathP == NULL) @@ -204,7 +204,7 @@ createPath(const char * const pathText, static void -destroyPath(path * const pathP) { +destroyPath(Path * const pathP) { assert(pathP->pathTextLength == strlen(pathP->pathText)); @@ -218,13 +218,13 @@ destroyPath(path * const pathP) { typedef struct { unsigned int x; unsigned int y; -} point; +} Point; -static point +static Point makePoint(unsigned int const x, unsigned int const y) { - point p; + Point p; p.x = x; p.y = y; @@ -233,7 +233,7 @@ makePoint(unsigned int const x, } static ppmd_point -makePpmdPoint(point const arg) { +makePpmdPoint(Point const arg) { ppmd_point p; @@ -248,16 +248,16 @@ typedef enum { PATH_LINETO, PATH_CLOSEPATH, PATH_CUBIC -} pathCommandVerb; +} PathCommandVerb; typedef struct { - point dest; -} pathMovetoArgs; + Point dest; +} PathMovetoArgs; typedef struct { /* Draw a line segment from current point to 'dest' */ - point dest; -} pathLinetoArgs; + Point dest; +} PathLinetoArgs; typedef struct { /* Draw a cubic spline from current point to 'dest' with control points @@ -272,19 +272,19 @@ typedef struct { A cubic curve is a plot of a polynomial equation of degree 3 (or less, for our purposes). */ - point dest; - point ctl1; - point ctl2; -} pathCubicArgs; + Point dest; + Point ctl1; + Point ctl2; +} PathCubicArgs; typedef struct { - pathCommandVerb verb; + PathCommandVerb verb; union { - pathMovetoArgs moveto; - pathLinetoArgs lineto; - pathCubicArgs cubic; + PathMovetoArgs moveto; + PathLinetoArgs lineto; + PathCubicArgs cubic; } args; -} pathCommand; +} PathCommand; @@ -292,15 +292,15 @@ typedef struct { /*---------------------------------------------------------------------------- This is an object for reading through a path from beginning to end. -----------------------------------------------------------------------------*/ - path * pathP; + Path * pathP; unsigned int cursor; -} pathReader; +} PathReader; static void -createPathReader(path * const pathP, - pathReader ** const pathReaderPP) { +pathReader_create(Path * const pathP, + PathReader ** const pathReaderPP) { - pathReader * pathReaderP; + PathReader * pathReaderP; MALLOCVAR_NOFAIL(pathReaderP); @@ -311,18 +311,31 @@ createPathReader(path * const pathP, } static void -destroyPathReader(pathReader * const pathReaderP) { +pathReader_destroy(PathReader * const pathReaderP) { free(pathReaderP); } +static const char * +pathReader_context(PathReader * const pathReaderP) { + + const char * retval; + + pm_asprintf(&retval, "Character position %u (starting at 0) in '%s'", + pathReaderP->cursor, pathReaderP->pathP->pathText); + + return retval; +} + + + static void -skipWhiteSpace(pathReader * const pathReaderP) { +pathReader_skipWhiteSpace(PathReader * const pathReaderP) { /*---------------------------------------------------------------------------- Move the cursor over any white space where it now points. -----------------------------------------------------------------------------*/ - const path * const pathP = pathReaderP->pathP; + const Path * const pathP = pathReaderP->pathP; while (isspace(pathP->pathText[pathReaderP->cursor]) && pathReaderP->cursor < pathP->pathTextLength) @@ -332,10 +345,10 @@ skipWhiteSpace(pathReader * const pathReaderP) { static void -getNumber(pathReader * const pathReaderP, - unsigned int * const numberP) { +pathReader_getNumber(PathReader * const pathReaderP, + unsigned int * const numberP) { - const path * const pathP = pathReaderP->pathP; + const Path * const pathP = pathReaderP->pathP; const char * const pathText = pathP->pathText; size_t const pathTextLength = pathP->pathTextLength; @@ -343,7 +356,10 @@ getNumber(pathReader * const pathReaderP, if (pathReaderP->cursor >= pathTextLength) pm_error("Path description ends where a number was expected."); - else { + else if (!isdigit(pathText[pathReaderP->cursor])) { + pm_error("Character '%c' instead of a digit where number expected", + pathText[pathReaderP->cursor]); + } else { unsigned int number; number = 0; /* initial value */ @@ -353,6 +369,10 @@ getNumber(pathReader * const pathReaderP, number = 10 * number + (pathText[pathReaderP->cursor] - '0'); ++pathReaderP->cursor; } + if (pathText[pathReaderP->cursor] == '.') + pm_error("Number contains decimal point. This program does not " + "know how to deal with fractional positions"); + *numberP = number; } } @@ -360,15 +380,15 @@ getNumber(pathReader * const pathReaderP, static void -getNextCommand(pathReader * const pathReaderP, - pathCommand * const pathCommandP, - bool * const endOfPathP) { +pathReader_getNextCommand(PathReader * const pathReaderP, + PathCommand * const pathCommandP, + bool * const endOfPathP) { - const path * const pathP = pathReaderP->pathP; + const Path * const pathP = pathReaderP->pathP; const char * const pathText = pathP->pathText; size_t const pathTextLength = pathP->pathTextLength; - skipWhiteSpace(pathReaderP); + pathReader_skipWhiteSpace(pathReaderP); if (pathReaderP->cursor >= pathTextLength) *endOfPathP = true; @@ -376,67 +396,79 @@ getNextCommand(pathReader * const pathReaderP, switch (pathText[pathReaderP->cursor++]) { case 'M': pathCommandP->verb = PATH_MOVETO; - skipWhiteSpace(pathReaderP); - getNumber(pathReaderP, &pathCommandP->args.moveto.dest.x); - skipWhiteSpace(pathReaderP); - getNumber(pathReaderP, &pathCommandP->args.moveto.dest.y); + pathReader_skipWhiteSpace(pathReaderP); + pathReader_getNumber(pathReaderP, + &pathCommandP->args.moveto.dest.x); + pathReader_skipWhiteSpace(pathReaderP); + pathReader_getNumber(pathReaderP, + &pathCommandP->args.moveto.dest.y); break; case 'L': pathCommandP->verb = PATH_LINETO; - skipWhiteSpace(pathReaderP); - getNumber(pathReaderP, &pathCommandP->args.lineto.dest.x); - skipWhiteSpace(pathReaderP); - getNumber(pathReaderP, &pathCommandP->args.lineto.dest.y); + pathReader_skipWhiteSpace(pathReaderP); + pathReader_getNumber(pathReaderP, + &pathCommandP->args.lineto.dest.x); + pathReader_skipWhiteSpace(pathReaderP); + pathReader_getNumber(pathReaderP, + &pathCommandP->args.lineto.dest.y); break; case 'C': pathCommandP->verb = PATH_CUBIC; - skipWhiteSpace(pathReaderP); - getNumber(pathReaderP, &pathCommandP->args.cubic.ctl1.x); - skipWhiteSpace(pathReaderP); - getNumber(pathReaderP, &pathCommandP->args.cubic.ctl1.y); - skipWhiteSpace(pathReaderP); - getNumber(pathReaderP, &pathCommandP->args.cubic.ctl2.x); - skipWhiteSpace(pathReaderP); - getNumber(pathReaderP, &pathCommandP->args.cubic.ctl2.y); - skipWhiteSpace(pathReaderP); - getNumber(pathReaderP, &pathCommandP->args.cubic.dest.x); - skipWhiteSpace(pathReaderP); - getNumber(pathReaderP, &pathCommandP->args.cubic.dest.y); + pathReader_skipWhiteSpace(pathReaderP); + pathReader_getNumber(pathReaderP, &pathCommandP->args.cubic.ctl1.x); + pathReader_skipWhiteSpace(pathReaderP); + pathReader_getNumber(pathReaderP, &pathCommandP->args.cubic.ctl1.y); + pathReader_skipWhiteSpace(pathReaderP); + pathReader_getNumber(pathReaderP, &pathCommandP->args.cubic.ctl2.x); + pathReader_skipWhiteSpace(pathReaderP); + pathReader_getNumber(pathReaderP, &pathCommandP->args.cubic.ctl2.y); + pathReader_skipWhiteSpace(pathReaderP); + pathReader_getNumber(pathReaderP, &pathCommandP->args.cubic.dest.x); + pathReader_skipWhiteSpace(pathReaderP); + pathReader_getNumber(pathReaderP, &pathCommandP->args.cubic.dest.y); break; case 'z': pathCommandP->verb = PATH_CLOSEPATH; break; - default: - pm_error("Unrecognized command in <path>: '%c'", - pathText[pathReaderP->cursor++]); + default: { + const char * const context = pathReader_context(pathReaderP); + + pm_errormsg("Unrecognized command in <path>: '%c'. %s", + pathText[pathReaderP->cursor++], context); + + pm_strfree(context); + + pm_longjmp(); + } } } } + static void -outlineObject(path * const pathP, +outlineObject(Path * const pathP, struct fillobj * const fillObjP) { /*---------------------------------------------------------------------------- Create a fill object, which contains and outline of the object and can be used with ppmd_fill() to fill the figure. The outline is as described by *pathP. -----------------------------------------------------------------------------*/ - pathReader * pathReaderP; + PathReader * pathReaderP; bool endOfPath; - point currentPos; - point subpathStart; + Point currentPos; + Point subpathStart; /* Point at which the current subpath starts */ endOfPath = false; subpathStart = makePoint(0,0); currentPos = subpathStart; - createPathReader(pathP, &pathReaderP); + pathReader_create(pathP, &pathReaderP); while (!endOfPath) { - pathCommand pathCommand; - getNextCommand(pathReaderP, &pathCommand, &endOfPath); + PathCommand pathCommand; + pathReader_getNextCommand(pathReaderP, &pathCommand, &endOfPath); if (!endOfPath) { switch (pathCommand.verb) { case PATH_MOVETO: @@ -448,7 +480,7 @@ outlineObject(path * const pathP, currentPos = subpathStart; break; case PATH_LINETO: { - point const dest = pathCommand.args.lineto.dest; + Point const dest = pathCommand.args.lineto.dest; if (traceDraw) pm_message("Lining to (%u, %u)", dest.x, dest.y); ppmd_line(NULL, 0, 0, 0, @@ -466,12 +498,14 @@ outlineObject(path * const pathP, currentPos = subpathStart; break; case PATH_CUBIC: { - point const dest = pathCommand.args.cubic.dest; - point const ctl1 = pathCommand.args.cubic.ctl1; - point const ctl2 = pathCommand.args.cubic.ctl2; + Point const dest = pathCommand.args.cubic.dest; + Point const ctl1 = pathCommand.args.cubic.ctl1; + Point const ctl2 = pathCommand.args.cubic.ctl2; if (traceDraw) pm_message("Doing cubic spline to (%u, %u)", dest.x, dest.y); + pm_error("SVG image contains a cubic spline path. " + "This program cannot process cubic splines."); /* We need to write ppmd_spline4() */ ppmd_spline4p(NULL, 0, 0, 0, makePpmdPoint(currentPos), @@ -484,14 +518,14 @@ outlineObject(path * const pathP, } } } - destroyPathReader(pathReaderP); + pathReader_destroy(pathReaderP); } static void -drawPath(canvas * const canvasP, - path * const pathP) { +drawPath(Canvas * const canvasP, + Path * const pathP) { /*---------------------------------------------------------------------------- Draw the path 'pathP' on the canvas 'canvasP'. -----------------------------------------------------------------------------*/ @@ -518,10 +552,10 @@ drawPath(canvas * const canvasP, -static style +static Style interpretStyle(const char * const styleAttr) { - style style; + Style style; char * buffer; @@ -582,7 +616,7 @@ interpretStyle(const char * const styleAttr) { static void getPathAttributes(xmlTextReaderPtr const xmlReaderP, - style * const styleP, + Style * const styleP, const char ** const pathP) { const char * const style = getAttribute(xmlReaderP, "style"); @@ -628,11 +662,11 @@ processSubPathNode(xmlTextReaderPtr const xmlReaderP, static void processPathElement(xmlTextReaderPtr const xmlReaderP, - canvas * const canvasP) { + Canvas * const canvasP) { - style style; + Style style; const char * pathData; - path * pathP; + Path * pathP; bool endOfPath; assert(xmlTextReaderNodeType(xmlReaderP) == XML_READER_TYPE_ELEMENT); @@ -670,29 +704,6 @@ processPathElement(xmlTextReaderPtr const xmlReaderP, static void -stringToUint(const char * const string, - unsigned int * const uintP, - const char ** const errorP) { - - /* TODO: move this to nstring.c */ - - if (strlen(string) == 0) - pm_asprintf(errorP, "Value is a null string"); - else { - char * tailptr; - - *uintP = strtoul(string, &tailptr, 10); - - if (*tailptr != '\0') - pm_asprintf(errorP, "Non-numeric crap in string: '%s'", tailptr); - else - *errorP = NULL; - } -} - - - -static void getSvgAttributes(xmlTextReaderPtr const xmlReaderP, unsigned int * const colsP, unsigned int * const rowsP) { @@ -702,14 +713,16 @@ getSvgAttributes(xmlTextReaderPtr const xmlReaderP, const char * error; - stringToUint(width, colsP, &error); + pm_string_to_uint(width, colsP, &error); if (error) { - pm_error("'width' attribute of <svg> has invalid value. %s", error); + pm_error("'width' attribute of <svg> has invalid value '%s'. %s", + width, error); pm_strfree(error); } - stringToUint(height, rowsP, &error); + pm_string_to_uint(height, rowsP, &error); if (error) { - pm_error("'height' attribute of <svg> has invalid value. %s", error); + pm_error("'height' attribute of <svg> has invalid value '%s'. %s", + height, error); pm_strfree(error); } } @@ -718,7 +731,7 @@ getSvgAttributes(xmlTextReaderPtr const xmlReaderP, static void processSubSvgElement(xmlTextReaderPtr const xmlReaderP, - canvas * const canvasP) { + Canvas * const canvasP) { const char * const nodeName = currentNodeName(xmlReaderP); @@ -735,7 +748,7 @@ processSubSvgElement(xmlTextReaderPtr const xmlReaderP, static void processSubSvgNode(xmlTextReaderPtr const xmlReaderP, - canvas * const canvasP, + Canvas * const canvasP, bool * const endOfSvgP) { xmlReaderTypes const nodeType = xmlTextReaderNodeType(xmlReaderP); @@ -765,9 +778,9 @@ static void createCanvas(unsigned int const width, unsigned int const height, pixval const maxval, - canvas ** const canvasPP) { + Canvas ** const canvasPP) { - canvas * canvasP; + Canvas * canvasP; MALLOCVAR_NOFAIL(canvasP); @@ -782,7 +795,7 @@ createCanvas(unsigned int const width, static void -destroyCanvas(canvas * const canvasP) { +destroyCanvas(Canvas * const canvasP) { ppm_freearray(canvasP->pixels, canvasP->height); @@ -793,7 +806,7 @@ destroyCanvas(canvas * const canvasP) { static void writePam(FILE * const ofP, - canvas * const canvasP) { + Canvas * const canvasP) { unsigned int row; struct pam pam; @@ -839,7 +852,7 @@ processSvgElement(xmlTextReaderPtr const xmlReaderP, unsigned int width, height; bool endOfSvg; - canvas * canvasP; + Canvas * canvasP; assert(xmlTextReaderNodeType(xmlReaderP) == XML_READER_TYPE_ELEMENT); assert(streq(currentNodeName(xmlReaderP), "svg")); diff --git a/converter/other/tifftopnm.c b/converter/other/tifftopnm.c index e72aff5e..c1e7af85 100644 --- a/converter/other/tifftopnm.c +++ b/converter/other/tifftopnm.c @@ -191,7 +191,7 @@ getBps(TIFF * const tif, if (bps < 1 || (bps > 8 && bps != 16 && bps != 32)) pm_error("This program can process Tiff images with only " - "1-8 or 16 bits per sample. The input Tiff image " + "1-8 or 16 or 32 bits per sample. The input Tiff image " "has %hu bits per sample.", bps); else *bpsP = bps; diff --git a/converter/pbm/g3.h b/converter/pbm/g3.h index e982f2da..42ba91c5 100644 --- a/converter/pbm/g3.h +++ b/converter/pbm/g3.h @@ -24,12 +24,30 @@ There is also the newer G4. */ -typedef struct g3TableEntry { - short int code; - short int length; -} g3TableEntry; +typedef struct G3TableEntry { + unsigned short int code; + unsigned short int length; +} G3TableEntry; -static struct g3TableEntry ttable[] = { + +struct BitString { + /* A string of bits, up to as many fit in 32 bits. */ + uint32_t intBuffer; + /* The bits are in the 'bitCount' least significant bit positions + of this number. The rest of the bits of this number are always + zero. + */ + unsigned int bitCount; + /* The length of the bit string */ + + /* Example: The bit string 010100 would be represented by + bitCount = 6, intBuffer = 20 + (N.B. 20 = 00000000 00000000 00000000 00010100 in binary) + */ +}; + + +static struct G3TableEntry ttable[] = { /* TERMWHITE TERMBLACK */ { 0x35, 8 }, { 0x37, 10 }, /* white 0 , black 0 */ { 0x07, 6 }, { 0x02, 3 }, @@ -143,4 +161,273 @@ static struct g3TableEntry ttable[] = { #define mtable ((ttable)+64*2) + +struct PrefabCode { + unsigned int leadBits; + unsigned int trailBits; + struct BitString activeBits; +}; + + +struct PrefabCode const prefabCode[256] = +{ +{ 0, 8, { 0x0000, 0}}, /* 000 */ +{ 7, 1, { 0x0000, 0}}, /* 001 */ +{ 6, 1, { 0x0002, 3}}, /* 002 */ +{ 6, 2, { 0x0000, 0}}, /* 003 */ +{ 5, 2, { 0x0002, 3}}, /* 004 */ +{ 5, 1, { 0x0087, 9}}, /* 005 */ +{ 5, 1, { 0x0003, 2}}, /* 006 */ +{ 5, 3, { 0x0000, 0}}, /* 007 */ +{ 4, 3, { 0x0002, 3}}, /* 008 */ +{ 4, 1, { 0x0027, 7}}, /* 009 */ +{ 4, 1, { 0x043a, 12}}, /* 010 */ +{ 4, 2, { 0x0087, 9}}, /* 011 */ +{ 4, 2, { 0x0003, 2}}, /* 012 */ +{ 4, 1, { 0x00c7, 8}}, /* 013 */ +{ 4, 1, { 0x0002, 2}}, /* 014 */ +{ 4, 4, { 0x0000, 0}}, /* 015 */ +{ 3, 4, { 0x0002, 3}}, /* 016 */ +{ 3, 1, { 0x0028, 7}}, /* 017 */ +{ 3, 1, { 0x013a, 10}}, /* 018 */ +{ 3, 2, { 0x0027, 7}}, /* 019 */ +{ 3, 2, { 0x043a, 12}}, /* 020 */ +{ 3, 1, { 0x10e87, 18}}, /* 021 */ +{ 3, 1, { 0x021f, 11}}, /* 022 */ +{ 3, 3, { 0x0087, 9}}, /* 023 */ +{ 3, 3, { 0x0003, 2}}, /* 024 */ +{ 3, 1, { 0x0037, 6}}, /* 025 */ +{ 3, 1, { 0x063a, 11}}, /* 026 */ +{ 3, 2, { 0x00c7, 8}}, /* 027 */ +{ 3, 2, { 0x0002, 2}}, /* 028 */ +{ 3, 1, { 0x0087, 8}}, /* 029 */ +{ 3, 1, { 0x0003, 3}}, /* 030 */ +{ 3, 5, { 0x0000, 0}}, /* 031 */ +{ 2, 5, { 0x0002, 3}}, /* 032 */ +{ 2, 1, { 0x002b, 7}}, /* 033 */ +{ 2, 1, { 0x0142, 10}}, /* 034 */ +{ 2, 2, { 0x0028, 7}}, /* 035 */ +{ 2, 2, { 0x013a, 10}}, /* 036 */ +{ 2, 1, { 0x4e87, 16}}, /* 037 */ +{ 2, 1, { 0x009f, 9}}, /* 038 */ +{ 2, 3, { 0x0027, 7}}, /* 039 */ +{ 2, 3, { 0x043a, 12}}, /* 040 */ +{ 2, 1, { 0x43a7, 16}}, /* 041 */ +{ 2, 1, { 0x8743a, 21}}, /* 042 */ +{ 2, 2, { 0x10e87, 18}}, /* 043 */ +{ 2, 2, { 0x021f, 11}}, /* 044 */ +{ 2, 1, { 0x87c7, 17}}, /* 045 */ +{ 2, 1, { 0x021e, 11}}, /* 046 */ +{ 2, 4, { 0x0087, 9}}, /* 047 */ +{ 2, 4, { 0x0003, 2}}, /* 048 */ +{ 2, 1, { 0x0038, 6}}, /* 049 */ +{ 2, 1, { 0x01ba, 9}}, /* 050 */ +{ 2, 2, { 0x0037, 6}}, /* 051 */ +{ 2, 2, { 0x063a, 11}}, /* 052 */ +{ 2, 1, { 0x18e87, 17}}, /* 053 */ +{ 2, 1, { 0x031f, 10}}, /* 054 */ +{ 2, 3, { 0x00c7, 8}}, /* 055 */ +{ 2, 3, { 0x0002, 2}}, /* 056 */ +{ 2, 1, { 0x0027, 6}}, /* 057 */ +{ 2, 1, { 0x043a, 11}}, /* 058 */ +{ 2, 2, { 0x0087, 8}}, /* 059 */ +{ 2, 2, { 0x0003, 3}}, /* 060 */ +{ 2, 1, { 0x00c7, 9}}, /* 061 */ +{ 2, 1, { 0x0003, 4}}, /* 062 */ +{ 2, 6, { 0x0000, 0}}, /* 063 */ +{ 1, 6, { 0x0002, 3}}, /* 064 */ +{ 1, 1, { 0x002c, 7}}, /* 065 */ +{ 1, 1, { 0x015a, 10}}, /* 066 */ +{ 1, 2, { 0x002b, 7}}, /* 067 */ +{ 1, 2, { 0x0142, 10}}, /* 068 */ +{ 1, 1, { 0x5087, 16}}, /* 069 */ +{ 1, 1, { 0x00a3, 9}}, /* 070 */ +{ 1, 3, { 0x0028, 7}}, /* 071 */ +{ 1, 3, { 0x013a, 10}}, /* 072 */ +{ 1, 1, { 0x13a7, 14}}, /* 073 */ +{ 1, 1, { 0x2743a, 19}}, /* 074 */ +{ 1, 2, { 0x4e87, 16}}, /* 075 */ +{ 1, 2, { 0x009f, 9}}, /* 076 */ +{ 1, 1, { 0x27c7, 15}}, /* 077 */ +{ 1, 1, { 0x009e, 9}}, /* 078 */ +{ 1, 4, { 0x0027, 7}}, /* 079 */ +{ 1, 4, { 0x043a, 12}}, /* 080 */ +{ 1, 1, { 0x43a8, 16}}, /* 081 */ +{ 1, 1, { 0x21d3a, 19}}, /* 082 */ +{ 1, 2, { 0x43a7, 16}}, /* 083 */ +{ 1, 2, { 0x8743a, 21}}, /* 084 */ +{ 1, 1, {0x21d0e87, 27}}, /* 085 */ +{ 1, 1, { 0x43a1f, 20}}, /* 086 */ +{ 1, 3, { 0x10e87, 18}}, /* 087 */ +{ 1, 3, { 0x021f, 11}}, /* 088 */ +{ 1, 1, { 0x21f7, 15}}, /* 089 */ +{ 1, 1, { 0x43e3a, 20}}, /* 090 */ +{ 1, 2, { 0x87c7, 17}}, /* 091 */ +{ 1, 2, { 0x021e, 11}}, /* 092 */ +{ 1, 1, { 0x8787, 17}}, /* 093 */ +{ 1, 1, { 0x043b, 12}}, /* 094 */ +{ 1, 5, { 0x0087, 9}}, /* 095 */ +{ 1, 5, { 0x0003, 2}}, /* 096 */ +{ 1, 1, { 0x003b, 6}}, /* 097 */ +{ 1, 1, { 0x01c2, 9}}, /* 098 */ +{ 1, 2, { 0x0038, 6}}, /* 099 */ +{ 1, 2, { 0x01ba, 9}}, /* 100 */ +{ 1, 1, { 0x6e87, 15}}, /* 101 */ +{ 1, 1, { 0x00df, 8}}, /* 102 */ +{ 1, 3, { 0x0037, 6}}, /* 103 */ +{ 1, 3, { 0x063a, 11}}, /* 104 */ +{ 1, 1, { 0x63a7, 15}}, /* 105 */ +{ 1, 1, { 0xc743a, 20}}, /* 106 */ +{ 1, 2, { 0x18e87, 17}}, /* 107 */ +{ 1, 2, { 0x031f, 10}}, /* 108 */ +{ 1, 1, { 0xc7c7, 16}}, /* 109 */ +{ 1, 1, { 0x031e, 10}}, /* 110 */ +{ 1, 4, { 0x00c7, 8}}, /* 111 */ +{ 1, 4, { 0x0002, 2}}, /* 112 */ +{ 1, 1, { 0x0028, 6}}, /* 113 */ +{ 1, 1, { 0x013a, 9}}, /* 114 */ +{ 1, 2, { 0x0027, 6}}, /* 115 */ +{ 1, 2, { 0x043a, 11}}, /* 116 */ +{ 1, 1, { 0x10e87, 17}}, /* 117 */ +{ 1, 1, { 0x021f, 10}}, /* 118 */ +{ 1, 3, { 0x0087, 8}}, /* 119 */ +{ 1, 3, { 0x0003, 3}}, /* 120 */ +{ 1, 1, { 0x0037, 7}}, /* 121 */ +{ 1, 1, { 0x063a, 12}}, /* 122 */ +{ 1, 2, { 0x00c7, 9}}, /* 123 */ +{ 1, 2, { 0x0003, 4}}, /* 124 */ +{ 1, 1, { 0x00c7, 10}}, /* 125 */ +{ 1, 1, { 0x0002, 4}}, /* 126 */ +{ 1, 7, { 0x0000, 0}}, /* 127 */ +{ 1, 7, { 0x0000, 0}}, /* 128 */ +{ 1, 1, { 0x000e, 4}}, /* 129 */ +{ 1, 1, { 0x0062, 7}}, /* 130 */ +{ 1, 2, { 0x000c, 4}}, /* 131 */ +{ 1, 2, { 0x005a, 7}}, /* 132 */ +{ 1, 1, { 0x1687, 13}}, /* 133 */ +{ 1, 1, { 0x002f, 6}}, /* 134 */ +{ 1, 3, { 0x000b, 4}}, /* 135 */ +{ 1, 3, { 0x0042, 7}}, /* 136 */ +{ 1, 1, { 0x0427, 11}}, /* 137 */ +{ 1, 1, { 0x843a, 16}}, /* 138 */ +{ 1, 2, { 0x1087, 13}}, /* 139 */ +{ 1, 2, { 0x0023, 6}}, /* 140 */ +{ 1, 1, { 0x08c7, 12}}, /* 141 */ +{ 1, 1, { 0x0022, 6}}, /* 142 */ +{ 1, 4, { 0x0008, 4}}, /* 143 */ +{ 1, 4, { 0x003a, 7}}, /* 144 */ +{ 1, 1, { 0x03a8, 11}}, /* 145 */ +{ 1, 1, { 0x1d3a, 14}}, /* 146 */ +{ 1, 2, { 0x03a7, 11}}, /* 147 */ +{ 1, 2, { 0x743a, 16}}, /* 148 */ +{ 1, 1, { 0x1d0e87, 22}}, /* 149 */ +{ 1, 1, { 0x3a1f, 15}}, /* 150 */ +{ 1, 3, { 0x0e87, 13}}, /* 151 */ +{ 1, 3, { 0x001f, 6}}, /* 152 */ +{ 1, 1, { 0x01f7, 10}}, /* 153 */ +{ 1, 1, { 0x3e3a, 15}}, /* 154 */ +{ 1, 2, { 0x07c7, 12}}, /* 155 */ +{ 1, 2, { 0x001e, 6}}, /* 156 */ +{ 1, 1, { 0x0787, 12}}, /* 157 */ +{ 1, 1, { 0x003b, 7}}, /* 158 */ +{ 1, 5, { 0x0007, 4}}, /* 159 */ +{ 1, 5, { 0x003a, 9}}, /* 160 */ +{ 1, 1, { 0x03ab, 13}}, /* 161 */ +{ 1, 1, { 0x1d42, 16}}, /* 162 */ +{ 1, 2, { 0x03a8, 13}}, /* 163 */ +{ 1, 2, { 0x1d3a, 16}}, /* 164 */ +{ 1, 1, { 0x74e87, 22}}, /* 165 */ +{ 1, 1, { 0x0e9f, 15}}, /* 166 */ +{ 1, 3, { 0x03a7, 13}}, /* 167 */ +{ 1, 3, { 0x743a, 18}}, /* 168 */ +{ 1, 1, { 0x743a7, 22}}, /* 169 */ +{ 1, 1, { 0xe8743a, 27}}, /* 170 */ +{ 1, 2, { 0x1d0e87, 24}}, /* 171 */ +{ 1, 2, { 0x3a1f, 17}}, /* 172 */ +{ 1, 1, { 0xe87c7, 23}}, /* 173 */ +{ 1, 1, { 0x3a1e, 17}}, /* 174 */ +{ 1, 4, { 0x0e87, 15}}, /* 175 */ +{ 1, 4, { 0x001f, 8}}, /* 176 */ +{ 1, 1, { 0x01f8, 12}}, /* 177 */ +{ 1, 1, { 0x0fba, 15}}, /* 178 */ +{ 1, 2, { 0x01f7, 12}}, /* 179 */ +{ 1, 2, { 0x3e3a, 17}}, /* 180 */ +{ 1, 1, { 0xf8e87, 23}}, /* 181 */ +{ 1, 1, { 0x1f1f, 16}}, /* 182 */ +{ 1, 3, { 0x07c7, 14}}, /* 183 */ +{ 1, 3, { 0x001e, 8}}, /* 184 */ +{ 1, 1, { 0x01e7, 12}}, /* 185 */ +{ 1, 1, { 0x3c3a, 17}}, /* 186 */ +{ 1, 2, { 0x0787, 14}}, /* 187 */ +{ 1, 2, { 0x003b, 9}}, /* 188 */ +{ 1, 1, { 0x0ec7, 15}}, /* 189 */ +{ 1, 1, { 0x0073, 10}}, /* 190 */ +{ 1, 6, { 0x0007, 6}}, /* 191 */ +{ 2, 6, { 0x0000, 0}}, /* 192 */ +{ 2, 1, { 0x000c, 4}}, /* 193 */ +{ 2, 1, { 0x005a, 7}}, /* 194 */ +{ 2, 2, { 0x000b, 4}}, /* 195 */ +{ 2, 2, { 0x0042, 7}}, /* 196 */ +{ 2, 1, { 0x1087, 13}}, /* 197 */ +{ 2, 1, { 0x0023, 6}}, /* 198 */ +{ 2, 3, { 0x0008, 4}}, /* 199 */ +{ 2, 3, { 0x003a, 7}}, /* 200 */ +{ 2, 1, { 0x03a7, 11}}, /* 201 */ +{ 2, 1, { 0x743a, 16}}, /* 202 */ +{ 2, 2, { 0x0e87, 13}}, /* 203 */ +{ 2, 2, { 0x001f, 6}}, /* 204 */ +{ 2, 1, { 0x07c7, 12}}, /* 205 */ +{ 2, 1, { 0x001e, 6}}, /* 206 */ +{ 2, 4, { 0x0007, 4}}, /* 207 */ +{ 2, 4, { 0x003a, 9}}, /* 208 */ +{ 2, 1, { 0x03a8, 13}}, /* 209 */ +{ 2, 1, { 0x1d3a, 16}}, /* 210 */ +{ 2, 2, { 0x03a7, 13}}, /* 211 */ +{ 2, 2, { 0x743a, 18}}, /* 212 */ +{ 2, 1, { 0x1d0e87, 24}}, /* 213 */ +{ 2, 1, { 0x3a1f, 17}}, /* 214 */ +{ 2, 3, { 0x0e87, 15}}, /* 215 */ +{ 2, 3, { 0x001f, 8}}, /* 216 */ +{ 2, 1, { 0x01f7, 12}}, /* 217 */ +{ 2, 1, { 0x3e3a, 17}}, /* 218 */ +{ 2, 2, { 0x07c7, 14}}, /* 219 */ +{ 2, 2, { 0x001e, 8}}, /* 220 */ +{ 2, 1, { 0x0787, 14}}, /* 221 */ +{ 2, 1, { 0x003b, 9}}, /* 222 */ +{ 2, 5, { 0x0007, 6}}, /* 223 */ +{ 3, 5, { 0x0000, 0}}, /* 224 */ +{ 3, 1, { 0x000b, 4}}, /* 225 */ +{ 3, 1, { 0x0042, 7}}, /* 226 */ +{ 3, 2, { 0x0008, 4}}, /* 227 */ +{ 3, 2, { 0x003a, 7}}, /* 228 */ +{ 3, 1, { 0x0e87, 13}}, /* 229 */ +{ 3, 1, { 0x001f, 6}}, /* 230 */ +{ 3, 3, { 0x0007, 4}}, /* 231 */ +{ 3, 3, { 0x003a, 9}}, /* 232 */ +{ 3, 1, { 0x03a7, 13}}, /* 233 */ +{ 3, 1, { 0x743a, 18}}, /* 234 */ +{ 3, 2, { 0x0e87, 15}}, /* 235 */ +{ 3, 2, { 0x001f, 8}}, /* 236 */ +{ 3, 1, { 0x07c7, 14}}, /* 237 */ +{ 3, 1, { 0x001e, 8}}, /* 238 */ +{ 3, 4, { 0x0007, 6}}, /* 239 */ +{ 4, 4, { 0x0000, 0}}, /* 240 */ +{ 4, 1, { 0x0008, 4}}, /* 241 */ +{ 4, 1, { 0x003a, 7}}, /* 242 */ +{ 4, 2, { 0x0007, 4}}, /* 243 */ +{ 4, 2, { 0x003a, 9}}, /* 244 */ +{ 4, 1, { 0x0e87, 15}}, /* 245 */ +{ 4, 1, { 0x001f, 8}}, /* 246 */ +{ 4, 3, { 0x0007, 6}}, /* 247 */ +{ 5, 3, { 0x0000, 0}}, /* 248 */ +{ 5, 1, { 0x0007, 4}}, /* 249 */ +{ 5, 1, { 0x003a, 9}}, /* 250 */ +{ 5, 2, { 0x0007, 6}}, /* 251 */ +{ 6, 2, { 0x0000, 0}}, /* 252 */ +{ 6, 1, { 0x0007, 6}}, /* 253 */ +{ 7, 1, { 0x0000, 0}}, /* 254 */ +{ 0, 8, { 0x0000, 0}}, /* 255 */ + }; + #endif + diff --git a/converter/pbm/g3topbm.c b/converter/pbm/g3topbm.c index 83479b91..2b486324 100644 --- a/converter/pbm/g3topbm.c +++ b/converter/pbm/g3topbm.c @@ -44,11 +44,37 @@ #define HASHSIZE 1021 -static g3TableEntry * whash[HASHSIZE]; -static g3TableEntry * bhash[HASHSIZE]; +#define MAXFILLBITS (5 * 9600) +/* +Fill bits are for flow control. This was important when DRAM was +expensive and fax machines came with small buffers. -struct cmdlineInfo { +If data arrives too quickly it may overflow the buffer of the +receiving device. On sending devices transmission time of compressed +data representing a single row can be shorter than the time required +to scan and encode. The CCITT standard allows sending devices to +insert fill bits to put communication on hold in these cases. + +By the CCITT standard, the maximum transmission time for one row is: + +100 - 400 pixels/inch 13 seconds +(standard mode: 200 pixels/inch) +600 pixels/inch 19 seconds +1200 pixels/inch 37 seconds + +If one row is not received within the above limits, the receiving +machine must disconnect the line. + +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. */ @@ -63,8 +89,8 @@ struct cmdlineInfo { static void -parseCommandLine(int argc, char ** const argv, - struct cmdlineInfo * const cmdlineP) { +parseCommandLine(int argc, const char ** const argv, + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. @@ -98,7 +124,7 @@ parseCommandLine(int argc, char ** const argv, 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, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char**)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ if (widthSpec && paper_sizeSpec) @@ -136,7 +162,7 @@ parseCommandLine(int argc, char ** const argv, -struct bitStream { +struct BitStream { FILE * fileP; bool reversebits; @@ -156,7 +182,7 @@ struct bitStream { static void -readBit(struct bitStream * const bitStreamP, +readBit(struct BitStream * const bitStreamP, unsigned int * const bitP, const char ** const errorP) { /*---------------------------------------------------------------------------- @@ -189,7 +215,7 @@ readBit(struct bitStream * const bitStreamP, static void -readBitAndDetectEol(struct bitStream * const bitStreamP, +readBitAndDetectEol(struct BitStream * const bitStreamP, unsigned int * const bitP, bool * const eolP, const char ** const errorP) { @@ -217,7 +243,7 @@ readBitAndDetectEol(struct bitStream * const bitStreamP, static void -initBitStream(struct bitStream * const bitStreamP, +initBitStream(struct BitStream * const bitStreamP, FILE * const fileP, bool const reversebits) { @@ -230,7 +256,7 @@ initBitStream(struct bitStream * const bitStreamP, static void -skipToNextLine(struct bitStream * const bitStreamP) { +skipToNextLine(struct BitStream * const bitStreamP) { bool eol; const char * error; @@ -248,8 +274,8 @@ skipToNextLine(struct bitStream * const bitStreamP) { static void -addtohash(g3TableEntry * hash[], - g3TableEntry table[], +addtohash(G3TableEntry * hash[], + G3TableEntry table[], unsigned int const n, int const a, int const b) { @@ -257,7 +283,7 @@ addtohash(g3TableEntry * hash[], unsigned int i; for (i = 0; i < n; ++i) { - g3TableEntry * const teP = &table[i*2]; + G3TableEntry * const teP = &table[i*2]; unsigned int const pos = ((teP->length + a) * (teP->code + b)) % HASHSIZE; if (hash[pos]) @@ -268,15 +294,15 @@ addtohash(g3TableEntry * hash[], -static g3TableEntry * -hashfind(g3TableEntry * hash[], +static G3TableEntry * +hashfind(G3TableEntry * hash[], int const length, int const code, int const a, int const b) { unsigned int pos; - g3TableEntry * te; + G3TableEntry * te; pos = ((length + a) * (code + b)) % HASHSIZE; te = hash[pos]; @@ -286,8 +312,8 @@ hashfind(g3TableEntry * hash[], static void -buildHashes(g3TableEntry * (*whashP)[HASHSIZE], - g3TableEntry * (*bhashP)[HASHSIZE]) { +buildHashes(G3TableEntry * (*whashP)[HASHSIZE], + G3TableEntry * (*bhashP)[HASHSIZE]) { unsigned int i; @@ -315,7 +341,7 @@ makeRowWhite(unsigned char * const packedBitrow, -static g3TableEntry * +static G3TableEntry * g3code(unsigned int const curcode, unsigned int const curlen, bit const color) { @@ -326,7 +352,7 @@ 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; + G3TableEntry * retval; switch (color) { case PBM_WHITE: @@ -383,7 +409,7 @@ writeBlackBitSpan(unsigned char * const packedBitrow, enum g3tableId {TERMWHITE, TERMBLACK, MKUPWHITE, MKUPBLACK}; static void -processG3Code(const g3TableEntry * const teP, +processG3Code(const G3TableEntry * const teP, unsigned char * const packedBitrow, unsigned int * const colP, bit * const colorP, @@ -452,7 +478,7 @@ formatBadCodeException(const char ** const exceptionP, static void -readFaxRow(struct bitStream * const bitStreamP, +readFaxRow(struct BitStream * const bitStreamP, unsigned char * const packedBitrow, unsigned int * const lineLengthP, const char ** const exceptionP, @@ -477,6 +503,8 @@ readFaxRow(struct bitStream * const bitStreamP, /* Number of bits we've read so far for the code we're currently reading */ + unsigned int fillbits; + /* Number of consecutive 0 bits. Can precede EOL codes */ unsigned int curcode; /* What we've assembled so far of the code we're currently reading */ unsigned int count; @@ -490,6 +518,7 @@ readFaxRow(struct bitStream * const bitStreamP, col = 0; curlen = 0; curcode = 0; + fillbits = 0; currentColor = PBM_WHITE; count = 0; *exceptionP = NULL; @@ -521,12 +550,17 @@ readFaxRow(struct bitStream * const bitStreamP, else { curcode = (curcode << 1) | bit; ++curlen; - - if (curlen > 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 = + const G3TableEntry * const teP = g3code(curcode, curlen, currentColor); /* Address of structure that describes the current G3 code. Null means 'curcode' isn't @@ -680,7 +714,7 @@ analyzeLineSize(lineSizeAnalyzer * const analyzerP, */ static void -readFax(struct bitStream * const bitStreamP, +readFax(struct BitStream * const bitStreamP, bool const stretch, unsigned int const expectedLineSize, bool const tolerateErrors, @@ -747,16 +781,16 @@ readFax(struct bitStream * const bitStreamP, int -main(int argc, char * argv[]) { +main(int argc, const char * argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE * ifP; - struct bitStream bitStream; + struct BitStream bitStream; unsigned int rows, cols; unsigned char ** packedBits; int row; - pbm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); diff --git a/converter/pbm/pbmtog3.c b/converter/pbm/pbmtog3.c index f0fd1252..4a731efd 100644 --- a/converter/pbm/pbmtog3.c +++ b/converter/pbm/pbmtog3.c @@ -1,84 +1,52 @@ /* pbmtog3.c - read a PBM image and produce a Group 3 FAX file -** -** Copyright (C) 1989 by Paul Haeberli <paul@manray.sgi.com>. -** -** Permission to use, copy, modify, and distribute this software and its -** documentation for any purpose and without fee is hereby granted, provided -** that the above copyright notice appear in all copies and that both that -** copyright notice and this permission notice appear in supporting -** documentation. This software is provided "as is" without express or -** implied warranty. -*/ -/* - For specifications for Group 3 (G3) fax MH coding see ITU-T T.4 - This program generates only MH. It is coded with future expansion for - MR and MMR in mind. + For specifications for Group 3 (G3) fax MH coding see ITU-T T.4: + Standardization of Group 3 facsimile terminals for document transmission + https://www.itu.int/rec/T-REC-T.4/en + + This program generates only MH. */ + #include <assert.h> #include "pm_c_util.h" #include "shhopt.h" #include "mallocvar.h" #include "bitreverse.h" -#include "wordaccess.h" -#include "wordintclz.h" +#include "intcode.h" #include "g3.h" #include "pbm.h" -#define TC_MC 64 - -static bool const pbmtorl = -#ifdef PBMTORL - TRUE; -#else - FALSE; -#endif - +enum G3eol {EOL, ALIGN8, ALIGN16, NO_EOL, NO_RTC, NO_EOLRTC}; -struct bitString { - /* A string of bits, up to as many fit in a word. */ - unsigned int bitCount; - /* The length of the bit string */ - wordint intBuffer; - /* The bits are in the 'bitCount' least significant bit positions - of this number. The rest of the bits of this number are always - zero. - */ +struct OutStream; - /* Example: The bit string 010100, on a machine with a 32 bit word, - would be represented by bitCount = 6, intBuffer = 20 - (N.B. 20 = 00000000 00000000 00000000 00010100 in binary) - */ +struct OutStream { + FILE * fp; + struct BitString buffer; + bool reverseBits; /* Reverse bit order */ + enum G3eol eolAlign; /* Omit EOL and/or RTC; align EOL to 8/16 bits */ + void * data; /* Reserved for future expansion */ }; -struct outStream { - struct bitString buffer; - - bool reverseBits; -}; - -/* This is a global variable for speed. */ -static struct outStream out; - - struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ const char * inputFileName; unsigned int reversebits; - unsigned int nofixedwidth; + enum G3eol align; + unsigned int desiredWidth; unsigned int verbose; }; static void -parseCommandLine(int argc, char ** const argv, +parseCommandLine(int argc, const char ** const argv, struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that @@ -87,6 +55,8 @@ parseCommandLine(int argc, char ** const argv, optEntry * option_def; /* Instructions to OptParseOptions2 on how to parse our options. */ optStruct3 opt; + unsigned int nofixedwidth; + unsigned int align8, align16; unsigned int option_def_index; @@ -95,7 +65,11 @@ parseCommandLine(int argc, char ** const argv, option_def_index = 0; /* incremented by OPTENTRY */ OPTENT3(0, "reversebits", OPT_FLAG, NULL, &cmdlineP->reversebits, 0); - OPTENT3(0, "nofixedwidth", OPT_FLAG, NULL, &cmdlineP->nofixedwidth, + OPTENT3(0, "nofixedwidth", OPT_FLAG, NULL, &nofixedwidth, + 0); + OPTENT3(0, "align8", OPT_FLAG, NULL, &align8, + 0); + OPTENT3(0, "align16", OPT_FLAG, NULL, &align16, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); @@ -105,14 +79,29 @@ parseCommandLine(int argc, char ** const argv, */ opt.opt_table = option_def; - opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ - opt.allowNegNum = TRUE; /* We may have parms that are negative numbers */ + opt.short_allowed = false; /* We have no short (old-fashioned) options */ + opt.allowNegNum = true; /* We may have parms that are negative numbers */ - pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ free(option_def); + if (align8) { + if (align16) + pm_error("You can't specify both -align8 and -align16"); + else + cmdlineP->align = ALIGN8; + } else if (align16) + cmdlineP->align = ALIGN16; + else + cmdlineP->align = EOL; + + if (nofixedwidth) + cmdlineP->desiredWidth = 0; + else + cmdlineP->desiredWidth = 1728; + if (argc-1 == 0) cmdlineP->inputFileName = "-"; else if (argc-1 != 1) @@ -129,27 +118,75 @@ reversebuffer(unsigned char * const p, unsigned int const n) { unsigned int i; + for (i = 0; i < n; ++i) p[i] = bitreverse[p[i]]; } -static struct bitString -makeBs(wordint const bits, - unsigned int const bitCount) { +static void +flushBuffer(struct OutStream * const outP) { +/*---------------------------------------------------------------------------- + Flush the contents of the bit buffer +-----------------------------------------------------------------------------*/ + struct BitString const buffer = outP->buffer; - struct bitString retval; - retval.intBuffer = bits; - retval.bitCount = bitCount; + assert (buffer.bitCount <= 32); - return retval; + if (buffer.bitCount > 0) { + unsigned int const fullBuffer = sizeof(buffer.intBuffer) * 8; + unsigned int const bytesToWrite = (buffer.bitCount+7)/8; + bigend32 outbytes; + size_t rc; + + outbytes = pm_bigendFromUint32( + buffer.intBuffer << (fullBuffer - buffer.bitCount)); + if (outP->reverseBits) + reversebuffer((unsigned char *)&outbytes, bytesToWrite); + rc = fwrite((unsigned char *)&outbytes, 1, bytesToWrite, outP->fp); + if (rc != bytesToWrite) + pm_error("Output error"); + } } +#if 1==0 +static void +putbitsDump(struct OutStream * const outP, + struct BitString const newBits) { +/*---------------------------------------------------------------------------- + Print the content of the bit put request, in human readable text form + For debugging. Also good for studying how the coding scheme works. + + By default the compiler ignores this function. + To turn on, remove the "#if" - "#endif" lines enclosing the function and + edit the output function name in putbits(). +-----------------------------------------------------------------------------*/ + unsigned int const bitCount = newBits.bitCount; + + unsigned int i; + char charBuff[128]; + + assert (bitCount >= 0 && bitCount < 32); + assert (sizeof(newBits.intBuffer) + 2 < 128); + + for (i = 0; i < bitCount; ++i) { + unsigned int const n = bitCount - i - 1; + charBuff[i] = ((newBits.intBuffer >> n) & 0x01) + '0'; + } + + charBuff[bitCount] = '\n'; + charBuff[bitCount+1] = '\0'; + fwrite(charBuff, 1, bitCount+1, outP->fp); +} +#endif + + -static __inline__ void -putbits(struct bitString const newBits) { +static void +putbitsBinary(struct OutStream * const outP, + struct BitString const newBits) { /*---------------------------------------------------------------------------- Push the bits 'newBits' onto the right end of output buffer out.buffer (moving the bits already in the buffer left). @@ -158,334 +195,462 @@ putbits(struct bitString const newBits) { 'newBits' must be shorter than a whole word. - N.B. the definition of struct bitString requires upper bits to be zero. + N.B. the definition of struct BitString requires upper bits to be zero. -----------------------------------------------------------------------------*/ - unsigned int const spaceLeft = - sizeof(out.buffer.intBuffer)*8 - out.buffer.bitCount; + unsigned int const fullBuffer = sizeof(outP->buffer.intBuffer) * 8; + unsigned int const spaceLeft = fullBuffer - outP->buffer.bitCount; /* Number of bits of unused space (at the high end) in buffer */ - assert(newBits.bitCount < sizeof(out.buffer.intBuffer) * 8); + assert(newBits.bitCount < fullBuffer); assert(newBits.intBuffer >> newBits.bitCount == 0); if (spaceLeft > newBits.bitCount) { /* New bits fit with bits to spare */ - out.buffer.intBuffer = - out.buffer.intBuffer << newBits.bitCount | newBits.intBuffer; - out.buffer.bitCount += newBits.bitCount; + outP->buffer.intBuffer = + outP->buffer.intBuffer << newBits.bitCount | newBits.intBuffer; + outP->buffer.bitCount += newBits.bitCount; } else { /* New bits fill buffer. We'll have to flush the buffer to stdout and put the rest of the bits in the new buffer. */ unsigned int const nextBufBitCount = newBits.bitCount - spaceLeft; + unsigned int const bitMask = ((1<<nextBufBitCount) - 1); - wordintBytes outbytes; - size_t rc; - - wordintToBytes(&outbytes, - (out.buffer.intBuffer << spaceLeft) - | (newBits.intBuffer >> nextBufBitCount)); - if (out.reverseBits) - reversebuffer(outbytes, sizeof(outbytes)); - - rc = fwrite(outbytes, 1, sizeof(outbytes), stdout); - if (rc != sizeof(outbytes)) - pm_error("Output error. Unable to fwrite() to stdout"); + outP->buffer.intBuffer = ( (outP->buffer.intBuffer << spaceLeft) + | (newBits.intBuffer >> nextBufBitCount)); + outP->buffer.bitCount = fullBuffer; + flushBuffer(outP); - out.buffer.intBuffer = newBits.intBuffer & ((1<<nextBufBitCount) - 1); - out.buffer.bitCount = nextBufBitCount; + outP->buffer.intBuffer = newBits.intBuffer & bitMask; + outP->buffer.bitCount = nextBufBitCount; } } static void -initOutStream(bool const reverseBits) { - out.buffer.intBuffer = 0; - out.buffer.bitCount = 0; - out.reverseBits = reverseBits; +initOutStream(struct OutStream * const outP, + bool const reverseBits, + enum G3eol const eolAlign) { + + outP->buffer.intBuffer = 0; + outP->buffer.bitCount = 0; + outP->reverseBits = reverseBits; + outP->fp = stdout; + outP->eolAlign = eolAlign; +} + + + +static struct BitString +tableEntryToBitString(G3TableEntry const tableEntry) { + + struct BitString retval; + + retval.intBuffer = tableEntry.code; + retval.bitCount = tableEntry.length; + + return retval; +} + + + +static void +putbits(struct OutStream * const outP, + struct BitString const newBits) { + + putbitsBinary(outP, newBits); + /* Change to putbitsDump() for human readable output */ } -static __inline__ void -putcode(unsigned int const clr, - unsigned int const ix) { +static void +putcodeShort(struct OutStream * const outP, + bit const color, + unsigned int const runLength) { /* Note that this requires ttable to be aligned white entry, black - entry, white, black, etc. + entry, white, black, etc. */ - putbits(makeBs(ttable[ix * 2 + clr].code, ttable[ix * 2 + clr].length)); + unsigned int index = runLength * 2 + color; + putbits(outP, tableEntryToBitString(ttable[index])); } -static __inline__ void -putcode2(int const clr, - int const ix) { +static void +putcodeLong(struct OutStream * const outP, + bit const color, + unsigned int const runLength) { /*---------------------------------------------------------------------------- Output Make-up code and Terminating code at once. - For run lengths above TC_MC threshold (usually 64). + For run lengths which require both: length 64 and above The codes are combined here to avoid calculations in putbits() - wordint is usually wide enough, with 32 or 64 bits. - Provisions are made for 16 bit wordint (for debugging). Terminating code is max 12 bits, Make-up code is max 13 bits. - (See ttable, mtable entries in pbmtog3.h) + (See ttable, mtable entries in pbmtog3.h) Also reduces object code size when putcode is compiled inline. -----------------------------------------------------------------------------*/ - unsigned int const loIndex = ix % 64 * 2 + clr; - unsigned int const hiIndex = ix / 64 * 2 + clr; - - if (sizeof(wordint) * 8 > 24) { - unsigned int const l1 = ttable[loIndex].length; - - putbits( - makeBs(mtable[hiIndex].code << l1 | ttable[loIndex].code, - mtable[hiIndex].length + l1) - ); - } else { /* typically 16 bit wordint used for debugging */ - putbits(makeBs(mtable[hiIndex].code, mtable[hiIndex].length)); - putbits(makeBs(ttable[loIndex].code, ttable[loIndex].length)); - } + unsigned int const loIndex = runLength % 64 * 2 + color; + unsigned int const hiIndex = runLength / 64 * 2 + color; + unsigned int const loLength = ttable[loIndex].length; + unsigned int const hiLength = mtable[hiIndex].length; + + struct BitString combinedCode; + + combinedCode.intBuffer = mtable[hiIndex].code << loLength | + ttable[loIndex].code; + combinedCode.bitCount = hiLength + loLength; + + putbits(outP, combinedCode); } -static __inline__ void -putspan_normal(bit const color, - unsigned int const len) { +static void +putcodeExtra(struct OutStream * const outP, + int const color, + int const runLength) { +/*---------------------------------------------------------------------------- + Lengths over 2560. This is rare. + According to the standard, the mark-up code for 2560 can be issued as + many times as necessary without terminal codes. + --------------------------------------------------------------------------*/ + G3TableEntry const markUp2560 = mtable[2560/64*2]; + /* Same code for black and white */ - if (len < TC_MC) - putcode(color, len); - else if (len < 2624) - putcode2(color, len); - else { /* len >= 2624 : rare */ - unsigned int remainingLen; + unsigned int remainingLen; - for (remainingLen = len; - remainingLen >= 2624; - remainingLen -= 2623) { + for (remainingLen = runLength; remainingLen > 2560; remainingLen -= 2560) + putbits(outP, tableEntryToBitString(markUp2560)); + /* after the above: 0 < remainingLen <= 2560 */ - putcode2(color, 2560+63); - putcode(!color, 0); - } - if (remainingLen < TC_MC) - putcode(color, remainingLen); - else /* TC_MC <= len < 2624 */ - putcode2(color, remainingLen); - } + if (remainingLen >= 64) + putcodeLong(outP, color, remainingLen); + else + putcodeShort(outP, color, remainingLen); } -static __inline__ void -putspan(bit const color, - unsigned int const len) { -/*---------------------------------------------------------------------------- - Put a span of 'len' pixels of color 'color' in the output. ------------------------------------------------------------------------------*/ - if (pbmtorl) { - if (len > 0) - printf("%c %d\n", color == PBM_WHITE ? 'W' : 'B', len); - } else - putspan_normal(color, len); +static void +putspan(struct OutStream * const outP, + bit const color, + unsigned int const runLength) { + + if (runLength < 64) + putcodeShort(outP, color, runLength); + else if (runLength < 2560) + putcodeLong (outP, color, runLength); + else /* runLength > 2560 : rare */ + putcodeExtra(outP, color, runLength); } static void -puteol(void) { +puteol(struct OutStream * const outP) { + + switch (outP->eolAlign) { + case EOL: { + struct BitString const eol = { 1, 12 }; + + putbits(outP, eol); + } break; + case ALIGN8: case ALIGN16: { + unsigned int const bitCount = outP->buffer.bitCount; + unsigned int const fillbits = + (outP->eolAlign == ALIGN8) ? (44 - bitCount) % 8 + : (52 - bitCount) % 16; + + struct BitString eol; + + eol.bitCount = 12 + fillbits; eol.intBuffer = 1; + putbits(outP, eol); + } break; + case NO_EOL: case NO_EOLRTC: + break; + case NO_RTC: + pm_error("INTERNAL ERROR: no-RTC EOL treatment not implemented"); + break; + } +} + - if (pbmtorl) - puts("EOL"); - else { - struct bitString const eol = {12, 1}; - putbits(eol); +static void +putrtc(struct OutStream * const outP) { + + switch (outP->eolAlign) { + case NO_RTC: case NO_EOLRTC: + break; + default: + puteol(outP); puteol(outP); puteol(outP); + puteol(outP); puteol(outP); puteol(outP); } } -/* - PBM raw bitrow to inflection point array +static void +readOffSideMargins(unsigned char * const bitrow, + unsigned int const colChars, + unsigned int * const firstNonWhiteCharP, + unsigned int * const lastNonWhiteCharP, + bool * const blankRowP) { +/*---------------------------------------------------------------------------- + Determine the white margins on the left and right side of a row. + This is an enhancement: convertRowToG3() works without this. +-----------------------------------------------------------------------------*/ + unsigned int charCnt; + unsigned int firstChar; + unsigned int lastChar; + bool blankRow; - Write inflection (=color change) points into array milepost[]. - It is easy to calculate run length from this. + assert(colChars > 0); - In milepost, a white-to-black (black-to-white) inflection point - always has an even (odd) index. A line starting with black is - indicated by bitrow[0] == 0. + for (charCnt = 0; charCnt < colChars && bitrow[charCnt] == 0; ++charCnt); - WWWWWWWBBWWWWWWW ... = 7,2,7, ... - BBBBBWBBBBBWBBBB ... = 0,5,1,5,1,4, ... + if (charCnt >= colChars) { + /* Reached end of bitrow with no black pixels encountered */ + firstChar = lastChar = 0; + blankRow = true; + } else { + /* There is at least one black pixel in the row */ + firstChar = charCnt; + blankRow = false; - Return the number of milepost elements written. - Note that max number of entries into milepost = cols+1 . + charCnt = colChars - 1; - The inflection points are calculated like this: + while (bitrow[charCnt--] == 0x00) + ; + lastChar = charCnt + 1; + } + + *firstNonWhiteCharP = firstChar; + *lastNonWhiteCharP = lastChar; + *blankRowP = blankRow; +} - r1: 00000000000111111110011111000000 - r2: c0000000000011111111001111100000 0->carry - xor: ?0000000000100000001010000100000 - The 1 bits in the xor above are the inflection points. -*/ -static __inline__ void -convertRowToRunLengths(unsigned char * const bitrow, - int const cols, - unsigned int * const milepost, - unsigned int * const lengthP) { - - unsigned int const bitsPerWord = sizeof(wordint) * 8; - wordint * const bitrowByWord = (wordint *) bitrow; - int const wordCount = (cols + bitsPerWord - 1)/bitsPerWord; - /* Number of full and partial words in the row */ - - - if (cols % bitsPerWord != 0) { - /* Clean final word in row. For loop simplicity */ - wordint r1; - r1 = bytesToWordint((unsigned char *)&bitrowByWord[wordCount - 1]); - r1 >>= bitsPerWord - cols % bitsPerWord; - r1 <<= bitsPerWord - cols % bitsPerWord; - wordintToBytes((wordintBytes *)&bitrowByWord[wordCount - 1], r1); +static void +setBlockBitsInFinalChar(unsigned char * const finalByteP, + unsigned int const cols) { +/*---------------------------------------------------------------------------- + If the char in the row is fractional, set it up so that the don't care + bits are the opposite color of the last valid pixel. +----------------------------------------------------------------------------*/ + unsigned char const finalByte = *finalByteP; + unsigned int const silentBitCnt = 8 - cols % 8; + bit const rowEndColor = (finalByte >> silentBitCnt) & 0x01; + + if (rowEndColor == PBM_WHITE) { + unsigned char const blackMask = (0x01 << silentBitCnt) - 1; + + *finalByteP = finalByte | blackMask; } - { - - wordint carry; - wordint r1, r2; - unsigned int n; - int i,c,k; - - for (i = carry = n = 0; i < wordCount; ++i) { - r1 = r2 = bytesToWordint((unsigned char *)&bitrowByWord[i]); - r2 = r1 ^ (carry << (bitsPerWord-1) | r2 >> 1); - carry = r1 & 0x1; k = 0; - while (r2 != 0) { - /* wordintClz(r2) reports most significant "1" bit of r2 - counting from MSB = position 0. - */ - c = wordintClz(r2); - milepost[n++] = i * bitsPerWord + k + c; - r2 <<= c++; r2 <<= 1; k += c; - } + /* No adjustment required if the row ends with a black pixel. + pbm_cleanrowend_packed() takes care of this. + */ +} + + + +static void +trimFinalChar(struct OutStream * const outP, + bit const color, + int const carryLength, + int const existingCols, + int const desiredWidth) { +/*--------------------------------------------------------------------------- + If the carry value from the last char in the row represents a valid + sequence, output it. + + (1) If input row width is not a whole multiple of 8 and -nofixwidth + was specified, the final carry value represents inactive bits + at the row end. Emit no code. See setBlockBitsInFinalChar(). + + (2) If there is white margin on the right side, the final carry value + is valid. We add to it the margin width. Right-side margin may + be added in main() to a narrow input image, detected in the + input row by readOffSideMargins() or both. The same treatment + applies regardless of the nature of the right-side margin. +----------------------------------------------------------------------------*/ + if (existingCols == desiredWidth) { + if (existingCols % 8 == 0) + putspan(outP, color, carryLength); /* Code up to byte boundary */ + /* Emit nothing if existingCols is not a whole multiple of 8 */ + } else if (existingCols < desiredWidth) { + if (color == 0) { /* Last bit sequence in final char: white */ + unsigned int const totalLength = + carryLength + (desiredWidth - existingCols); + putspan(outP, 0, totalLength); + } else { /* Black */ + unsigned int const padLength = desiredWidth - existingCols; + putspan(outP, 1, carryLength); + putspan(outP, 0, padLength); } - if (n == 0 || milepost[n - 1] != cols) - milepost[n++] = cols; - *lengthP = n; } } static void -padToDesiredWidth(unsigned int * const milepost, - unsigned int * const nRunP, - int const existingCols, - int const desiredCols) { - - if (existingCols < desiredCols) { - /* adjustment for narrow input in fixed width mode - nRun % 2 == 1 (0) means last (=rightmost) pixel is white (black) - if white, extend the last span to outwidth - if black, fill with a white span len (outwidth - readcols) - */ - if (*nRunP % 2 == 0) - ++*nRunP; - milepost[*nRunP - 1] = desiredCols; +convertRowToG3(struct OutStream * const outP, + unsigned char * const bitrow, + unsigned int const existingCols, + unsigned int const desiredWidth) { +/*---------------------------------------------------------------------------- + Table based Huffman coding + + Normally Huffman code encoders count sequences of ones and zeros + and convert them to binary codes as they terminate. This program + recognizes chains of pixels and converts them directly, reading + prefabricated code chains from an indexed table. + + For example the 8-bit sequence 01100110 translates to + Huffman code: 000111 11 0111 11 000111. + + In reality things are more complicated. The leftmost 0 (MSB) may be + part of a longer sequence starting in the adjacent byte or perhaps + spanning several bytes. Likewise for the rightmost 0. + + So we first remove the sequence on the left side and compare its + color with the leftmost pixel of the adjacent byte and emit either + one code for a single sequence if they agree or two if they disagree. + Next the composite code for the central part (in the above example + 110011 -> 11 0111 11) is emitted. Finally we save the length and + color of the sequence on the right end as carry-over for the next + byte cycle. Some 8-bit input sequences (00000000, 01111111, + 00111111, etc.) have no central part: these are special cases. +---------------------------------------------------------------------------*/ + unsigned int const colChars = pbm_packed_bytes(existingCols); + + unsigned int charCnt; + unsigned int firstActiveChar; + unsigned int lastActiveChar; + bool blankRow; + bit borderColor; + + borderColor = PBM_WHITE; /* initial value */ + + if (existingCols == desiredWidth && (desiredWidth % 8) > 0) + setBlockBitsInFinalChar(&bitrow[colChars-1], desiredWidth); + + readOffSideMargins(bitrow, colChars, + &firstActiveChar, &lastActiveChar, &blankRow); + + if (blankRow) + putspan(outP, PBM_WHITE, desiredWidth); + else { + unsigned int carryLength; + + for (charCnt = firstActiveChar, carryLength = firstActiveChar * 8; + charCnt <=lastActiveChar; + ++charCnt) { + + unsigned char const byte = bitrow[charCnt]; + bit const rColor = !borderColor; + + if (byte == borderColor * 0xFF) { + carryLength += 8; + } else if (byte == (unsigned char) ~(borderColor * 0xFF)) { + putspan(outP, borderColor, carryLength); + carryLength = 8; + borderColor = rColor; + } else { + struct PrefabCode const code = prefabCode[byte]; + unsigned int const activeLength = + 8 - code.leadBits - code.trailBits; + + if (borderColor == (byte >> 7)) { + putspan(outP, borderColor, carryLength + code.leadBits); + } else { + putspan(outP, borderColor, carryLength); + putcodeShort(outP, rColor, code.leadBits); + } + if (activeLength > 0) + putbits(outP, code.activeBits); + + borderColor = byte & 0x01; + carryLength = code.trailBits; + } + } + trimFinalChar(outP, borderColor, carryLength, + (lastActiveChar + 1) * 8, desiredWidth); } + puteol(outP); } int -main(int argc, - char * argv[]) { +main(int argc, + const char * argv[]) { struct CmdlineInfo cmdline; FILE * ifP; unsigned char * bitrow; /* This is the bits of the current row, as read from the input and - modified various ways at various points in the program. It has - a word of zero padding on the high (right) end for the convenience - of code that accesses this buffer in word-size bites. + modified various ways at various points in the program. It has + a word of zero padding on the high (right) end for the convenience + of code that accesses this buffer in word-size bites. */ int rows; int cols; - int readcols; - int outwidth; int format; - int row; - unsigned int * milepost; + unsigned int existingCols; + unsigned int desiredWidth; + unsigned int row; + struct OutStream out; - pbm_init(&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFileName); pbm_readpbminit(ifP, &cols, &rows, &format); - if (cmdline.nofixedwidth) - readcols = outwidth = cols; + + if (cmdline.desiredWidth == 0) + desiredWidth = existingCols = cols; else { - readcols = MIN(cols, 1728); - outwidth = 1728; + if (cmdline.desiredWidth < cols) + existingCols = desiredWidth = cmdline.desiredWidth; + else { + existingCols = pbm_packed_bytes(cols) * 8; + desiredWidth = cmdline.desiredWidth; + } } - MALLOCARRAY_NOFAIL(bitrow, pbm_packed_bytes(cols) + sizeof(wordint)); + MALLOCARRAY(bitrow, pbm_packed_bytes(cols) + sizeof(uint32_t)); - MALLOCARRAY_NOFAIL(milepost, readcols + 2); + if (!bitrow) + pm_error("Failed to allocate a row buffer for %u columns", cols); - initOutStream(cmdline.reversebits); - puteol(); + initOutStream(&out, cmdline.reversebits, cmdline.align); + + puteol(&out); for (row = 0; row < rows; ++row) { - unsigned int nRun; /* Number of runs in milepost[] */ - unsigned int p; - unsigned int i; - pbm_readpbmrow_packed(ifP, bitrow, cols, format); - - convertRowToRunLengths(bitrow, readcols, milepost, &nRun); - - padToDesiredWidth(milepost, &nRun, readcols, outwidth); - - for (i = p = 0; i < nRun; p = milepost[i++]) - putspan(i%2 == 0 ? PBM_WHITE : PBM_BLACK, milepost[i] - p); - /* TODO 2-dimensional coding MR, MMR */ - puteol(); + pbm_cleanrowend_packed(bitrow, cols); + convertRowToG3(&out, bitrow, existingCols, desiredWidth); } - free(milepost); pbm_freerow_packed(bitrow); - - { - unsigned int i; - for( i = 0; i < 6; ++i) - puteol(); - } - if (out.buffer.bitCount > 0) { - /* flush final partial buffer */ - unsigned int const bytesToWrite = (out.buffer.bitCount+7)/8; - - unsigned char outbytes[sizeof(wordint)]; - size_t rc; - wordintToBytes(&outbytes, - out.buffer.intBuffer << (sizeof(out.buffer.intBuffer)*8 - - out.buffer.bitCount)); - if (out.reverseBits) - reversebuffer(outbytes, bytesToWrite); - rc = fwrite(outbytes, 1, bytesToWrite, stdout); - if (rc != bytesToWrite) - pm_error("Output error"); - } + putrtc(&out); + flushBuffer(&out); pm_close(ifP); return 0; } + + + diff --git a/converter/pbm/pbmtox10bm b/converter/pbm/pbmtox10bm index 6e1a12a2..deb3aeab 100644 --- a/converter/pbm/pbmtox10bm +++ b/converter/pbm/pbmtox10bm @@ -1,3 +1,27 @@ +#!/bin/sh + +############################################################################## +# This is essentially a Perl program. We exec the Perl interpreter specifying +# this same file as the Perl program and use the -x option to cause the Perl +# interpreter to skip down to the Perl code. The reason we do this instead of +# just making /usr/bin/perl the script interpreter (instead of /bin/sh) is +# that the user may have multiple Perl interpreters and the one he wants to +# use is properly located in the PATH. The user's choice of Perl interpreter +# may be crucial, such as when the user also has a PERL5LIB environment +# variable and it selects modules that work with only a certain main +# interpreter program. +# +# An alternative some people use is to have /usr/bin/env as the script +# interpreter. We don't do that because we think the existence and +# compatibility of /bin/sh is more reliable. +# +# Note that we aren't concerned about efficiency because the user who needs +# high efficiency can use directly the programs that this program invokes. +# +############################################################################## + +exec perl -w -x -S -- "$0" "$@" + #! /usr/bin/perl #============================================================================ diff --git a/converter/ppm/ppmtoarbtxt.c b/converter/ppm/ppmtoarbtxt.c index fc8927ce..6d4ed04e 100644 --- a/converter/ppm/ppmtoarbtxt.c +++ b/converter/ppm/ppmtoarbtxt.c @@ -734,15 +734,20 @@ interpretObjType(const char * const typstr) { static SkeletonObject * -newIcSkelFromReplString(const char * const objstr, +newIcSkelFromReplString(const char * const icolorObjstr, SkeletonObjectType const objType) { - +/*---------------------------------------------------------------------------- + A new skeleton for an integer color substitution specifier (class + OBJTYP_ICOLOR) whose replacement string (the stuff between the parentheses + in #(...)) says substitution type 'objType' and the rest of the + replacement string is 'icolorObjstr'. +-----------------------------------------------------------------------------*/ SkeletonObject * retval; unsigned int icolmin, icolmax; char formstr[MAX_OBJ_BUF]; - unsigned int nOdata; + int nOdata; - nOdata = sscanf(objstr, "%*s%s%u%u", formstr, &icolmin, &icolmax); + nOdata = sscanf(icolorObjstr, "%s%u%u", formstr, &icolmin, &icolmax); if (nOdata == 3) retval = newIcolDataObj(objType, formstr, icolmin, icolmax); @@ -758,16 +763,20 @@ newIcSkelFromReplString(const char * const objstr, static SkeletonObject * -newFcSkelFromReplString(const char * const objstr, +newFcSkelFromReplString(const char * const fcolorObjstr, SkeletonObjectType const objType) { - +/*---------------------------------------------------------------------------- + A new skeleton for a floating point color substitution specifier (class + OBJTYP_FCOLOR) whose replacement string (the stuff between the parentheses + in #(...)) says substitution type 'objType' and the rest of the + replacement string is 'fcolorObjstr'. +-----------------------------------------------------------------------------*/ SkeletonObject * retval; double fcolmin, fcolmax; char formstr[MAX_OBJ_BUF]; - unsigned int nOdata; + int nOdata; - nOdata = sscanf(objstr, "%*s%s%lf%lf", formstr, - &fcolmin, &fcolmax); + nOdata = sscanf(fcolorObjstr, "%s%lf%lf", formstr, &fcolmin, &fcolmax); if (nOdata == 3) retval = newFcolDataObj(objType, formstr, fcolmin, fcolmax); @@ -783,12 +792,19 @@ newFcSkelFromReplString(const char * const objstr, static SkeletonObject * -newISkelFromReplString(const char * const objstr, +newISkelFromReplString(const char * const intObjstr, SkeletonObjectType const objType) { - +/*---------------------------------------------------------------------------- + A new skeleton for an integer substitution specifier (class OBJTYP_INT) + whose replacement string (the stuff between the parentheses in #(...)) + says substitution type 'objType' and the rest of the replacement string is + 'intObjstr'. +-----------------------------------------------------------------------------*/ SkeletonObject * retval; char formstr[MAX_OBJ_BUF]; - unsigned int const nOdata = sscanf(objstr, "%*s%s", formstr); + int nOdata; + + nOdata = sscanf(intObjstr, "%s", formstr); if (nOdata == 1) retval = newIdataObj(objType, formstr); @@ -806,7 +822,7 @@ newISkelFromReplString(const char * const objstr, static SkeletonObject * newSkeletonFromReplString(const char * const objstr) { /*---------------------------------------------------------------------------- - Create a skeleton from the replacement string 'objstr' (the stuff + A new skeleton created from the replacement string 'objstr' (the stuff between the parentheses in #(...) ). Return NULL if it isn't a valid replacement string. @@ -821,6 +837,7 @@ newSkeletonFromReplString(const char * const objstr) { SkeletonObject * retval; char typstr[MAX_OBJ_BUF]; + int typlen; SkeletonObjectType objType; int conversionCt; char s1[MAX_OBJ_BUF]; /* Dry read. */ @@ -829,7 +846,8 @@ newSkeletonFromReplString(const char * const objstr) { typstr[0] = '\0'; /* initial value */ - conversionCt = sscanf(objstr, "%s%s%f%f%s", typstr, s1, &f1, &f2, s2); + conversionCt = sscanf(objstr, "%s%n%s%f%f%s", + typstr, &typlen, s1, &f1, &f2, s2); switch (conversionCt) { case 1: case 2: case 4: objType = interpretObjType(typstr); @@ -840,13 +858,13 @@ newSkeletonFromReplString(const char * const objstr) { switch (objClass(objType)) { case OBJTYP_ICOLOR: - retval = newIcSkelFromReplString(objstr, objType); + retval = newIcSkelFromReplString(&objstr[typlen], objType); break; case OBJTYP_FCOLOR: - retval = newFcSkelFromReplString(objstr, objType); + retval = newFcSkelFromReplString(&objstr[typlen], objType); break; case OBJTYP_INT: - retval = newISkelFromReplString(objstr, objType); + retval = newISkelFromReplString(&objstr[typlen], objType); break; case OBJTYP_BDATA: retval = NULL; diff --git a/converter/ppm/ppmtompeg/jrevdct.c b/converter/ppm/ppmtompeg/jrevdct.c index bf9196c4..dd1f9fff 100644 --- a/converter/ppm/ppmtompeg/jrevdct.c +++ b/converter/ppm/ppmtompeg/jrevdct.c @@ -26,7 +26,11 @@ * matrix, perhaps with the difference cases encoded. */ +#define _XOPEN_SOURCE 500 /* get M_PI in math.h */ + #include <memory.h> +#include <math.h> + #include "all.h" #include "dct.h" @@ -1211,35 +1215,29 @@ mpeg_jrevdct_quick(data) */ -/* Here we use math.h to generate constants. Compiler results may - vary a little */ - -#ifndef PI -#ifdef M_PI -#define PI M_PI -#else -#define PI 3.14159265358979323846 -#endif -#endif - /* cosine transform matrix for 8x1 IDCT */ static double itrans_coef[8][8]; -/* initialize DCT coefficient matrix */ -void init_idctref() -{ - int freq, time; - double scale; - - for (freq=0; freq < 8; freq++) - { - scale = (freq == 0) ? sqrt(0.125) : 0.5; - for (time=0; time<8; time++) - itrans_coef[freq][time] = scale*cos((PI/8.0)*freq*(time + 0.5)); - } + +void init_idctref() { +/*---------------------------------------------------------------------------- + initialize DCT coefficient matrix +-----------------------------------------------------------------------------*/ + unsigned int freq; + + for (freq=0; freq < 8; ++freq) { + double const scale = (freq == 0) ? sqrt(0.125) : 0.5; + + unsigned int time; + + for (time = 0; time < 8; ++time) + itrans_coef[freq][time] = scale*cos((M_PI/8.0)*freq*(time + 0.5)); + } } + + /* perform IDCT matrix multiply for 8x8 coefficient block */ void reference_rev_dct(block) diff --git a/converter/ppm/ppmtompeg/mfwddct.c b/converter/ppm/ppmtompeg/mfwddct.c index 75c3a718..9381e51c 100644 --- a/converter/ppm/ppmtompeg/mfwddct.c +++ b/converter/ppm/ppmtompeg/mfwddct.c @@ -15,6 +15,10 @@ * instead of floating point. */ +#define _XOPEN_SOURCE 500 /* get M_PI in math.h */ + +#include <math.h> + #include "all.h" #include "dct.h" @@ -375,26 +379,19 @@ mp_fwd_dct_block2(data, dest) * */ -#ifndef PI -#ifdef M_PI -#define PI M_PI -#else -#define PI 3.14159265358979323846 -#endif -#endif -void init_fdct() -{ - int i, j; - double s; +void init_fdct() { - for (i=0; i<8; i++) - { - s = (i==0) ? sqrt(0.125) : 0.5; + unsigned int i; - for (j=0; j<8; j++) - trans_coef[i][j] = s * cos((PI/8.0)*i*(j+0.5)); - } + for (i = 0; i < 8; ++i) { + double const s = i == 0 ? sqrt(0.125) : 0.5; + + unsigned int j; + + for (j = 0; j < 8; ++j) + trans_coef[i][j] = s * cos((M_PI/8.0) * i * (j+0.5)); + } } |