From ebd5d47022a0bd4539719348c150602d958d4e00 Mon Sep 17 00:00:00 2001 From: giraffedata Date: Tue, 1 Nov 2022 22:39:01 +0000 Subject: Add -size, cleanup git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@4449 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- .../other/jpeg2000/libjasper/base/jas_image.c | 33 ++-- converter/other/jpeg2000/libjasper/jpc/jpc_enc.c | 187 ++++++++++----------- converter/other/jpeg2000/libjasper/jpc/jpc_util.c | 71 +++++--- converter/other/jpeg2000/pamtojpeg2k.c | 11 +- 4 files changed, 165 insertions(+), 137 deletions(-) (limited to 'converter') diff --git a/converter/other/jpeg2000/libjasper/base/jas_image.c b/converter/other/jpeg2000/libjasper/base/jas_image.c index 5ee13a0d..c6f984c1 100644 --- a/converter/other/jpeg2000/libjasper/base/jas_image.c +++ b/converter/other/jpeg2000/libjasper/base/jas_image.c @@ -675,7 +675,7 @@ int jas_image_fmtfromname(char *name) return -1; } ++ext; - /* Try to find a format that uses this extension. */ + /* Try to find a format that uses this extension. */ for (i = 0, fmtinfo = jas_image_fmtinfos; i < jas_image_numfmts; ++i, ++fmtinfo) { /* Do we have a match? */ @@ -686,25 +686,28 @@ int jas_image_fmtfromname(char *name) return -1; } -/******************************************************************************\ +/*****************************************************************************\ * Miscellaneous operations. -\******************************************************************************/ +\*****************************************************************************/ -uint_fast32_t jas_image_rawsize(jas_image_t *image) -{ - uint_fast32_t rawsize; - uint_fast32_t cmptno; - jas_image_cmpt_t *cmpt; +uint_fast32_t +jas_image_rawsize(jas_image_t * const imageP) { +/*---------------------------------------------------------------------------- + The raw size of the image, i.e. the number of bytes the raster of the image + would take if just represented simply, with no compression. +-----------------------------------------------------------------------------*/ + uint_fast32_t rawsize; + uint_fast32_t cmptno; - rawsize = 0; - for (cmptno = 0; cmptno < image->numcmpts_; ++cmptno) { - cmpt = image->cmpts_[cmptno]; - rawsize += (cmpt->width_ * cmpt->height_ * cmpt->prec_ + - 7) / 8; - } - return rawsize; + for (cmptno = 0, rawsize = 0; cmptno < imageP->numcmpts_; ++cmptno) { + jas_image_cmpt_t * const cmptP = imageP->cmpts_[cmptno]; + rawsize += (cmptP->width_ * cmptP->height_ * cmptP->prec_ + 7) / 8; + } + return rawsize; } + + void jas_image_delcmpt(jas_image_t *image, uint_fast16_t cmptno) { if (cmptno >= image->numcmpts_) { diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c index 9db41ca2..fd309188 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_enc.c @@ -69,7 +69,6 @@ static void prc_destroy(jpc_enc_prc_t *prcs); static jpc_enc_cblk_t *cblk_create(jpc_enc_cblk_t *cblk, jpc_enc_cp_t *cp, jpc_enc_prc_t *prc); static void cblk_destroy(jpc_enc_cblk_t *cblks); -int ratestrtosize(const char *s, uint_fast32_t rawsize, uint_fast32_t *size); static void pass_destroy(jpc_enc_pass_t *pass); void jpc_enc_dump(jpc_enc_t *enc); @@ -143,7 +142,6 @@ typedef enum { OPT_NUMGBITS, OPT_RATE, OPT_ILYRRATES, - OPT_JP2OVERHEAD } optid_t; jas_taginfo_t encopts[] = { @@ -173,7 +171,6 @@ jas_taginfo_t encopts[] = { {OPT_NUMGBITS, "numgbits"}, {OPT_RATE, "rate"}, {OPT_ILYRRATES, "ilyrrates"}, - {OPT_JP2OVERHEAD, "_jp2overhead"}, {-1, 0} }; @@ -292,6 +289,28 @@ error: +static void +ratestrtosize(const char * const s, + uint_fast32_t const rawsize, + uint_fast32_t * const sizeP) { + + if (strchr(s, 'B')) { + *sizeP = atoi(s); + } else { + jpc_flt_t const f = atof(s); + + if (f < 0) { + *sizeP = 0; + } else if (f > 1.0) { + *sizeP = rawsize + 1; + } else { + *sizeP = f * rawsize; + } + } +} + + + /*****************************************************************************\ * Option parsing code. \*****************************************************************************/ @@ -314,7 +333,6 @@ cp_create(char *optstr, jas_image_t *image) { uint_fast16_t prcwidthexpn; uint_fast16_t prcheightexpn; bool enablemct; - uint_fast32_t jp2overhead; uint_fast16_t lyrno; uint_fast32_t hsteplcm; uint_fast32_t vsteplcm; @@ -332,7 +350,6 @@ cp_create(char *optstr, jas_image_t *image) { prcwidthexpn = 15; prcheightexpn = 15; enablemct = true; - jp2overhead = 0; cp->ccps = 0; cp->debug = 0; @@ -380,6 +397,10 @@ cp_create(char *optstr, jas_image_t *image) { cp->rawsize = jas_image_rawsize(image); cp->totalsize = UINT_FAST32_MAX; + /* Set default value, the special value that means size is unlimited + (so lossless coding is called for). To be overridden if user + specified + */ tcp = &cp->tcp; tcp->csty = 0; @@ -492,12 +513,8 @@ cp_create(char *optstr, jas_image_t *image) { cp->tccp.numgbits = atoi(jas_tvparser_getval(tvp)); break; case OPT_RATE: - if (ratestrtosize(jas_tvparser_getval(tvp), cp->rawsize, - &cp->totalsize)) { - fprintf(stderr, - "ignoring bad rate specifier %s\n", - jas_tvparser_getval(tvp)); - } + ratestrtosize(jas_tvparser_getval(tvp), cp->rawsize, + &cp->totalsize); break; case OPT_ILYRRATES: if (jpc_atoaf(jas_tvparser_getval(tvp), &numilyrrates, @@ -505,13 +522,10 @@ cp_create(char *optstr, jas_image_t *image) { fprintf(stderr, "warning: invalid intermediate layer rates specifier " "ignored (%s)\n", - jas_tvparser_getval(tvp)); + jas_tvparser_getval(tvp)); } break; - case OPT_JP2OVERHEAD: - jp2overhead = atoi(jas_tvparser_getval(tvp)); - break; default: fprintf(stderr, "warning: ignoring invalid option %s\n", jas_tvparser_gettag(tvp)); @@ -522,11 +536,6 @@ cp_create(char *optstr, jas_image_t *image) { jas_tvparser_destroy(tvp); tvp = 0; - if (cp->totalsize != UINT_FAST32_MAX) { - cp->totalsize = (cp->totalsize > jp2overhead) ? - (cp->totalsize - jp2overhead) : 0; - } - if (cp->imgareatlx == UINT_FAST32_MAX) { cp->imgareatlx = 0; } else { @@ -697,20 +706,28 @@ cp_create(char *optstr, jas_image_t *image) { /* The intermediate layers rates must increase monotonically. */ for (lyrno = 0; lyrno + 2 < tcp->numlyrs; ++lyrno) { if (tcp->ilyrrates[lyrno] >= tcp->ilyrrates[lyrno + 1]) { - fprintf(stderr, - "intermediate layer rates must increase " - "monotonically\n"); + pm_message("Compression rate for Layer %u (%f) " + "is not greater than that for Layer %u (%f). " + "Rates must increase at every layer", + (unsigned)(lyrno+1), + jpc_fixtodbl(tcp->ilyrrates[lyrno + 1]), + (unsigned)lyrno, + jpc_fixtodbl(tcp->ilyrrates[lyrno])); goto error; } } /* The intermediate layer rates must be less than the overall rate. */ if (cp->totalsize != UINT_FAST32_MAX) { for (lyrno = 0; lyrno < tcp->numlyrs - 1; ++lyrno) { - if (jpc_fixtodbl(tcp->ilyrrates[lyrno]) > - ((double) cp->totalsize) / cp->rawsize) { - fprintf(stderr, - "warning: intermediate layer rates must be " - "less than overall rate\n"); + double const thisLyrRate = jpc_fixtodbl(tcp->ilyrrates[lyrno]); + double const completeRate = + ((double) cp->totalsize) / cp->rawsize; + if (thisLyrRate > completeRate) { + pm_message( + "Compression rate for Layer %u is %f, " + "which is greater than the rate for the complete " + "image (%f)", + (unsigned)lyrno, thisLyrRate, completeRate); goto error; } } @@ -753,28 +770,6 @@ jpc_enc_cp_destroy(jpc_enc_cp_t *cp) { -int -ratestrtosize(const char *s, uint_fast32_t rawsize, uint_fast32_t *size) { - - char *cp; - jpc_flt_t f; - - /* Note: This function must not modify output size on failure. */ - if ((cp = strchr(s, 'B'))) { - *size = atoi(s); - } else { - f = atof(s); - if (f < 0) { - *size = 0; - } else if (f > 1.0) { - *size = rawsize + 1; - } else { - *size = f * rawsize; - } - } - return 0; -} - /*****************************************************************************\ * Encoder constructor and destructor. \*****************************************************************************/ @@ -845,6 +840,8 @@ jpc_enc_destroy(jpc_enc_t *enc) { static int jpc_enc_encodemainhdr(jpc_enc_t *enc) { + uint_fast32_t const maintlrlen = 2; + jpc_siz_t *siz; jpc_cod_t *cod; jpc_qcd_t *qcd; @@ -961,7 +958,7 @@ jpc_enc_encodemainhdr(jpc_enc_t *enc) { (analgain + 1)), bandinfo->synenergywt); } else { absstepsize = jpc_inttofix(1); - } + } cp->ccps[cmptno].stepsizes[bandno] = jpc_abstorelstepsize(absstepsize, cp->ccps[cmptno].prec + analgain); @@ -1038,14 +1035,27 @@ jpc_enc_encodemainhdr(jpc_enc_t *enc) { enc->mrk = 0; } -#define MAINTLRLEN 2 mainhdrlen = jas_stream_getrwcount(enc->out) - startoff; enc->len += mainhdrlen; if (enc->cp->totalsize != UINT_FAST32_MAX) { - uint_fast32_t overhead; - overhead = mainhdrlen + MAINTLRLEN; - enc->mainbodysize = (enc->cp->totalsize >= overhead) ? - (enc->cp->totalsize - overhead) : 0; + uint_fast32_t const overhead = mainhdrlen + maintlrlen; + + if (overhead > enc->cp->totalsize) { + pm_message("Requested limit on image size of %u bytes " + "is not possible because it is less than " + "the image metadata size (%u bytes)", + (unsigned)enc->cp->totalsize, (unsigned)overhead); + return -1; + } + enc->mainbodysize = enc->cp->totalsize - overhead; + /* This has never actually worked. 'totalsize' is supposed to be + the total all-in, so if you request total size 200, you should + get an output file 200 bytes or smaller; but we see 209 bytes. + Furthermore, at 194 bytes, we get a warning that an empty layer + is generated, which probably is actually an error. + + We should fix this some day. + */ } else { enc->mainbodysize = UINT_FAST32_MAX; } @@ -1166,12 +1176,12 @@ calcrdslopes(jpc_enc_cblk_t *cblk) { static void traceLayerSizes(const uint_fast32_t * const lyrSizes, - unsigned int const layerCt) { + uint_fast32_t const layerCt) { if (jas_getdbglevel() > 0) { - unsigned int i; + uint_fast32_t i; for (i = 0; i < layerCt; ++i) { - fprintf(stderr, "Layer %u size = ", i); + fprintf(stderr, "Layer %u size = ", (unsigned)i); if (lyrSizes[i] == UINT_FAST32_MAX) fprintf(stderr, "Unlimited"); @@ -1196,41 +1206,22 @@ computeLayerSizes(jpc_enc_t * const encP, "unlimited". */ - unsigned int const lastLyrno = tileP->numlyrs - 1; + uint_fast32_t const lastLyrno = tileP->numlyrs - 1; - unsigned int lyrno; + uint_fast32_t lyrno; assert(tileP->numlyrs > 0); for (lyrno = 0; lyrno < lastLyrno; ++lyrno) { - tileP->lyrsizes[lyrno] = tileP->rawsize * jpc_fixtodbl( - cpP->tcp.ilyrrates[lyrno]); + tileP->lyrsizes[lyrno] = + MAX(tileP->rawsize * + jpc_fixtodbl(cpP->tcp.ilyrrates[lyrno]), + tilehdrlen + 1) - tilehdrlen; } tileP->lyrsizes[lastLyrno] = - (cpP->totalsize != UINT_FAST32_MAX) ? - (rho * encP->mainbodysize) : UINT_FAST32_MAX; - - - /* Subtract 'tilehdrlen' from every layer. */ - - for (lyrno = 0; lyrno < tileP->numlyrs; ++lyrno) { - if (tileP->lyrsizes[lyrno] != UINT_FAST32_MAX) { - if (tilehdrlen <= tileP->lyrsizes[lyrno]) { - tileP->lyrsizes[lyrno] -= tilehdrlen; - } else { - tileP->lyrsizes[lyrno] = 0; - } - } - } - - if (tileP->lyrsizes[lastLyrno] < 1) - pm_asprintf(errorP, "Cannot make image that small (%u bytes). " - "Even with pixels compressed as far as possible, metadata " - "would exceed the limit", - (unsigned)cpP->totalsize); - else - *errorP = NULL; + (cpP->totalsize == UINT_FAST32_MAX) ? + UINT_FAST32_MAX : (rho * encP->mainbodysize); traceLayerSizes(tileP->lyrsizes, tileP->numlyrs); } @@ -1313,8 +1304,8 @@ trace_layeringinfo(jpc_enc_t * const encP) { static void validateCumlensIncreases(const uint_fast32_t * const cumlens, - unsigned int const numlyrs) { - unsigned int lyrno; + uint_fast32_t const numlyrs) { + uint_fast32_t lyrno; for (lyrno = 1; lyrno < numlyrs - 1; ++lyrno) { if (cumlens[lyrno - 1] > cumlens[lyrno]) { @@ -1404,7 +1395,7 @@ findMinMaxRDSlopeValues(jpc_enc_tile_t * const tileP, static void performTier2CodingOneLayer(jpc_enc_t * const encP, jpc_enc_tile_t * const tileP, - unsigned int const lyrno, + uint_fast32_t const lyrno, jas_stream_t * const outP, const char ** const errorP) { /*---------------------------------------------------------------------------- @@ -1444,7 +1435,7 @@ performTier2CodingOneLayer(jpc_enc_t * const encP, static void assignHighSlopePassesToLayer(jpc_enc_t * const encP, jpc_enc_tile_t * const tileP, - unsigned int const lyrno, + uint_fast32_t const lyrno, bool const haveThresh, jpc_flt_t const thresh) { /*---------------------------------------------------------------------------- @@ -1522,7 +1513,7 @@ assignHighSlopePassesToLayer(jpc_enc_t * const encP, static void doLayer(jpc_enc_t * const encP, jpc_enc_tile_t * const tileP, - unsigned int const lyrno, + uint_fast32_t const lyrno, uint_fast32_t const allowedSize, jpc_flt_t const mnrdslope, jpc_flt_t const mxrdslope, @@ -1550,7 +1541,7 @@ doLayer(jpc_enc_t * const encP, long pos; jpc_flt_t lo; jpc_flt_t hi; - unsigned int numiters; + uint_fast32_t numiters; lo = mnrdslope; /* initial value */ hi = mxrdslope; /* initial value */ @@ -1625,10 +1616,10 @@ doLayer(jpc_enc_t * const encP, static void -performTier2Coding(jpc_enc_t * const encP, - unsigned int const numlyrs, - uint_fast32_t * const cumlens, - const char ** const errorP) { +performTier2Coding(jpc_enc_t * const encP, + uint_fast32_t const numlyrs, + uint_fast32_t * const cumlens, + const char ** const errorP) { /*---------------------------------------------------------------------------- Encode in 'numlyrs' layers, such that at each layer L, the size is cumlens[L]. @@ -1636,7 +1627,7 @@ performTier2Coding(jpc_enc_t * const encP, jpc_enc_tile_t * const tileP = encP->curtile; jas_stream_t * outP; - unsigned int lyrno; + uint_fast32_t lyrno; jpc_flt_t mnrdslope; jpc_flt_t mxrdslope; @@ -2770,7 +2761,7 @@ jpc_enc_encodemainbody(jpc_enc_t *enc) { tile->rawsize = cp->rawsize * rho; computeLayerSizes(enc, tile, cp, rho, tilehdrlen, &error); - + if (!error) { int rc; performTier2Coding(enc, tile->numlyrs, tile->lyrsizes, &error); diff --git a/converter/other/jpeg2000/libjasper/jpc/jpc_util.c b/converter/other/jpeg2000/libjasper/jpc/jpc_util.c index fede2bef..e6e3942a 100644 --- a/converter/other/jpeg2000/libjasper/jpc/jpc_util.c +++ b/converter/other/jpeg2000/libjasper/jpc/jpc_util.c @@ -114,9 +114,9 @@ * $Id$ */ -/******************************************************************************\ +/*****************************************************************************\ * Includes -\******************************************************************************/ +\*****************************************************************************/ #include #include @@ -133,21 +133,21 @@ #include "jpc_flt.h" #include "jpc_util.h" -/******************************************************************************\ +/*****************************************************************************\ * Miscellaneous Functions -\******************************************************************************/ +\*****************************************************************************/ -int jpc_atoaf(const char *s, int *numvalues, double **values) -{ - static char delim[] = ", \t\n"; +static unsigned int +countOfTokens(const char * const s, + const char * const delim) { + + unsigned int n; char buf[4096]; - int n; - double *vs; - char *cp; + const char * cp; strncpy(buf, s, sizeof(buf)); buf[sizeof(buf) - 1] = '\0'; - n = 0; + n = 0; /* initial value */ if ((cp = strtok(buf, delim))) { ++n; while ((cp = strtok(0, delim))) { @@ -156,32 +156,57 @@ int jpc_atoaf(const char *s, int *numvalues, double **values) } } } + return n; +} + + + +int +jpc_atoaf(const char * const s, + int * const numvaluesP, + double ** const valuesP) { +/*---------------------------------------------------------------------------- + Parse a string like "3.2,9,-5". Return as *numvaluesP the number of + values in the string and as *valuesP a malloced array of the values. - if (n) { - if (!(vs = jas_malloc(n * sizeof(double)))) { + But if the string is empty (*numvaluesP is zero), return *valuesP NULL. + + Delimiters can be comma as in the example or space, tab, or newline. +-----------------------------------------------------------------------------*/ + char const delim[] = ", \t\n"; + + unsigned int const valueCt = countOfTokens(s, delim); + + if (valueCt > 0) { + unsigned int i; + double * vs; + const char * cp; + char buf[4096]; + + if (!(vs = jas_malloc(valueCt * sizeof(double)))) { return -1; } strncpy(buf, s, sizeof(buf)); buf[sizeof(buf) - 1] = '\0'; - n = 0; + i = 0; if ((cp = strtok(buf, delim))) { - vs[n] = atof(cp); - ++n; + vs[i] = atof(cp); + ++i; while ((cp = strtok(0, delim))) { if (cp[0] != '\0') { - vs[n] = atof(cp); - ++n; + vs[i] = atof(cp); + ++i; } } } + assert(i == valueCt); + *numvaluesP = valueCt; + *valuesP = vs; } else { - vs = 0; + *valuesP = NULL; + *numvaluesP = 0; } - - *numvalues = n; - *values = vs; - return 0; } diff --git a/converter/other/jpeg2000/pamtojpeg2k.c b/converter/other/jpeg2000/pamtojpeg2k.c index ee5189ce..8f7409c0 100644 --- a/converter/other/jpeg2000/pamtojpeg2k.c +++ b/converter/other/jpeg2000/pamtojpeg2k.c @@ -53,6 +53,8 @@ struct CmdlineInfo { enum compmode compmode; unsigned int compressionSpec; float compression; + unsigned int size; + unsigned int sizeSpec; char * ilyrrates; enum progression progression; unsigned int numrlvls; @@ -76,7 +78,7 @@ parseCommandLine(int argc, char ** argv, struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that many of the strings that this function returns in the - *cmdline_p structure are actually in the supplied argv array. And + *cmdlineP structure are actually in the supplied argv array. And sometimes, one of these strings is actually just a suffix of an entry in argv! -----------------------------------------------------------------------------*/ @@ -126,6 +128,8 @@ parseCommandLine(int argc, char ** argv, &modeSpec, 0); OPTENT3(0, "compression", OPT_FLOAT, &cmdlineP->compression, &cmdlineP->compressionSpec, 0); + OPTENT3(0, "size", OPT_UINT, &cmdlineP->size, + &cmdlineP->sizeSpec, 0); OPTENT3(0, "ilyrrates", OPT_STRING, &cmdlineP->ilyrrates, &ilyrratesSpec, 0); OPTENT3(0, "progression", OPT_STRING, &progressionOpt, @@ -219,6 +223,9 @@ parseCommandLine(int argc, char ** argv, if (!debuglevelSpec) cmdlineP->debuglevel = 0; + if (cmdlineP->compressionSpec && cmdlineP->sizeSpec) + pm_error("You cannot specify by -compression and -size"); + if (argc - 1 == 0) cmdlineP->inputFilename = strdup("-"); /* he wants stdin */ else if (argc - 1 == 1) @@ -405,6 +412,8 @@ writeJpc(jas_image_t * const jasperP, if (cmdline.compressionSpec) sprintf(rateOpt, "rate=%1.9f", 1.0/cmdline.compression); + else if (cmdline.sizeSpec) + sprintf(rateOpt, "rate=%uB", cmdline.size); else { /* No 'rate' option. This means there is no constraint on the image size, so the encoder will compress losslessly. Note that the -- cgit 1.4.1