diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2023-08-26 22:55:35 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2023-08-26 22:55:35 +0000 |
commit | 28933e862bf1864c23ca5f3a837a1e5d3789eeea (patch) | |
tree | 34c31d2b6e0fb184eddbd9e612340e3e35b8f3b3 /converter/other/pnmtojpeg.c | |
parent | 287c76a2f527155343889d48009629e5d2f59e00 (diff) | |
download | netpbm-mirror-28933e862bf1864c23ca5f3a837a1e5d3789eeea.tar.gz netpbm-mirror-28933e862bf1864c23ca5f3a837a1e5d3789eeea.tar.xz netpbm-mirror-28933e862bf1864c23ca5f3a837a1e5d3789eeea.zip |
cleanup
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@4617 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/other/pnmtojpeg.c')
-rw-r--r-- | converter/other/pnmtojpeg.c | 291 |
1 files changed, 190 insertions, 101 deletions
diff --git a/converter/other/pnmtojpeg.c b/converter/other/pnmtojpeg.c index 5e639182..1b064f5c 100644 --- a/converter/other/pnmtojpeg.c +++ b/converter/other/pnmtojpeg.c @@ -489,9 +489,9 @@ readTextInteger(FILE * const fileP, static bool -readScanInteger (FILE * const fileP, - long * const resultP, - int * const termcharP) { +readScanInteger(FILE * const fileP, + long * const resultP, + int * const termcharP) { /*---------------------------------------------------------------------------- Variant of readTextInteger that always looks for a non-space termchar; this simplifies parsing of punctuation in scan scripts. @@ -523,114 +523,194 @@ readScanInteger (FILE * const fileP, -static bool -readScanScript(j_compress_ptr const cinfo, - const char * const fileNm) { +static void +readScanScriptComponents(FILE * const fP, + jpeg_scan_info * const scanP, + int * const termcharP, + long * const valP, + const char ** const errorP) { /*---------------------------------------------------------------------------- - Read a scan script from the specified text file. - Each entry in the file defines one scan to be emitted. - Entries are separated by semicolons ';'. - An entry contains one to four component indexes, - optionally followed by a colon ':' and four progressive-JPEG parameters. - The component indexes denote which component(s) are to be transmitted - in the current scan. The first component has index 0. - Sequential JPEG is used if the progressive-JPEG parameters are omitted. - The file is free format text: any whitespace may appear between numbers - and the ':' and ';' punctuation marks. Also, other punctuation (such - as commas or dashes) can be placed between numbers if desired. - Comments preceded by '#' may be included in the file. - Note: we do very little validity checking here; - jcmaster.c will validate the script parameters. + Set component table in *scanP, i.e. scanP->component_index and + scanP->comps_in_scan. + + *termcharP and *valP at entry are for the value we already read from the + file; at exit, they are the value beyond the component table. -----------------------------------------------------------------------------*/ - FILE * fp; - unsigned int nscans; - unsigned int ncomps; - int termchar; - long val; -#define MAX_SCANS 100 /* quite arbitrary limit */ - jpeg_scan_info scans[MAX_SCANS]; + unsigned int compCt; - fp = fopen(fileNm, "r"); - if (fp == NULL) { - pm_message("Can't open scan definition file '%s'", fileNm); - return false; - } - nscans = 0; + *errorP = NULL; /* initial value */ - while (readScanInteger(fp, &val, &termchar)) { - ++nscans; /* We got another scan */ - if (nscans > MAX_SCANS) { - pm_message("Too many scans defined in file '%s'", fileNm); - fclose(fp); - return false; - } - scans[nscans-1].component_index[0] = (int) val; - ncomps = 1; - while (termchar == ' ') { - if (ncomps >= MAX_COMPS_IN_SCAN) { - pm_message("Too many components in one scan in file '%s'", - fileNm); - fclose(fp); - return FALSE; - } - if (! readScanInteger(fp, &val, &termchar)) - goto bogus; - scans[nscans-1].component_index[ncomps] = (int) val; - ++ncomps; + /* First component is value we already read: */ + scanP->component_index[0] = (int) *valP; + compCt = 1; + + /* Rest of components follow, until termchar other than ' ': */ + while (*termcharP == ' ' && !*errorP) { + if (compCt >= MAX_COMPS_IN_SCAN) { + pm_asprintf(errorP, "Too many components in one scan " + "(Max allowed is %u)", MAX_COMPS_IN_SCAN); } - scans[nscans-1].comps_in_scan = ncomps; - if (termchar == ':') { - if (! readScanInteger(fp, &val, &termchar) || termchar != ' ') - goto bogus; - scans[nscans-1].Ss = (int) val; - if (! readScanInteger(fp, &val, &termchar) || termchar != ' ') - goto bogus; - scans[nscans-1].Se = (int) val; - if (! readScanInteger(fp, &val, &termchar) || termchar != ' ') - goto bogus; - scans[nscans-1].Ah = (int) val; - if (! readScanInteger(fp, &val, &termchar)) - goto bogus; - scans[nscans-1].Al = (int) val; + if (! readScanInteger(fP, valP, termcharP)) { + pm_asprintf(errorP, "Invalid scan entry format"); } else { - /* set non-progressive parameters */ - scans[nscans-1].Ss = 0; - scans[nscans-1].Se = DCTSIZE2-1; - scans[nscans-1].Ah = 0; - scans[nscans-1].Al = 0; - } - if (termchar != ';' && termchar != EOF) { - bogus: - pm_message("Invalid scan entry format in file '%s'", fileNm); - fclose(fp); - return false; + scanP->component_index[compCt++] = (int) *valP; } } + scanP->comps_in_scan = compCt; +} - if (termchar != EOF) { - pm_message("Non-numeric data in file '%s'", fileNm); - fclose(fp); - return false; + + +static void +readScanScriptProg(FILE * const fP, + jpeg_scan_info * const scanP, + int * const termcharP, + long * const valP, + const char ** const errorP) { + + if (! readScanInteger(fP, valP, termcharP) || *termcharP != ' ') + pm_asprintf(errorP, "Error in Ss"); + else { + scanP->Ss = (int) *valP; + if (! readScanInteger(fP, valP, termcharP) || *termcharP != ' ') + pm_asprintf(errorP, "Error in Se"); + else { + scanP->Se = (int) *valP; + if (! readScanInteger(fP, valP, termcharP) || *termcharP != ' ') + pm_asprintf(errorP, "Error in Ah"); + else { + scanP->Ah = (int) *valP; + if (! readScanInteger(fP, valP, termcharP)) + pm_asprintf(errorP, "Error in Al"); + else { + scanP->Al = (int) *valP; + *errorP = NULL; + } + } + } } +} - if (nscans > 0) { - /* Stash completed scan list in cinfo structure. NOTE: in - this program, JPOOL_IMAGE is the right lifetime for this - data, but if you want to compress multiple images you'd - want JPOOL_PERMANENT. - */ - unsigned int const scanInfoSz = nscans * sizeof(jpeg_scan_info); - jpeg_scan_info * const scanInfo = - (jpeg_scan_info *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - scanInfoSz); - memcpy(scanInfo, scans, scanInfoSz); - cinfo->scan_info = scanInfo; - cinfo->num_scans = nscans; + + +static void +setScanScriptNonProgressive(jpeg_scan_info * const scanP) { + + scanP->Ss = 0; + scanP->Se = DCTSIZE2-1; + scanP->Ah = 0; + scanP->Al = 0; +} + + + +static void +readScanScript1(FILE * const fP, + jpeg_scan_info * const scanP, + int * const termcharP, + long * const valP, + const char ** const errorP) { + + const char * error; + + readScanScriptComponents(fP, scanP, termcharP, valP, &error); + + if (error) { + pm_asprintf(errorP, "Error in component table. %s", error); + pm_strfree(error); + } else { + if (*termcharP == ':') { + const char * error; + + readScanScriptProg(fP, scanP, termcharP, valP, &error); + + if (error) { + pm_asprintf(errorP, "Invalid progressive parameters. %s", + error); + pm_strfree(error); + } + } else + setScanScriptNonProgressive(scanP); + + if (*termcharP != ';' && *termcharP != EOF) { + pm_asprintf(errorP, "Expected ';' or EOF"); + } } +} - fclose(fp); - return true; + + +static void +readScanScript(j_compress_ptr const cinfoP, + const char * const fileNm, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Read a scan script from the specified text file. + + Each entry in the file defines one scan to be emitted. + + Entries are separated by semicolons ';'. + + An entry contains one to four component indexes, optionally followed by a + colon ':' and four progressive-JPEG parameters. The indexes and parameters + are separated by spaces. + + The component indexes identify the color components to be transmitted in the + current scan. The first component has index 0. + + Sequential JPEG is used if the progressive-JPEG parameters are omitted. + + Any whitespace may appear between numbers and the ':' and ';' punctuation + marks. Also, other punctuation (such as commas or dashes) may be placed + between numbers. + + Comments preceded by '#' may be included in the file. + + Note: we do very little validity checking here; libjpeg will validate the + script parameters. + + The data goes into newly malloc'ed memory pointed to by cinfo->scan_info, + with its size as cinfo->num_scans. If there isn't any scan script, + cinfo->scan_info is null. +-----------------------------------------------------------------------------*/ + FILE * fP; + + fP = fopen(fileNm, "r"); + if (!fP) + pm_asprintf(errorP, "Can't open file"); + else { + unsigned int scanCt; + int termchar; + long val; + jpeg_scan_info * scan; /* malloc'ed array */ + /* Index 0 in this array is called "Entry 1" by libjpeg messages */ + + *errorP = NULL; /* initial assumption */ + scanCt = 0; scan = NULL; /* initial values */ + + while (readScanInteger(fP, &val, &termchar) && !*errorP) { + ++scanCt; /* We got another scan */ + + REALLOCARRAY(scan, scanCt); + + if (!scan) + pm_error("Unable to allocate memory for scan table"); + + readScanScript1(fP, &scan[scanCt-1], &termchar, &val, errorP); + } + if (!*errorP && termchar != EOF) + pm_asprintf(errorP, "Non-numeric data in file '%s'", fileNm); + + if (*errorP) { + if (scan) + free(scan); + cinfoP->scan_info = NULL; + } else { + cinfoP->scan_info = scanCt > 0 ? scan : NULL; + cinfoP->num_scans = scanCt; + } + fclose(fP); + } } @@ -883,10 +963,14 @@ setupJpeg(struct jpeg_compress_struct * const cinfoP, setupJpegDensity(cinfoP, cmdline.density); if (cmdline.scans != NULL) { - if (! readScanScript(cinfoP, cmdline.scans)) { - pm_message("Error in scan script '%s'.", cmdline.scans); + const char * error; + readScanScript(cinfoP, cmdline.scans, &error); + if (error) { + pm_message("Error in scan script '%s'. %s", cmdline.scans, error); + pm_strfree(error); } - } + } else + cinfoP->scan_info = NULL; /* Specify data destination for compression */ jpeg_stdio_dest(cinfoP, ofP); @@ -1137,6 +1221,11 @@ main(int argc, jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); + if (cinfo.scan_info) { + free((void*)cinfo.scan_info); + cinfo.scan_info = NULL; + } + /* Close files, if we opened them */ if (ifP != stdin) pm_close(ifP); |