From 27bea38852a7e0f5af8cdada0437c349e5d0aa57 Mon Sep 17 00:00:00 2001 From: Dirk Meyer Date: Wed, 2 Mar 2022 10:56:56 +0100 Subject: [PATCH] graphics/xv: update for jasper 3 support --- graphics/xv/Makefile | 2 +- graphics/xv/files/patch-xvjp2k.c | 2384 +++++++++++++++++++++++++++++- 2 files changed, 2376 insertions(+), 10 deletions(-) diff --git a/graphics/xv/Makefile b/graphics/xv/Makefile index 0bb76fb34381..4998e169a6ed 100644 --- a/graphics/xv/Makefile +++ b/graphics/xv/Makefile @@ -2,7 +2,7 @@ PORTNAME= xv PORTVERSION= 3.10a -PORTREVISION= 17 +PORTREVISION= 18 CATEGORIES+= graphics MASTER_SITES= ftp://ftp.cis.upenn.edu/pub/xv/:base \ SF/png-mng/XV%20jumbo%20patches/20070520 diff --git a/graphics/xv/files/patch-xvjp2k.c b/graphics/xv/files/patch-xvjp2k.c index 36e6e70a37e6..2f84d53a8c16 100644 --- a/graphics/xv/files/patch-xvjp2k.c +++ b/graphics/xv/files/patch-xvjp2k.c @@ -1,11 +1,2377 @@ ---- xvjp2k.c.orig 2007-05-14 01:04:37 UTC -+++ xvjp2k.c -@@ -76,7 +76,7 @@ static const char *fbasename, /* File's base name, fo - */ - int jas_getdbglevel(void) {return 0;} - int jas_setdbglevel(int n) {return 0;} --int jas_memdump(FILE *fp,void *data,size_t len) {return 0;} -+int jas_memdump(FILE *fp,const void *data,size_t len) {return 0;} +diff -ur ./xvjp2k.c /home/src/master/GIT/xv/src/xvjp2k.c +--- ./xvjp2k.c 2022-02-20 20:18:25.590840000 +0100 ++++ /home/src/master/GIT/xv/src/xvjp2k.c 2022-02-20 20:39:26.277883000 +0100 +@@ -2,20 +2,20 @@ + * xvjp2k.c - I/O subroutines for JPEG 2000 format pictures + * + * This module is a "shim" between XV and a JPEG 2000 CODEC in the open-source +- * JasPer Library created by Michael D. Adams; for more information, see the URL +- * "http://www.ece.uvic.ca/~mdadams/jasper". We don't use most of the other +- * facilities in this library, so it's better to link XV with a UNIX "archive" +- * representation of it, not a DLL. ++ * JasPer Library created by Michael D. Adams; for more information, see the ++ * URL "http://www.ece.uvic.ca/~mdadams/jasper". We don't use most of the ++ * other facilities in this library, so it's better to link XV with a UNIX ++ * "archive" representation of it, not a DLL. + * + * JPEG 2000 files can be represented in either of two general ways: The + * simplest representation is a "code stream", which often has a ".jpc" file + * name suffix and is organized much like a classical JPEG file, except that + * unfortunately, JPEG 2000 code streams indicate the no. of colors in an image + * but no longer give any clues about its color space (e.g., RGB or YCbCr). +- * Instead, there is now a semantically higher-level representation, which often +- * has a ".jp2" file name suffix and encapsulates a "code stream" with (possibly +- * a lot of) color-space information, optionally including things like ICC +- * correction tables. ++ * Instead, there is now a semantically higher-level representation, which ++ * often has a ".jp2" file name suffix and encapsulates a "code stream" with ++ * (possibly a lot of) color-space information, optionally including things ++ * like ICC correction tables. + * + * Compared to the IJG JPEG Library used in file "xvjpeg.c", one must solve + * several problems for color images when marrying JasPer to XV. +@@ -25,9 +25,9 @@ + * normal "X Windows" display, so we must carefully check a decoded image's + * parameters in order to reject anything that we can't handle gracefully. + * +- * 2. JasPer prefers to decode/encode images using color-plane "slices", instead +- * of interleaved pixels needed by "X Windows", so we must (de)interleave +- * copies of the image buffer here. ++ * 2. JasPer prefers to decode/encode images using color-plane "slices", ++ * instead of interleaved pixels needed by "X Windows", so we must ++ * (de)interleave copies of the image buffer here. + * + * XXX Things to do: + * +@@ -42,599 +42,419 @@ + * + * --Scott Marovich , Hewlett-Packard Laboratories, + * January 2005. ++ * ++ * Michael Aadams , University of Victoria, January 2022. ++ * The original code needed to be almost entirely rewritten due to its ++ * insistence on bypassing the JasPer library API and violating many ++ * preconditions in the usage of the API (which, of course, caused ++ * many problems as the JasPer library evolved over time). ++ * + */ + #include "copyright.h" - int jas_eprintf(const char *fmt,...) /* Handle JasPer Library message */ +-#define NEEDSARGS ++#define NEEDSARGS + #include "xv.h" + + #ifdef HAVE_JP2K + + #include +-/* missing prototype in 1.701.0, sigh: */ +-jas_stream_t *jas_stream_freopen PARM((const char *, const char *, FILE *)); + +-static const char *fbasename, /* File's base name, for error/warning msgs */ +- bad_samp[] = "%s: can't read %d-plane %s file!", +- fmode[] = "rb", +- full_msg[] = "%s %s. (%ld bytes)", +- jp2_kind[] = "JP2", +- jpc_kind[] = "JPEG 2000", +- load_msg[] = "Loading %dx%d %s %s (%ld bytes)...", +- no_mem[] = "%s: can't read %s file - out of memory", +- pixel_size[] = "%s: can't display %d-bit pixels!", +- shrt_msg[] = "%dx%d %s %s. ", +- truncated[] = "%s: Unexpected end of %s file", +- read_err[] = "%s: I/O error reading %s file", +- bad_dims[] = "%s: error in JPEG-2000 header (bad image size)"; ++#define GIBI (1024ULL * 1024ULL * 1024ULL) + +-/* We only want to override the JasPer Library's "jas_eprintf()" subroutine in +- order to make it a "wrapper" around XV's own error-reporting subroutine, but +- because of the way the former is currently packaged in JasPer Library Version +- 1.701, we must override everything else packaged in the "jas_debug.o" module +- with it, otherwise we get "duplicate definition" messages from the linker. +-*/ +-int jas_getdbglevel(void) {return 0;} +-int jas_setdbglevel(int n) {return 0;} +-int jas_memdump(FILE *fp,void *data,size_t len) {return 0;} ++static const char *fbasename, /* File's base name, for error/warning msgs */ ++ bad_samp[] = "%s: can't read %d-plane %s file!", fmode[] = "rb", ++ full_msg[] = "%s %s. (%ld bytes)", jp2_kind[] = "JP2", ++ jpc_kind[] = "JPEG 2000", load_msg[] = "Loading %dx%d %s %s (%ld bytes)...", ++ no_mem[] = "%s: can't read %s file - out of memory", ++ pixel_size[] = "%s: can't display %d-bit pixels!", ++ shrt_msg[] = "%dx%d %s %s. ", ++ truncated[] = "%s: Unexpected end of %s file", ++ read_err[] = "%s: I/O error reading %s file", ++ bad_dims[] = "%s: error in JPEG-2000 header (bad image size)"; + +-int jas_eprintf(const char *fmt,...) /* Handle JasPer Library message */ ++static int get_debug_level(void) { +- static char error[] = "error: ", warning[]= "warning: "; +- va_list ap; +- int kind = ISTR_WARNING; +- char buffer[512]; +- register char *p; +- +- /* Unlike the IJG JPEG Library, the JasPer Library current has no graceful way +- for an application (= us!) to intercept its diagnostic messages and output +- them using our own subroutines, so this ugly replacement for its output +- subroutine will have to suffice. At Version 1.701, lthough the library's +- own "jas_eprintf()" is a varargs subroutine, all calls currently pass just +- 1 string with a Line Feed at the end and no "printf(3C)" arguments. Most +- strings begin with "error: " or "warning: ", although a few have neither. +- We try to translate these into the format preferred by XV, trimming any +- trailing Line Feed character (ugh!). +- */ +- va_start(ap, fmt); +- vsnprintf(p = buffer,512,fmt,ap); +- va_end(ap); +- while (*p++); +- if (p[-2] == '\n') p[-2] = '\0'; +- p = buffer; +- if (strncmp(p,error,sizeof error) == 0) /* "error: ... " */ +- { +- kind = ISTR_WARNING; +- p += sizeof error; +- } +- else /* "warning: ... " */ +- if (strncmp(p,warning,sizeof warning) == 0) +- { +- kind = ISTR_INFO; +- p += sizeof warning; +- }; +- SetISTR(kind,"%s: %s",fbasename,p); +- return strlen(fmt); ++ int debug_level = 0; ++ const char *cp; ++ if ((cp = getenv("XV_JASPER_DEBUG_LEVEL"))) { ++ debug_level = atoi(cp); ++ } ++ return debug_level; + } + +-static char *SetBuf(FILE *f) +-{ +- char *buf; +- register char *p; ++#if (JAS_VERSION_MAJOR >= 3) ++static int print_log(jas_logtype_t type, const char *format, va_list ap) { ++ const int buffer_size = 512; ++ char buffer[buffer_size]; ++ int count; + +- /* JPEG 2000 image files are apt to be large, but the buffer size allocated by +- most implementations of the "C" Standard I/O Library is still ridiculously +- small, typically 1 KB. We want to allocate a much larger buffer for higher +- I/O efficiency, but the details are unfortunately a bit platform-specific. +- Under UNIX systems with virtual memory, we want to encourage its internal +- "physio()" subroutine by making the buffer an integral number of pages, +- aligned on a page-multiple memory address boundary. Under HP-UX 11.1+ and +- perhaps other operating-systems, a Standard I/O buffer is preceded by a +- header whose size must also be taken into account. +- */ +-# ifndef IOBUFSIZ +-# define IOBUFSIZ 65536 +-# endif /* IOBUFSIZ */ +-# ifdef __hpux +-# define OVERHEAD sizeof(mbstate_t) +-# endif /* __hpux */ +-# ifndef OVERHEAD +-# define OVERHEAD 0 +-# endif /* OVERHEAD */ ++ int log_class = jas_logtype_getclass(type); ++ int kind; ++ switch (log_class) { ++ case JAS_LOGTYPE_CLASS_INFO: ++ kind = ISTR_INFO; ++ break; ++ case JAS_LOGTYPE_CLASS_WARN: ++ case JAS_LOGTYPE_CLASS_ERROR: ++ default: ++ kind = ISTR_WARNING; ++ break; ++ } + +-# ifdef NBPG +- if (!(buf = p = malloc(NBPG+OVERHEAD+IOBUFSIZ))) return 0; +- p = (char *)((unsigned long)p+NBPG-1 & ~(NBPG-1)); +- p -= OVERHEAD; +-# else /* not NBPG */ +- if (!(buf = p = malloc(OVERHEAD+IOBUFSIZ))) return 0; +- p += OVERHEAD; +-# endif /* NBPG */ +- setvbuf(f,p,_IOFBF,OVERHEAD+IOBUFSIZ); +- return buf; +-# undef OVERHEAD +-# undef IOBUFSIZ ++ count = vsnprintf(buffer, buffer_size, format, ap); ++ ++ if (log_class == JAS_LOGTYPE_CLASS_WARN || ++ log_class == JAS_LOGTYPE_CLASS_ERROR) { ++ if (get_debug_level() >= 1) { ++ jas_eprintf("%s", buffer); ++ } else { ++ int i; ++ for (i = 0; i < count; ++i) { ++ if (buffer[i] == '\n') { ++ buffer[i] = ' '; ++ } ++ } ++ SetISTR(kind, "%s: %s", fbasename, buffer); ++ } ++ } else { ++ jas_eprintf("%s", buffer); ++ } ++ return count; + } ++#endif + +-int LoadJPC(char *fname,register PICINFO *pinfo,int quick) +-{ +- jas_image_t *img; +- jas_stream_t *str; +- FILE *fp; +- char *iobuf; +- const char *s; +- unsigned long filesize; +- long w, h, npixels, bufsize; +- int ok = 0, vstride; +- register int i; ++static int LoadJP2K(char *fname, register PICINFO *pinfo, int quick, ++ bool jpc_format) { ++ jas_image_t *img = 0; ++ jas_stream_t *str = 0; ++ FILE *fp; ++ const char *s; ++ unsigned long filesize; ++ long w, h, npixels, bufsize; ++ int vstride; ++ register int i; ++ jas_matrix_t *data = 0; + +- /* Load a JPEG 2000 "code stream" image file into a pixel buffer for XV. +- Unlike classical JPEG files, they have no clue about the image's color +- space, so we check for 8-bit data samples but make no effort to check or +- convert color spaces, and "what you see is what you get". For now, ignore +- the "quick" option to return a reduced-resolution or -size image. Return 1 +- on success, or 0 on failure. +- */ +- if (!(fp = xv_fopen(fname,fmode))) return 0; +- fbasename = BaseName(fname); /* Input file's base name, for message(s) */ +- if (!(iobuf = SetBuf(fp))) +- { +- (void)fclose(fp); +- SetISTR(ISTR_WARNING,no_mem,fbasename,jpc_kind); +- goto L3; +- } ++ int ret = 1; + +- /* Before telling the JasPer Library about this file, get its size for display +- purposes. Non-UNIX systems don't necessarily simulate "stat(2)", so do it +- crudely but portably by seeking to the end, then back to the beginning. +- */ +- fseek(fp,0L,2); +- filesize = ftell(fp); +- fseek(fp,0L,0); ++ int debug_level = get_debug_level(); ++#if (JAS_VERSION_MAJOR >= 3) ++ size_t max_mem = jas_get_total_mem_size(); ++ if (!max_mem) { ++ max_mem = GIBI; ++ } ++ jas_conf_clear(); ++ jas_conf_set_max_mem_usage(max_mem); ++ jas_init_library(); ++ jas_init_thread(); ++ jas_set_vlogmsgf(print_log); ++#else ++ jas_init(); ++#endif ++#if (JAS_VERSION_MAJOR >= 3) ++ jas_set_debug_level(debug_level); ++#else ++ jas_setdbglevel(debug_level); ++#endif + +- /* "jas_stream_close()" will eventually close the input file, so only do it +- explicitly if no stream can be created: +- */ +- if (!(str = jas_stream_freopen(fname,fmode,fp))) /* nice if prototype... */ +- { +- (void)fclose(fp); +- goto L3; +- } ++ if (!(fp = xv_fopen(fname, fmode))) { ++ return 0; ++ } ++ /* Input file's base name, for message(s) */ ++ fbasename = BaseName(fname); + +- /* It's not clear to me whether the following represents a JasPer Library "bug" +- but it sure looks goofy: Unless a stream buffer is marked "read only", +- which only happens when the stream's "fillbuf" method is called, even though +- our buffers are always "read only", the library will try to flush out buffer +- contents when the stream is destroyed, which makes it die a horrible death. +- So, mark the stream buffer proactively: +- */ +- str->bufmode_ |= JAS_STREAM_RDBUF; /* We will only read the stream buffer */ +- if (!(img = jpc_decode(str,0))) goto L2; +- if ((vstride = jas_image_numcmpts(img))) /* num. color planes */ +- { ++ /* Compute file size is portable way. */ ++ fseek(fp, 0L, 2); ++ filesize = ftell(fp); ++ fseek(fp, 0L, 0); + +- /* After the image-component streams created, they are left in a "write" +- state with the streams' cursors positioned at their ends, so "seek" in +- order to "read" each stream from its beginning. +- */ +- i = vstride; +- while (--i >= 0) +- if (jas_stream_seek(img->cmpts_[i]->stream_,0L,0)) +- { +- SetISTR(ISTR_WARNING,read_err,fbasename,jpc_kind); +- goto L1; +- } +- } +- w = jas_image_width(img); +- h = jas_image_height(img); ++#if (JAS_VERSION_MAJOR >= 3) ++ /* ++ This approach will not work in JasPer prior to 3.0.0 due to a bug in ++ the stream code. ++ */ ++ if (!(str = jas_stream_freopen(fname,fmode,fp))) { ++ fclose(fp); ++ ret = 0; ++ goto done; ++ } + +- /* avoid buffer overflow */ +- npixels = w * h; +- bufsize = vstride * npixels; +- if (w <= 0 || h <= 0 || npixels/w != h || bufsize/vstride != npixels) +- { +- (void)fclose(fp); +- SetISTR(ISTR_WARNING,bad_dims,fbasename); +- goto L1; +- } +- pinfo->normw = pinfo->w = w; +- pinfo->normh = pinfo->h = h; ++ /* It's not clear to me whether the following represents a JasPer Library ++ "bug" but it sure looks goofy: Unless a stream buffer is marked "read ++ only", which only happens when the stream's "fillbuf" method is called, ++ even though our buffers are always "read only", the library will try to ++ flush out buffer contents when the stream is destroyed, which makes it ++ die a horrible death. So, mark the stream buffer proactively: ++ */ ++ str->bufmode_ |= JAS_STREAM_RDBUF; /* We will only read the stream buffer */ ++#else ++ { ++ if (!(str = jas_stream_memopen(0, 0))) { ++ ret = 0; ++ goto done; ++ } ++ const size_t buffer_size = 1024; ++ char buffer[buffer_size]; ++ for (;;) { ++ size_t count; ++ count = fread(buffer, 1, buffer_size, fp); ++ if (!count) { ++ if (!feof(fp)) { ++ ret = 0; ++ goto done; ++ } ++ break; ++ } ++ if (jas_stream_write(str, buffer, count) != count) { ++ ret = 0; ++ goto done; ++ } ++ } ++ jas_stream_rewind(str); ++ } ++#endif + +- /* Sanity-check the image's color space and no. of colors. For now, accept +- only "generic" color spaces, not files needing image-specific color +- correction, but fix that someday... +- */ +- switch (vstride) +- { +- default: +- SetISTR(ISTR_WARNING,bad_samp,fbasename,vstride,jpc_kind); +- goto L1; +- case 1: +- if ((i = jas_image_cmptprec(img,0)) != 8) /* not 8-bit pixels */ +- { +- SetISTR(ISTR_WARNING,pixel_size,fbasename,i); +- goto L1; +- } +- s = "Greyscale"; +- pinfo->type = PIC8; +- pinfo->colType = F_GREYSCALE; +- i = 256; /* Return fake indexed-color "map" */ +- while (--i >= 0) pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i; +- break; +- case 3: ++ const jas_image_fmtinfo_t *fmtinfo = jas_image_lookupfmtbyname( ++ jpc_format ? "jpc" : "jp2"); ++ assert(fmtinfo); ++ if (!(img = jas_image_decode(str, fmtinfo->id, 0))) { ++ ret = 0; ++ goto done; ++ } + +- /* BEWARE OF KLUDGE: If the image's color space is RGB, assume that the +- data-sample precision for all color planes is the +- same. If the color space is YCbCr, assume the luminance (Y = 0th) +- component has the greatest precision, although the chrominance +- (Cr = 1st, Cb = 2nd) components are usually sub-sampled. +- */ +- if ((i = jas_image_cmptprec(img,0)) != 8) /* not 24-bit pixels */ +- { +- SetISTR(ISTR_WARNING,pixel_size,fbasename,i*3); +- goto L1; +- } +- s = "Color"; +- pinfo->type = PIC24; +- pinfo->colType = F_FULLCOLOR; ++ w = jas_image_width(img); ++ h = jas_image_height(img); ++ vstride = jas_image_numcmpts(img); + +- /* XXX Unlike the IJG JPEG Library, the JasPer Library is apparently +- unable to quantize colors or tell us whether the image's colors +- were quantized by its creator, so it seems that we can't return a +- color map for XV to potentially use 8-bit indexed color. If there +- *is* an easy way to do it that escapes me, put the code here someday. +- */ +- } +- if (!(pinfo->pic = (byte *)malloc(bufsize))) /* image buffer for XV */ +- { +- SetISTR(ISTR_WARNING,no_mem,fbasename,jpc_kind); +- goto L1; +- } +- pinfo->frmType = F_JPC; +- sprintf(pinfo->fullInfo,full_msg,s,jpc_kind,filesize); +- sprintf(pinfo->shrtInfo,shrt_msg,pinfo->w,pinfo->h,s,jpc_kind); +- SetISTR(ISTR_INFO,load_msg,pinfo->normw,pinfo->normh,s,jpc_kind,filesize); +- if (vstride == 1) /* gray-scale image */ +- { register jas_stream_t *c = img->cmpts_[0]->stream_; +- register byte *p = pinfo->pic; ++ /* avoid buffer overflow */ ++ npixels = w * h; ++ bufsize = vstride * npixels; ++ if (w <= 0 || h <= 0 || npixels / w != h || bufsize / vstride != npixels) { ++ (void)fclose(fp); ++ SetISTR(ISTR_WARNING, bad_dims, fbasename); ++ ret = 0; ++ goto done; ++ } ++ pinfo->normw = pinfo->w = w; ++ pinfo->normh = pinfo->h = h; + +- /* Since this is a 1-plane image, avoid a lot of errant nonsense in the +- JasPer Library by sequentially reading all of the data into our buffer +- directly. +- */ +- do if ((i = (*c->ops_->read_)(c->obj_,(char *)p,bufsize)) <= 0) +- { +- SetISTR(ISTR_WARNING,i < 0 ? read_err : truncated,fbasename, +- jpc_kind); +- goto L1; +- } +- while ((p += i),(bufsize -= i) > 0); +- } +- else /* RGB color image */ +- { ++ /* Sanity-check the image's color space and no. of colors. For now, accept ++ only "generic" color spaces, not files needing image-specific color ++ correction, but fix that someday... ++ */ ++ switch (vstride) { ++ static char color_space[] = {"%s: invalid color space!"}; + +- /* Reading color images is inefficient because JPEG 2000 wants to partition +- file data into separate image planes (colors), while XV wants data +- samples from each plane to be interleaved as 3-byte pixels. Apparently +- the fastest method consists of 3 passes through the XV image buffer, +- into which we insert the bytes of each component. +- */ +- i = 0; +- do /* each color component */ +- { long npix = npixels; +- register jas_stream_t *c = img->cmpts_[i]->stream_; +- register byte *p = pinfo->pic + i; ++ default: ++ SetISTR(ISTR_WARNING, bad_samp, fbasename, vstride, jp2_kind); ++ ret = 0; ++ goto done; ++ case 1: ++ if (!jas_clrspc_isunknown(i = jas_image_clrspc(img)) && ++ jas_clrspc_fam(i) != JAS_CLRSPC_FAM_GRAY) { ++ SetISTR(ISTR_WARNING, color_space, fbasename); ++ ret = 0; ++ goto done; ++ } ++ if ((i = jas_image_cmptprec(img, 0)) != 8) /* not 8-bit pixels */ ++ { ++ SetISTR(ISTR_WARNING, pixel_size, fbasename, i); ++ ret = 0; ++ goto done; ++ } ++ s = "Greyscale"; ++ pinfo->type = PIC8; ++ pinfo->colType = F_GREYSCALE; ++ i = 256; /* Return fake indexed-color "map" */ ++ while (--i >= 0) ++ pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i; ++ break; ++ case 3: ++ if (jas_clrspc_isunknown(i = jas_image_clrspc(img))) { ++ SetISTR(ISTR_WARNING, color_space, fbasename); ++ ret = 0; ++ goto done; ++ } ++ if (jas_clrspc_fam(i) != JAS_CLRSPC_FAM_RGB) { ++ jas_image_t *oimg; ++ jas_cmprof_t *profile; + +- do /* each pixel */ +- { register int b; ++ /* Here's where the JasPer Library really shines. The only color ++ space that XV handles is RGB, so if that's not what our image ++ uses, then to quote Capt. Kirk: "Make it so!" ++ */ ++ if (!(profile = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB))) { ++ SetISTR(ISTR_WARNING, "%s: can't create RGB profile", ++ fbasename); ++ ret = 0; ++ goto done; ++ } ++ img = ++ jas_image_chclrspc(oimg = img, profile, JAS_CMXFORM_INTENT_PER); ++ jas_cmprof_destroy(profile); ++ if (!img) /* Oops! We failed, so restore original image */ ++ { ++ img = oimg; ++ SetISTR(ISTR_WARNING, "%s: can't convert to RGB", fbasename); ++ ret = 0; ++ goto done; ++ } ++ jas_image_destroy(oimg); ++ } + +- if ((b = jas_stream_getc(c)) < 0) +- { +- SetISTR(ISTR_WARNING, +- (c->flags_ & JAS_STREAM_EOF) ? truncated : read_err, +- fbasename,jpc_kind); +- goto L1; +- } +- *p = b; +- } +- while ((p += 3),--npix > 0); +- } +- while (++i <= 2); +- } +- ok = 1; /* Success! */ +-L1: jas_image_destroy(img); +-L2: (void)jas_stream_close(str); +- free(iobuf); +-L3: return ok; +-} ++ /* BEWARE OF KLUDGE: If the image's color space is RGB, assume that the ++ data-sample precision for all color planes is the ++ same. If the color space is YCbCr, assume the luminance (Y = 0th) ++ component has the greatest precision, although the chrominance ++ (Cr = 1st, Cb = 2nd) components are usually sub-sampled. ++ */ ++ if ((i = jas_image_cmptprec(img, 0)) != 8) /* not 24-bit pixels */ ++ { ++ SetISTR(ISTR_WARNING, pixel_size, fbasename, i * 3); ++ ret = 0; ++ goto done; ++ } ++ s = "Color"; ++ pinfo->type = PIC24; ++ pinfo->colType = F_FULLCOLOR; + +-int LoadJP2(char *fname,register PICINFO *pinfo,int quick) +-{ +- jas_image_t *img; +- jas_stream_t *str; +- FILE *fp; +- char *iobuf; +- const char *s; +- unsigned long filesize; +- long w, h, npixels, bufsize; +- int ok = 0, vstride; +- register int i; ++ /* XXX Unlike the IJG JPEG Library, the JasPer Library is apparently ++ unable to quantize colors or tell us whether the image's colors ++ were quantized by its creator, so it seems that we can't return a ++ color map for XV to potentially use 8-bit indexed color. If there ++ *is* an easy way to do it that escapes me, put the code here someday. ++ */ ++ } + +- /* Load a JPEG 2000 JP2 image file into a pixel buffer for XV, doing any +- necessary color-space conversion to end up with 8-bit gray scale or 24-bit +- RGB. For now, ignore the "quick" option to return a reduced-resolution +- or -size image. Return 1 on success, or 0 on failure. +- */ +- if (!(fp = xv_fopen(fname,fmode))) return 0; +- fbasename = BaseName(fname); /* Input file's base name, for message(s) */ +- if (!(iobuf = SetBuf(fp))) +- { +- (void)fclose(fp); +- SetISTR(ISTR_WARNING,no_mem,fbasename,jpc_kind); +- goto L3; +- } ++ /* image buffer for XV */ ++ if (!(pinfo->pic = (byte *)malloc(bufsize))) ++ { ++ SetISTR(ISTR_WARNING, no_mem, fbasename, jp2_kind); ++ ret = 0; ++ goto done; ++ } ++ pinfo->frmType = F_JP2; ++ sprintf(pinfo->fullInfo, full_msg, s, jp2_kind, filesize); ++ sprintf(pinfo->shrtInfo, shrt_msg, pinfo->w, pinfo->h, s, jp2_kind); ++ SetISTR(ISTR_INFO, load_msg, pinfo->normw, pinfo->normh, s, jp2_kind, ++ filesize); + +- /* Before telling the JasPer Library about this file, get its size for display +- purposes. Non-UNIX systems don't necessarily simulate "stat(2)", so do it +- crudely but portably by seeking to the end, then back to the beginning. +- */ +- fseek(fp,0L,2); +- filesize = ftell(fp); +- fseek(fp,0L,0); ++ /* Copy the sample data from the JasPer image to the xv image. */ ++ { ++ int num_comps = vstride; ++ int width = w; ++ int height = h; ++ int comp_ind; ++ data = jas_matrix_create(height, width); ++ assert(data); ++ for (comp_ind = 0; comp_ind < num_comps; ++comp_ind) { ++ if (jas_image_readcmpt(img, comp_ind, 0, 0, width, height, data)) { ++ ret = 0; ++ goto done; ++ } ++ unsigned char *buffer; ++ jas_seqent_t *src; ++ unsigned char *dst; ++ int xx, yy; ++ dst = pinfo->pic + comp_ind; ++ for (yy = 0; yy < height; ++yy) { ++ src = jas_matrix_getvref(data, yy); ++ for (xx = 0; xx < width; ++xx) { ++ *dst = *src; ++ ++src; ++ dst += num_comps; ++ } ++ } ++ } ++ } + +- /* "jas_stream_close()" will eventually close the input file, so only do it +- explicitly if no stream can be created: +- */ +- if (!(str = jas_stream_freopen(fname,fmode,fp))) +- { +- (void)fclose(fp); +- goto L3; +- } ++ /* Success! */ ++ ret = 1; + +- /* It's not clear to me whether the following represents a JasPer Library "bug" +- but it sure looks goofy: Unless a stream buffer is marked "read only", +- which only happens when the stream's "fillbuf" method is called, even though +- our buffers are always "read only", the library will try to flush out buffer +- contents when the stream is destroyed, which makes it die a horrible death. +- So, mark the stream buffer proactively: +- */ +- str->bufmode_ |= JAS_STREAM_RDBUF; /* We will only read the stream buffer */ +- if (!(img = jp2_decode(str,0))) goto L2; +- if ((vstride = jas_image_numcmpts(img))) /* num. color planes */ +- { ++done: ++ if (data) { ++ jas_matrix_destroy(data); ++ } ++ if (img) { ++ jas_image_destroy(img); ++ } ++ if (str) { ++ jas_stream_close(str); ++ } ++#if (JAS_VERSION_MAJOR >= 3) ++ jas_cleanup_thread(); ++ jas_cleanup_library(); ++#else ++ jas_cleanup(); ++#endif ++ return ret; ++} + +- /* After the image-component streams created, they are left in a "write" +- state with the streams' cursors positioned at their ends, so "seek" in +- order to "read" each stream from its beginning. +- */ +- i = vstride; +- while (--i >= 0) +- if (jas_stream_seek(img->cmpts_[i]->stream_,0L,0)) +- { +- SetISTR(ISTR_WARNING,read_err,fbasename,jp2_kind); +- goto L1; +- } +- } +- w = jas_image_width(img); +- h = jas_image_height(img); ++int LoadJP2(char *fname, register PICINFO *pinfo, int quick) { ++ return LoadJP2K(fname, pinfo, quick, false); ++} + +- /* avoid buffer overflow */ +- npixels = w * h; +- bufsize = vstride * npixels; +- if (w <= 0 || h <= 0 || npixels/w != h || bufsize/vstride != npixels) +- { +- (void)fclose(fp); +- SetISTR(ISTR_WARNING,bad_dims,fbasename); +- goto L1; +- } +- pinfo->normw = pinfo->w = w; +- pinfo->normh = pinfo->h = h; +- +- /* Sanity-check the image's color space and no. of colors. For now, accept +- only "generic" color spaces, not files needing image-specific color +- correction, but fix that someday... +- */ +- switch (vstride) +- { static char color_space[]={"%s: invalid color space!"}; +- +- default: +- SetISTR(ISTR_WARNING,bad_samp,fbasename,vstride,jp2_kind); +- goto L1; +- case 1: +- if ( !jas_clrspc_isunknown(i = jas_image_clrspc(img)) +- && jas_clrspc_fam(i) != JAS_CLRSPC_FAM_GRAY +- ) +- { +- SetISTR(ISTR_WARNING,color_space,fbasename); +- goto L1; +- } +- if ((i = jas_image_cmptprec(img,0)) != 8) /* not 8-bit pixels */ +- { +- SetISTR(ISTR_WARNING,pixel_size,fbasename,i); +- goto L1; +- } +- s = "Greyscale"; +- pinfo->type = PIC8; +- pinfo->colType = F_GREYSCALE; +- i = 256; /* Return fake indexed-color "map" */ +- while (--i >= 0) pinfo->r[i] = pinfo->g[i] = pinfo->b[i] = i; +- break; +- case 3: +- if (jas_clrspc_isunknown(i = jas_image_clrspc(img))) +- { +- SetISTR(ISTR_WARNING,color_space,fbasename); +- goto L1; +- } +- if (jas_clrspc_fam(i) != JAS_CLRSPC_FAM_RGB) +- { jas_image_t *oimg; +- jas_cmprof_t *profile; +- +- /* Here's where the JasPer Library really shines. The only color +- space that XV handles is RGB, so if that's not what our image +- uses, then to quote Capt. Kirk: "Make it so!" +- */ +- if (!(profile = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB))) +- { +- SetISTR(ISTR_WARNING,"%s: can't create RGB profile", +- fbasename); +- goto L1; +- } +- img = jas_image_chclrspc( oimg = img +- , profile +- , JAS_CMXFORM_INTENT_PER +- ); +- jas_cmprof_destroy(profile); +- if (!img) /* Oops! We failed, so restore original image */ +- { +- img = oimg; +- SetISTR(ISTR_WARNING,"%s: can't convert to RGB",fbasename); +- goto L1; +- } +- jas_image_destroy(oimg); +- } +- +- /* BEWARE OF KLUDGE: If the image's color space is RGB, assume that the +- data-sample precision for all color planes is the +- same. If the color space is YCbCr, assume the luminance (Y = 0th) +- component has the greatest precision, although the chrominance +- (Cr = 1st, Cb = 2nd) components are usually sub-sampled. +- */ +- if ((i = jas_image_cmptprec(img,0)) != 8) /* not 24-bit pixels */ +- { +- SetISTR(ISTR_WARNING,pixel_size,fbasename,i*3); +- goto L1; +- } +- s = "Color"; +- pinfo->type = PIC24; +- pinfo->colType = F_FULLCOLOR; +- +- /* XXX Unlike the IJG JPEG Library, the JasPer Library is apparently +- unable to quantize colors or tell us whether the image's colors +- were quantized by its creator, so it seems that we can't return a +- color map for XV to potentially use 8-bit indexed color. If there +- *is* an easy way to do it that escapes me, put the code here someday. +- */ +- } +- if (!(pinfo->pic = (byte *)malloc(bufsize))) /* image buffer for XV */ +- { +- SetISTR(ISTR_WARNING,no_mem,fbasename,jp2_kind); +- goto L1; +- } +- pinfo->frmType = F_JP2; +- sprintf(pinfo->fullInfo,full_msg,s,jp2_kind,filesize); +- sprintf(pinfo->shrtInfo,shrt_msg,pinfo->w,pinfo->h,s,jp2_kind); +- SetISTR(ISTR_INFO,load_msg,pinfo->normw,pinfo->normh,s,jp2_kind,filesize); +- if (vstride == 1) /* gray-scale image */ +- { register jas_stream_t *c = img->cmpts_[0]->stream_; +- register byte *p = pinfo->pic; +- +- /* Since this is a 1-plane image, avoid a lot of errant nonsense in the +- JasPer Library by sequentially reading all of the data into our buffer +- directly. +- */ +- do if ((i = (*c->ops_->read_)(c->obj_,(char *)p,bufsize)) <= 0) +- { +- SetISTR(ISTR_WARNING,i < 0 ? read_err : truncated,fbasename, +- jp2_kind); +- goto L1; +- } +- while ((p += i),(bufsize -= i) > 0); +- } +- else /* RGB color image */ +- { +- +- /* Reading color images is inefficient because JPEG 2000 wants to partition +- file data into separate image planes (colors), while XV wants data +- samples from each plane to be interleaved as 3-byte pixels. Apparently +- the fastest method consists of 3 passes through the XV image buffer, +- into which we insert the bytes of each component. +- */ +- i = 0; +- do /* each color component */ +- { long npix = npixels; +- register jas_stream_t *c = img->cmpts_[i]->stream_; +- register byte *p = pinfo->pic + i; +- +- do /* each pixel */ +- { register int b; +- +- if ((b = jas_stream_getc(c)) < 0) +- { +- SetISTR(ISTR_WARNING, +- (c->flags_ & JAS_STREAM_EOF) ? truncated : read_err, +- fbasename,jp2_kind); +- goto L1; +- } +- *p = b; +- } +- while ((p += 3),--npix > 0); +- } +- while (++i <= 2); +- } +- ok = 1; /* Success! */ +-L1: jas_image_destroy(img); +-L2: (void)jas_stream_close(str); +- free(iobuf); +-L3: return ok; ++int LoadJPC(char *fname, register PICINFO *pinfo, int quick) { ++ return LoadJP2K(fname, pinfo, quick, true); + } + + /* The following variables and subroutines are used when writing a JPEG 2000 + file, which is done mainly using call-backs from "X Windows" widgets. The + most complicated part of this interface is: managing interactions with a +- window to request the boat-loads of options that the JasPer Library supports. +- Start by defining subwindow sizes, plus indices into several arrays of +- corresponding widget-state variables. ++ window to request the boat-loads of options that the JasPer Library ++ supports. Start by defining subwindow sizes, plus indices into several ++ arrays of corresponding widget-state variables. + + IMPLEMENTATION NOTES: The following dimensions create a tall, thin window +- which appears to have considerable empty space at the ++ which appears to have considerable empty space at the + bottom. Before you complain, click the Precinct Height menu button in order +- to the tall pop-up subwindow that it generates. If the parent window is made +- shorter, then this pop-up will be clipped, which is an ugly nuisance. I ++ to the tall pop-up subwindow that it generates. If the parent window is ++ made shorter, then this pop-up will be clipped, which is an ugly nuisance. I + don't know how to make the pop-up visible outside its parent's borders; do +- you? If there's some way to make "X Windows" do this, then we might consider +- making the parent shorter. ++ you? If there's some way to make "X Windows" do this, then we might ++ consider making the parent shorter. + + Note that there is currently no mechanism to program the no. of intermediate + layers used by the encoder, or their rates. This is potentially a large and + complicated data-entry problem, and perhaps someday we can invent a clever + solution using the rest of the parent window's space. + */ +-# define JP2KW 275 /* Window width, in pixels */ +-# define JP2KH 400 /* Window height, in pixels */ +-# define BUTTW 51 /* Button width, in pixels (odd for half-toning) */ +-# define BUTTH 20 /* Button height, in pixels */ +-# define MENUW 75 /* Menu-button width, in pixels (odd for half-toning) */ +-# define MENUH 24 /* Menu-button height, in pixels */ +-# define RBUTH 20 /* Radio button height, in pixels */ +-# define RBUTW 51 /* Radio button width, in pixels (odd for half-toning) */ +-# define TEXTH (LINEHIGH+5) /* Text subwindow height, in pixels */ +-# define TEXTW 75 /* Text subwindow width, in pixels */ ++#define JP2KW 275 /* Window width, in pixels */ ++#define JP2KH 400 /* Window height, in pixels */ ++#define BUTTW 51 /* Button width, in pixels (odd for half-toning) */ ++#define BUTTH 20 /* Button height, in pixels */ ++#define MENUW 75 /* Menu-button width, in pixels (odd for half-toning) */ ++#define MENUH 24 /* Menu-button height, in pixels */ ++#define RBUTH 20 /* Radio button height, in pixels */ ++#define RBUTW 51 /* Radio button width, in pixels (odd for half-toning) */ ++#define TEXTH (LINEHIGH + 5) /* Text subwindow height, in pixels */ ++#define TEXTW 75 /* Text subwindow width, in pixels */ + +-# define J_BOK 0 /* Boolean "Ok" button */ +-# define J_BCANC 1 /* Boolean "Cancel" button */ +-# define J_NBUTT 2 /* No. of regular button widgets */ ++#define J_BOK 0 /* Boolean "Ok" button */ ++#define J_BCANC 1 /* Boolean "Cancel" button */ ++#define J_NBUTT 2 /* No. of regular button widgets */ + +-# define J_CSOP 0 /* Boolean encoding-style option buttons */ +-# define J_CEPH 1 +-# define J_CLAZY 2 +-# define J_CTERM 3 +-# define J_CSEGS 4 +-# define J_CVCAU 5 +-# define J_CPTRM 6 +-# define J_CRSTP 7 +-# define J_NCHKB 8 /* No. of check-box button widgets */ ++#define J_CSOP 0 /* Boolean encoding-style option buttons */ ++#define J_CEPH 1 ++#define J_CLAZY 2 ++#define J_CTERM 3 ++#define J_CSEGS 4 ++#define J_CVCAU 5 ++#define J_CPTRM 6 ++#define J_CRSTP 7 ++#define J_NCHKB 8 /* No. of check-box button widgets */ + +-# define J_MCBXW 0 /* 1-of-N menu-selection buttons */ +-# define J_MCBXH 1 +-# define J_MPREW 2 +-# define J_MPREH 3 +-# define J_MPROG 4 +-# define J_NMENU 5 /* No. of menu-button widgets */ ++#define J_MCBXW 0 /* 1-of-N menu-selection buttons */ ++#define J_MCBXH 1 ++#define J_MPREW 2 ++#define J_MPREH 3 ++#define J_MPROG 4 ++#define J_NMENU 5 /* No. of menu-button widgets */ + +-# define J_TGBIT 0 /* (Unsigned numeric) string subwindows */ +-# define J_TRES 1 +-# define J_TRATE 2 +-# define J_NTEXT 3 /* No. of text subwindows */ ++#define J_TGBIT 0 /* (Unsigned numeric) string subwindows */ ++#define J_TRES 1 ++#define J_TRATE 2 ++#define J_NTEXT 3 /* No. of text subwindows */ + + static BUTT button[J_NBUTT]; + static CBUTT chkbut[J_NCHKB]; +@@ -642,685 +462,757 @@ + static RBUTT *radio; + static Window text[J_NTEXT]; + static int colorType, format, textval[J_NTEXT]; +-static const char *ProgList[]={"lrcp","rlcp","rpcl","pcrl","cprl"}; ++static const char *ProgList[] = {"lrcp", "rlcp", "rpcl", "pcrl", "cprl"}; + +-void CreateJP2KW(void) +-{ +- static const char EXP2_0[] ={ "1"}, /* Successive powers of 2 */ +- EXP2_1[] ={ "2"}, +- EXP2_2[] ={ "4"}, +- EXP2_3[] ={ "8"}, +- EXP2_4[] ={ "16"}, +- EXP2_5[] ={ "32"}, +- EXP2_6[] ={ "64"}, +- EXP2_7[] ={ "128"}, +- EXP2_8[] ={ "256"}, +- EXP2_9[] ={ "512"}, +- EXP2_10[]={ "1024"}, +- EXP2_11[]={ "2048"}, +- EXP2_12[]={ "4096"}, +- EXP2_13[]={ "8192"}, +- EXP2_14[]={"16384"}, +- EXP2_15[]={"32768"}; +- static const char *CBoxList[]= +- { +- EXP2_1 ,EXP2_2 ,EXP2_3 ,EXP2_4 ,EXP2_5,EXP2_6 ,EXP2_7 ,EXP2_8 ,EXP2_9, +- EXP2_10,EXP2_11 +- }; +- static const char *PrecList[]= +- { +- EXP2_0,EXP2_1,EXP2_2 ,EXP2_3 ,EXP2_4 ,EXP2_5 ,EXP2_6 ,EXP2_7 , +- EXP2_8,EXP2_9,EXP2_10,EXP2_11,EXP2_12,EXP2_13,EXP2_14,EXP2_15 +- }; +- static const char hstr[]={"Height"}, wstr[]={"Width"}; ++void CreateJP2KW(void) { ++ static const char EXP2_0[] = {"1"}, /* Successive powers of 2 */ ++ EXP2_1[] = {"2"}, EXP2_2[] = {"4"}, EXP2_3[] = {"8"}, EXP2_4[] = {"16"}, ++ EXP2_5[] = {"32"}, EXP2_6[] = {"64"}, EXP2_7[] = {"128"}, ++ EXP2_8[] = {"256"}, EXP2_9[] = {"512"}, ++ EXP2_10[] = {"1024"}, EXP2_11[] = {"2048"}, ++ EXP2_12[] = {"4096"}, EXP2_13[] = {"8192"}, ++ EXP2_14[] = {"16384"}, EXP2_15[] = {"32768"}; ++ static const char *CBoxList[] = {EXP2_1, EXP2_2, EXP2_3, EXP2_4, ++ EXP2_5, EXP2_6, EXP2_7, EXP2_8, ++ EXP2_9, EXP2_10, EXP2_11}; ++ static const char *PrecList[] = { ++ EXP2_0, EXP2_1, EXP2_2, EXP2_3, EXP2_4, EXP2_5, EXP2_6, EXP2_7, ++ EXP2_8, EXP2_9, EXP2_10, EXP2_11, EXP2_12, EXP2_13, EXP2_14, EXP2_15}; ++ static const char hstr[] = {"Height"}, wstr[] = {"Width"}; + +- if (!(jp2kW = CreateWindow( "xvjp2k" +- , "XVjp2k" +- , 0 +- , JP2KW +- , JP2KH +- , infofg +- , infobg +- , 0 +- ) +- ) +- ) FatalError("can't create JPEG 2000 window!"); +- XSelectInput(theDisp,jp2kW,ExposureMask|ButtonPressMask|KeyPressMask); ++ if (!(jp2kW = CreateWindow("xvjp2k", "XVjp2k", 0, JP2KW, JP2KH, infofg, ++ infobg, 0))) ++ FatalError("can't create JPEG 2000 window!"); ++ XSelectInput(theDisp, jp2kW, ExposureMask | ButtonPressMask | KeyPressMask); + +- /* Create a row of 2 boolean-valued, regular buttons ("Ok" and "Cancel") in the +- window's bottom right corner. +- */ +- BTCreate(&button[J_BOK ],jp2kW, +- JP2KW-2*BUTTW-20,JP2KH-10-BUTTH-1,BUTTW,BUTTH, +- "Ok" ,infofg,infobg,hicol,locol); +- BTCreate(&button[J_BCANC],jp2kW, +- JP2KW- BUTTW-10,JP2KH-10-BUTTH-1,BUTTW,BUTTH, +- "Cancel",infofg,infobg,hicol,locol); ++ /* Create a row of 2 boolean-valued, regular buttons ("Ok" and "Cancel") in ++ the window's bottom right corner. ++ */ ++ BTCreate(&button[J_BOK], jp2kW, JP2KW - 2 * BUTTW - 20, ++ JP2KH - 10 - BUTTH - 1, BUTTW, BUTTH, "Ok", infofg, infobg, hicol, ++ locol); ++ BTCreate(&button[J_BCANC], jp2kW, JP2KW - BUTTW - 10, ++ JP2KH - 10 - BUTTH - 1, BUTTW, BUTTH, "Cancel", infofg, infobg, ++ hicol, locol); + +- /* Create a vertical column of 8 boolean-valued, check-box buttons (for +- encoding-style options) down the window's left side. +- */ +- CBCreate(&chkbut[J_CSOP] ,jp2kW, +- 10,10+ASCENT+SPACING+2*LINEHIGH+0*BUTTH, +- "sop" ,infofg,infobg,hicol,locol); +- CBCreate(&chkbut[J_CEPH] ,jp2kW, +- 10,10+ASCENT+SPACING+2*LINEHIGH+1*BUTTH, +- "eph" ,infofg,infobg,hicol,locol); +- CBCreate(&chkbut[J_CLAZY],jp2kW, +- 10,10+ASCENT+SPACING+2*LINEHIGH+2*BUTTH, +- "lazy" ,infofg,infobg,hicol,locol); +- CBCreate(&chkbut[J_CTERM],jp2kW, +- 10,10+ASCENT+SPACING+2*LINEHIGH+3*BUTTH, +- "termall" ,infofg,infobg,hicol,locol); +- CBCreate(&chkbut[J_CSEGS],jp2kW, +- 10,10+ASCENT+SPACING+2*LINEHIGH+4*BUTTH, +- "segsym" ,infofg,infobg,hicol,locol); +- CBCreate(&chkbut[J_CVCAU],jp2kW, +- 10,10+ASCENT+SPACING+2*LINEHIGH+5*BUTTH, +- "vcausal" ,infofg,infobg,hicol,locol); +- CBCreate(&chkbut[J_CPTRM],jp2kW, +- 10,10+ASCENT+SPACING+2*LINEHIGH+6*BUTTH, +- "pterm" ,infofg,infobg,hicol,locol); +- CBCreate(&chkbut[J_CRSTP],jp2kW, +- 10,10+ASCENT+SPACING+2*LINEHIGH+7*BUTTH, +- "resetprob",infofg,infobg,hicol,locol); +- /* Create text subwindows for unsigned decimal integer values. */ ++ /* Create a vertical column of 8 boolean-valued, check-box buttons (for ++ encoding-style options) down the window's left side. ++ */ ++ CBCreate(&chkbut[J_CSOP], jp2kW, 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 0 * BUTTH, "sop", infofg, ++ infobg, hicol, locol); ++ CBCreate(&chkbut[J_CEPH], jp2kW, 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 1 * BUTTH, "eph", infofg, ++ infobg, hicol, locol); ++ CBCreate(&chkbut[J_CLAZY], jp2kW, 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 2 * BUTTH, "lazy", infofg, ++ infobg, hicol, locol); ++ CBCreate(&chkbut[J_CTERM], jp2kW, 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 3 * BUTTH, "termall", ++ infofg, infobg, hicol, locol); ++ CBCreate(&chkbut[J_CSEGS], jp2kW, 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 4 * BUTTH, "segsym", infofg, ++ infobg, hicol, locol); ++ CBCreate(&chkbut[J_CVCAU], jp2kW, 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 5 * BUTTH, "vcausal", ++ infofg, infobg, hicol, locol); ++ CBCreate(&chkbut[J_CPTRM], jp2kW, 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 6 * BUTTH, "pterm", infofg, ++ infobg, hicol, locol); ++ CBCreate(&chkbut[J_CRSTP], jp2kW, 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 7 * BUTTH, "resetprob", ++ infofg, infobg, hicol, locol); ++ /* Create text subwindows for unsigned decimal integer values. */ + +- text[J_TGBIT] = XCreateSimpleWindow(theDisp,jp2kW, +- JP2KW-TEXTW-10,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+0*TEXTH,TEXTW,TEXTH, +- 1,infofg,infobg); +- XSelectInput(theDisp,text[J_TGBIT],ExposureMask|KeyPressMask); +- text[J_TRES ] = XCreateSimpleWindow(theDisp,jp2kW, +- JP2KW-TEXTW-10,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+1*TEXTH,TEXTW,TEXTH, +- 1,infofg,infobg); +- XSelectInput(theDisp,text[J_TRES ],ExposureMask|KeyPressMask); +- text[J_TRATE] = XCreateSimpleWindow(theDisp,jp2kW, +- JP2KW-TEXTW-10,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+2*TEXTH,TEXTW,TEXTH, +- 1,infofg,infobg); +- XSelectInput(theDisp,text[J_TRATE],ExposureMask|KeyPressMask); ++ text[J_TGBIT] = XCreateSimpleWindow(theDisp, jp2kW, JP2KW - TEXTW - 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + ++ 3 * MENUH + 0 * TEXTH, ++ TEXTW, TEXTH, 1, infofg, infobg); ++ XSelectInput(theDisp, text[J_TGBIT], ExposureMask | KeyPressMask); ++ text[J_TRES] = XCreateSimpleWindow(theDisp, jp2kW, JP2KW - TEXTW - 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + ++ 3 * MENUH + 1 * TEXTH, ++ TEXTW, TEXTH, 1, infofg, infobg); ++ XSelectInput(theDisp, text[J_TRES], ExposureMask | KeyPressMask); ++ text[J_TRATE] = XCreateSimpleWindow(theDisp, jp2kW, JP2KW - TEXTW - 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + ++ 3 * MENUH + 2 * TEXTH, ++ TEXTW, TEXTH, 1, infofg, infobg); ++ XSelectInput(theDisp, text[J_TRATE], ExposureMask | KeyPressMask); + +- /* Create a row of 2 boolean-valued radio buttons (for the "Rate" subwindow +- value's unit of measure). The 1st button is "selected" by default. +- */ +- radio = RBCreate(0,jp2kW, +- JP2KW-19*RBUTW/8-10,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+3*TEXTH+4, +- "Percent",infofg,infobg,hicol,locol); +- (void)RBCreate(radio,jp2kW, +- JP2KW-1*RBUTW-10 ,10+ASCENT+SPACING+2*LINEHIGH+3*MENUH+3*TEXTH+4, +- "Bytes",infofg,infobg,hicol,locol); ++ /* Create a row of 2 boolean-valued radio buttons (for the "Rate" subwindow ++ value's unit of measure). The 1st button is "selected" by default. ++ */ ++ radio = RBCreate(0, jp2kW, JP2KW - 19 * RBUTW / 8 - 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 3 * MENUH + ++ 3 * TEXTH + 4, ++ "Percent", infofg, infobg, hicol, locol); ++ (void)RBCreate(radio, jp2kW, JP2KW - 1 * RBUTW - 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 3 * MENUH + ++ 3 * TEXTH + 4, ++ "Bytes", infofg, infobg, hicol, locol); + +- /* Create pop-up menu-selection buttons after mapping the above subwindows, +- since we don't want the pop-up menus mapped unless the corresponding button +- is selected. +- */ +- XMapSubwindows(theDisp,jp2kW); +- MBCreate(&menu[J_MCBXW],jp2kW, +- JP2KW-2*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+0*MENUH,MENUW,MENUH, +- wstr ,CBoxList,sizeof CBoxList/sizeof *CBoxList,infofg,infobg, +- hicol,locol); +- MBCreate(&menu[J_MCBXH],jp2kW, +- JP2KW-2*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+1*MENUH,MENUW,MENUH, +- hstr ,CBoxList,sizeof CBoxList/sizeof *CBoxList,infofg,infobg, +- hicol,locol); +- MBCreate(&menu[J_MPREW],jp2kW, +- JP2KW-1*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+0*MENUH,MENUW,MENUH, +- wstr ,PrecList,sizeof PrecList/sizeof *PrecList,infofg,infobg, +- hicol,locol); +- MBCreate(&menu[J_MPREH],jp2kW, +- JP2KW-1*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+1*MENUH,MENUW,MENUH, +- hstr ,PrecList,sizeof PrecList/sizeof *PrecList,infofg,infobg, +- hicol,locol); +- MBCreate(&menu[J_MPROG],jp2kW, +- JP2KW-1*MENUW-10,10+ASCENT+SPACING+2*LINEHIGH+2*MENUH,MENUW,MENUH, +- "Order",ProgList,sizeof ProgList/sizeof *ProgList,infofg,infobg, +- hicol,locol); ++ /* Create pop-up menu-selection buttons after mapping the above subwindows, ++ since we don't want the pop-up menus mapped unless the corresponding ++ button is selected. ++ */ ++ XMapSubwindows(theDisp, jp2kW); ++ MBCreate(&menu[J_MCBXW], jp2kW, JP2KW - 2 * MENUW - 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 0 * MENUH, MENUW, MENUH, ++ wstr, CBoxList, sizeof CBoxList / sizeof *CBoxList, infofg, infobg, ++ hicol, locol); ++ MBCreate(&menu[J_MCBXH], jp2kW, JP2KW - 2 * MENUW - 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 1 * MENUH, MENUW, MENUH, ++ hstr, CBoxList, sizeof CBoxList / sizeof *CBoxList, infofg, infobg, ++ hicol, locol); ++ MBCreate(&menu[J_MPREW], jp2kW, JP2KW - 1 * MENUW - 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 0 * MENUH, MENUW, MENUH, ++ wstr, PrecList, sizeof PrecList / sizeof *PrecList, infofg, infobg, ++ hicol, locol); ++ MBCreate(&menu[J_MPREH], jp2kW, JP2KW - 1 * MENUW - 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 1 * MENUH, MENUW, MENUH, ++ hstr, PrecList, sizeof PrecList / sizeof *PrecList, infofg, infobg, ++ hicol, locol); ++ MBCreate(&menu[J_MPROG], jp2kW, JP2KW - 1 * MENUW - 10, ++ 10 + ASCENT + SPACING + 2 * LINEHIGH + 2 * MENUH, MENUW, MENUH, ++ "Order", ProgList, sizeof ProgList / sizeof *ProgList, infofg, ++ infobg, hicol, locol); + +- /* Initialize values represented by widgets, which should correspond to default +- compiled into the JasPer Library. Unfortunately, as of Version 1.701 there +- is no easy way for an application to extract these from the library, so the +- following code might get out of sync over time: +- */ +- menu[J_MCBXW].hascheck = 1; menu[J_MCBXW].flags[ 5] = 1; +- menu[J_MCBXH].hascheck = 1; menu[J_MCBXH].flags[ 5] = 1; +- menu[J_MPREW].hascheck = 1; menu[J_MPREW].flags[15] = 1; +- menu[J_MPREH].hascheck = 1; menu[J_MPREH].flags[15] = 1; +- menu[J_MPROG].hascheck = 1; menu[J_MPROG].flags[ 0] = 1; +- textval[J_TGBIT] = 2; /* No. of guard bits */ +- textval[J_TRES ] = 6; /* Max. no. of resolution levels */ +- textval[J_TRATE] = 100; /* Rate = 100% */ ++ /* Initialize values represented by widgets, which should correspond to ++ default compiled into the JasPer Library. Unfortunately, as of ++ Version 1.701 there is no easy way for an application to extract these ++ from the library, so the following code might get out of sync over time: ++ */ ++ menu[J_MCBXW].hascheck = 1; ++ menu[J_MCBXW].flags[5] = 1; ++ menu[J_MCBXH].hascheck = 1; ++ menu[J_MCBXH].flags[5] = 1; ++ menu[J_MPREW].hascheck = 1; ++ menu[J_MPREW].flags[15] = 1; ++ menu[J_MPREH].hascheck = 1; ++ menu[J_MPREH].flags[15] = 1; ++ menu[J_MPROG].hascheck = 1; ++ menu[J_MPROG].flags[0] = 1; ++ textval[J_TGBIT] = 2; /* No. of guard bits */ ++ textval[J_TRES] = 6; /* Max. no. of resolution levels */ ++ textval[J_TRATE] = 100; /* Rate = 100% */ + } + +-void JP2KSaveParams(int fmt,char *fname,int col) /* Save output-file parms */ ++void JP2KSaveParams(int fmt, char *fname, int col) /* Save output-file parms */ + { +- format = fmt; /* Desired file format: F_JPC|F_JP2 */ +- fbasename = fname; /* ->Output file path */ +- colorType = col; /* Desired color space: F_GREYSCALE|... */ ++ format = fmt; /* Desired file format: F_JPC|F_JP2 */ ++ fbasename = fname; /* ->Output file path */ ++ colorType = col; /* Desired color space: F_GREYSCALE|... */ + } + +-static void StoreJP2K(char *options) +-{ +- static jas_image_cmptparm_t parm[3]= /* Image parameters */ +- {{0,0,1,1,0,0,8,0},{0,0,1,1,0,0,8,0},{0,0,1,1,0,0,8,0}}; +- static char nomem[]={"StoreJP2K: out of memory\n"}, +- write[]={"w"}; +- jas_image_t *img; +- jas_stream_t *str; +- FILE *fp, *fp2; +- byte *pic, *r, *g, *b; +- const char *filename; +- char *iobuf = 0; +- unsigned long imagesize; +- jas_clrspc_t color_space; +- int nc, w, h, pfree, ptype, error = 1; +- register int i; ++static void StoreJP2K(char *options) { ++ static jas_image_cmptparm_t parm[3] = /* Image parameters */ ++ {{0, 0, 1, 1, 0, 0, 8, 0}, ++ {0, 0, 1, 1, 0, 0, 8, 0}, ++ {0, 0, 1, 1, 0, 0, 8, 0}}; ++ static char nomem[] = {"StoreJP2K: out of memory\n"}, write[] = {"w"}; ++ jas_image_t *img = 0; ++ jas_stream_t *str = 0; ++ FILE *fp = 0; ++ FILE *fp2 = 0; ++ byte *pic, *r, *g, *b; ++ const char *filename; ++ unsigned long imagesize; ++ jas_clrspc_t color_space; ++ int nc, w, h; ++ int pfree, ptype; ++ int error = 1; ++ register int i; ++ jas_matrix_t *data = 0; ++ int debug_level = get_debug_level(); + +- /* This is a generic subroutine for writing JPEG 2000 image files using the +- JasPer Library. Our argument is an ASCII string, containing a Space (" ")- +- separated sequence of encoder options that currently aren't well documented. +- Most of the work is identical for both ".jpc" and ".jp2" files. Start by +- verifying that the output file can be opened, then get an image buffer from +- XV and begin crunching it into a suitable form for the JasPer Library. +- */ +- if (!(fp = OpenOutFile(filename = fbasename))) return; /* Oops! */ +- setbuf(fp,0); /* We don't really use this file pointer for I/O; see below */ +- fbasename = BaseName(filename); +- WaitCursor(); +- pic = GenSavePic(&ptype,&w,&h,&pfree,&nc,&r,&g,&b); +- imagesize = w*h; +- if (ptype == PIC24) imagesize *= 3; ++#if (JAS_VERSION_MAJOR >= 3) ++ size_t max_mem = jas_get_total_mem_size(); ++ if (!max_mem) { ++ max_mem = GIBI; ++ } ++ jas_conf_clear(); ++ jas_conf_set_max_mem_usage(max_mem); ++ jas_init_library(); ++ jas_init_thread(); ++ jas_set_vlogmsgf(print_log); ++ jas_set_debug_level(debug_level); ++#else ++ jas_init(); ++ jas_setdbglevel(debug_level); ++#endif + +- /* As an optimization to save file space, even if our user didn't ask to store +- a gray-scale image, check whether we could and, if so, do it anyway. +- */ +- if (colorType != F_GREYSCALE) /* can we force a gray-scale image? */ +- { +- if (ptype == PIC8) +- { +- i = nc; +- while (--i >= 0 && r[i] == g[i] && r[i] == b[i]); +- } +- else /* PIC24 */ +- { register byte *p = pic + imagesize; ++ /* This is a generic subroutine for writing JPEG 2000 image files using the ++ JasPer Library. Our argument is an ASCII string, containing a Space (" ++ ")- separated sequence of encoder options that currently aren't well ++ documented. Most of the work is identical for both ".jpc" and ".jp2" ++ files. Start by verifying that the output file can be opened, then get an ++ image buffer from XV and begin crunching it into a suitable form for the ++ JasPer Library. ++ */ ++ if (!(fp = OpenOutFile(filename = fbasename))) ++ return; /* Oops! */ ++ setbuf(fp, ++ 0); /* We don't really use this file pointer for I/O; see below */ ++ fbasename = BaseName(filename); ++ WaitCursor(); ++ pic = GenSavePic(&ptype, &w, &h, &pfree, &nc, &r, &g, &b); ++ assert(ptype == PIC8 || ptype == PIC24); ++ imagesize = w * h; ++ if (ptype == PIC24) ++ imagesize *= 3; + +- while ((p -= 3) >= pic && p[0] == p[1] && p[0] == p[2]); +- i = p-pic; +- }; +- if (i < 0) colorType = F_GREYSCALE; /* We made it all the way through */ +- }; ++ assert(colorType == F_GREYSCALE || colorType == F_FULLCOLOR); ++#if 1 ++ /* As an optimization to save file space, even if our user didn't ask to ++ store a gray-scale image, check whether we could and, if so, do it ++ anyway. ++ */ ++ if (colorType != F_GREYSCALE) /* can we force a gray-scale image? */ ++ { ++ if (ptype == PIC8) { ++ i = nc; ++ while (--i >= 0 && r[i] == g[i] && r[i] == b[i]) {} ++ } else { ++ assert(ptype == PIC24); ++ /* PIC24 */ ++ byte *p = pic + imagesize; ++ while ((p -= 3) >= pic && p[0] == p[1] && p[0] == p[2]) {} ++ i = p - pic; ++ }; ++ if (i < 0) { ++ colorType = F_GREYSCALE; /* We made it all the way through */ ++ } ++ }; ++#endif + +- /* If XV is currently color-mapping the image, make a color-mapped copy so that +- the map needn't be transmitted in the output file. +- */ +- if ((i = (colorType != F_GREYSCALE) << 1 | (ptype != PIC8)) != 3) +- { byte *tmp = pic, *last = pic + imagesize; +- register byte *from = tmp, *to = pic; ++ /* Now comes a egregious hack: The JasPer Library will eventually want to ++ close the output file that it writes, but since XV opened the file, XV ++ also thinks it has the right to close the file! In order to pacify them ++ both, we duplicate the file pointer and let the JasPer Library have it, ++ while we retain the original for XV. + +- if (!(pic = (byte *)malloc(imagesize))) FatalError(nomem); +- switch (i) +- { ++ XXX This code is very UNIX-specific; what's an equivalent hack for ++ Windows? ++ */ ++ { ++ int fd = dup(fileno(fp)); ++ if (fd < 0) { ++ FatalError("StoreJP2K: can't duplicate output file pointer\n"); ++ } ++ if (!(fp2 = fdopen(fd, write))) { ++ FatalError("StoreJP2K: can't duplicate output file pointer\n"); ++ } ++ } + +- /* Color-map 8->8 bit image. */ ++ /* Hand our output file to the JasPer Library and create an image object. ++ "jas_stream_close()" will eventually close our output file, so only do it ++ explicitly if no stream can be created. If everything looks copacetic, ++ then write our buffer contents to the image components' streams. ++ */ ++ if (!(str = jas_stream_freopen(filename, write, fp2))) { ++ (void)fclose(fp2); ++ FatalError("StoreJP2K: can't open output stream\n"); ++ }; ++ fp2 = 0; + +- case 0: do +- { +- i = *from; +- *to++ = MONO(r[i],g[i],b[i]); +- } +- while (++from < last); +- break; ++ int num_comps = (colorType == F_GREYSCALE) ? 1 : 3; ++ int comp_ind; ++ if (num_comps == 3) { ++ color_space = JAS_CLRSPC_SRGB; ++ } else { ++ color_space = JAS_CLRSPC_SGRAY; ++ } ++ for (comp_ind = 0; comp_ind < num_comps; ++comp_ind) { ++ parm[comp_ind].tlx = 0; ++ parm[comp_ind].tly = 0; ++ parm[comp_ind].hstep = 1; ++ parm[comp_ind].vstep = 1; ++ parm[comp_ind].width = w; ++ parm[comp_ind].height = h; ++ parm[comp_ind].prec = 8; ++ parm[comp_ind].sgnd = 0; ++ } ++ if (!(img = jas_image_create(num_comps, parm, color_space))) { ++ goto L2; ++ } ++ if (get_debug_level() >= 1) { ++ fprintf(stderr, "num_comps %d width %d height %d\n", num_comps, w, h); ++ fprintf(stderr, "colorType %d\n", colorType); ++ fprintf(stderr, "ptype %d\n", ptype); ++ } + +- /* Color-map 24->8 bit image. */ ++ { ++ int comp_ind; ++ if (!(data = jas_matrix_create(h, w))) { ++ goto done; ++ } ++ if (num_comps == 3) { ++ for (comp_ind = 0; comp_ind < num_comps; ++comp_ind) { ++ int comp_type; ++ switch (comp_ind) { ++ case 0: ++ comp_type = JAS_IMAGE_CT_RGB_R; ++ break; ++ case 1: ++ comp_type = JAS_IMAGE_CT_RGB_G; ++ break; ++ case 2: ++ comp_type = JAS_IMAGE_CT_RGB_B; ++ break; ++ } ++ jas_image_setcmpttype(img, comp_ind, comp_type); ++ unsigned char *buffer; ++ unsigned char *src; ++ jas_seqent_t *dst; ++ int x, y; ++ src = pic + comp_ind; ++ for (y = 0; y < h; ++y) { ++ dst = jas_matrix_getvref(data, y); ++ for (x = 0; x < w; ++x) { ++ *dst = *src; ++ ++dst; ++ src += num_comps; ++ } ++ } ++ if (jas_image_writecmpt(img, comp_ind, 0, 0, w, h, data)) { ++ goto L1; ++ } ++ } ++ } else { ++ int mode = (ptype == PIC8) ? 0 : 1; ++ assert(num_comps == 1); ++ jas_image_setcmpttype(img, 0, JAS_IMAGE_CT_GRAY_Y); ++ unsigned char *buffer; ++ unsigned char *src; ++ jas_seqent_t *dst; ++ int x, y; ++ src = pic; ++ for (y = 0; y < h; ++y) { ++ dst = jas_matrix_getvref(data, y); ++ for (x = 0; x < w; ++x) { ++ int v; ++ if (mode == 0) { ++ v = *src; ++ v = MONO(r[v], g[v], b[v]); ++ } else if (mode == 1) { ++ v = MONO(src[0], src[1], src[2]); ++ } ++ *dst = v; ++ ++dst; ++ ++src; ++ } ++ } ++ if (jas_image_writecmpt(img, 0, 0, 0, w, h, data)) { ++ goto L1; ++ } ++ } ++ } + +- case 1: do *to++ = MONO(from[0],from[1],from[2]); +- while ((from += 3) < last); +- break; ++ const jas_image_fmtinfo_t *fmtinfo = ++ jas_image_lookupfmtbyname(((format == F_JPC) ? "jpc" : "jp2")); ++ if (!jas_image_encode(img, str, fmtinfo->id, options) && ++ jas_stream_flush(str) >= 0) { ++ error = 0; /* Success! */ ++ } + +- /* Color-map 8->24 bit image. */ ++done: ++ if (data) { ++ jas_matrix_destroy(data); ++ } ++L1: ++ if (img) { ++ jas_image_destroy(img); ++ } ++L2: ++ if (str) { ++ jas_stream_close(str); ++ } ++ if (pfree) { ++ free(pic); ++ } ++ if (!CloseOutFile(fp, filename, error)) { ++ DirBox(0); ++ } ++ SetCursors(-1); + +- case 2: do +- { +- i = *from; +- *to++ = r[i]; *to++ = g[i]; *to++ = b[i]; +- } +- while (++from < last); +- break; +- }; +- if (pfree) free(tmp); /* Release the original image buffer if we can */ +- pfree = 1; /* Let the modified buffer be released later */ +- }; +- +- /* Initialize various image-file parameter variables. */ +- +- parm[0].width = w; +- parm[0].height = h; +- if (colorType == F_GREYSCALE) /* gray-scale image */ +- { +- ptype = 1; /* No. of color planes */ +- color_space = JAS_CLRSPC_SGRAY; +- } +- else /* RGB color image */ +- { +- ptype = 3; /* No. of color planes */ +- color_space = JAS_CLRSPC_SRGB; +- parm[2].width = parm[1].width = parm[0].width; +- parm[2].height = parm[1].height = parm[0].height; +- }; +- +- /* Now comes a egregious hack: The JasPer Library will eventually want to +- close the output file that it writes, but since XV opened the file, XV also +- thinks it has the right to close the file! In order to pacify them both, +- we duplicate the file pointer and let the JasPer Library have it, while we +- retain the original for XV. +- +- XXX This code is very UNIX-specific; what's an equivalent hack for Windows? +- */ +- if (!(fp2 = (i = dup(fileno(fp))) >= 0 ? fdopen(i,write) : 0)) +- FatalError("StoreJP2K: can't duplicate output file pointer\n"); +- if (!(iobuf = SetBuf(fp2))) +- { +- (void)fclose(fp2); +- FatalError(nomem); +- }; +- +- /* Hand our output file to the JasPer Library and create an image object. +- "jas_stream_close()" will eventually close our output file, so only do it +- explicitly if no stream can be created. If everything looks copacetic, +- then write our buffer contents to the image components' streams. +- */ +- if (!(str = jas_stream_freopen(filename,write,fp2))) +- { +- (void)fclose(fp2); +- FatalError("StoreJP2K: can't open output stream\n"); +- }; +- if (!(img = jas_image_create(ptype,parm,color_space))) goto L2; +- if (ptype == 1) +- { register jas_stream_t *c = img->cmpts_[0]->stream_; +- register byte *p = pic; +- +- /* Since this is a 1-plane image, avoid a lot of errant nonsense in the +- JasPer Library by sequentially writing all of the data directly from our +- buffer. +- */ +- jas_image_setcmpttype(img,0,JAS_IMAGE_CT_GRAY_Y); +- img->cmpts_[0]->type_ = JAS_IMAGE_CT_GRAY_Y; +- do if ((i = (*c->ops_->write_)(c->obj_,(char *)p,imagesize)) <= 0) +- goto L1; +- while ((p += i),(imagesize -= i) > 0); +- if (jas_stream_flush(c) < 0) goto L1; +- } +- else /* RGB color image */ +- { +- +- /* Writing color images is inefficient because JPEG 2000 wants to partition +- file data into separate image planes (colors), while XV wants data +- samples from each plane to be interleaved as 3-byte pixels. Apparently +- the fastest method consists of 3 passes through the XV image buffer, +- from which we extract the bytes of each component. +- */ +- i = 0; +- do /* each color component */ +- { long npix = imagesize/3; +- register jas_stream_t *c = img->cmpts_[i]->stream_; +- register byte *p = pic + i; +- +- jas_image_setcmpttype(img,i,i+JAS_IMAGE_CT_RGB_R); +- do if (jas_stream_putc(c,*p) < 0) goto L1; +- while ((p += 3),--npix > 0); +- if (jas_stream_flush(c) < 0) goto L1; +- } +- while (++i <= 2); +- }; +- if ( (*(format == F_JPC ? jpc_encode : jp2_encode))(img,str,options) >= 0 +- && jas_stream_flush(str) >= 0 +- ) error = 0; /* Success! */ +-L1: jas_image_destroy(img); +-L2: (void)jas_stream_close(str); +- if (iobuf) free(iobuf); +- if (pfree) free(pic); +- if (!CloseOutFile(fp,filename,error)) DirBox(0); +- SetCursors(-1); ++#if (JAS_VERSION_MAJOR >= 3) ++ jas_cleanup_thread(); ++ jas_cleanup_library(); ++#else ++ jas_cleanup(); ++#endif + } + +-void JP2KDialog(int vis) +-{ +- if ((jp2kUp = vis)) CenterMapWindow(jp2kW,0,0,JP2KW,JP2KH); +- else XUnmapWindow(theDisp,jp2kW); ++void JP2KDialog(int vis) { ++ if ((jp2kUp = vis)) ++ CenterMapWindow(jp2kW, 0, 0, JP2KW, JP2KH); ++ else ++ XUnmapWindow(theDisp, jp2kW); + } + +-static void TWRedraw(Window w,unsigned int val) +-{ +- char buf[11]; +- register int i; ++static void TWRedraw(Window w, unsigned int val) { ++ char buf[11]; ++ register int i; + +- /* Draw a 1-line numeric text string in the specified window, representing the +- argument value as a left-justified unsigned decimal integer, followed by a +- "cursor" icon. +- */ +- sprintf(buf,"%u",val); +- if (ctrlColor) XClearArea(theDisp,w,2,2,TEXTW-4,TEXTH-4,False); +- else XClearWindow(theDisp,w); +- Draw3dRect(w,0,0,TEXTW-1,TEXTH-1,R3D_IN,2,hicol,locol,infobg); +- XSetForeground(theDisp,theGC,infofg); +- XDrawString(theDisp,w,theGC,3,ASCENT+3,buf,i = strlen(buf)); ++ /* Draw a 1-line numeric text string in the specified window, representing ++ the argument value as a left-justified unsigned decimal integer, followed ++ by a "cursor" icon. ++ */ ++ sprintf(buf, "%u", val); ++ if (ctrlColor) ++ XClearArea(theDisp, w, 2, 2, TEXTW - 4, TEXTH - 4, False); ++ else ++ XClearWindow(theDisp, w); ++ Draw3dRect(w, 0, 0, TEXTW - 1, TEXTH - 1, R3D_IN, 2, hicol, locol, infobg); ++ XSetForeground(theDisp, theGC, infofg); ++ XDrawString(theDisp, w, theGC, 3, ASCENT + 3, buf, i = strlen(buf)); + +- /* Draw a "cursor" icon after the numeric string. */ ++ /* Draw a "cursor" icon after the numeric string. */ + +- i = XTextWidth(mfinfo,buf,i); +- XDrawLine(theDisp,w,theGC,i+3,2 ,i+3,2+CHIGH+1); +- XDrawLine(theDisp,w,theGC,i+3,2+CHIGH+1,i+5,2+CHIGH+3); +- XDrawLine(theDisp,w,theGC,i+3,2+CHIGH+1,i+1,2+CHIGH+3); ++ i = XTextWidth(mfinfo, buf, i); ++ XDrawLine(theDisp, w, theGC, i + 3, 2, i + 3, 2 + CHIGH + 1); ++ XDrawLine(theDisp, w, theGC, i + 3, 2 + CHIGH + 1, i + 5, 2 + CHIGH + 3); ++ XDrawLine(theDisp, w, theGC, i + 3, 2 + CHIGH + 1, i + 1, 2 + CHIGH + 3); + } + +-int JP2KCheckEvent(register XEvent *xev) +-{ +- int ok = 0; ++int JP2KCheckEvent(register XEvent *xev) { ++ int ok = 0; + +- /* Check whether the argument "X Windows" event is for one of our subwindows. +- If it is, handle the event and return 1; otherwise, return 0. +- */ +- if (!jp2kUp) return 0; +- switch (xev->type) +- { KeySym ks; +- int len; +- char buf[128]; +- register int i; ++ /* Check whether the argument "X Windows" event is for one of our ++ subwindows. If it is, handle the event and return 1; otherwise, return 0. ++ */ ++ if (!jp2kUp) ++ return 0; ++ switch (xev->type) { ++ KeySym ks; ++ int len; ++ char buf[128]; ++ register int i; + +- /* Throw away excess "expose" events for "dumb" windows. */ ++ /* Throw away excess "expose" events for "dumb" windows. */ + +- case Expose : +-# define E ((XExposeEvent *)xev) +- if (E->window == jp2kW) +- { XRectangle rect; ++ case Expose: ++#define E ((XExposeEvent *)xev) ++ if (E->window == jp2kW) { ++ XRectangle rect; + +- rect.x = E->x ; rect.y = E->y ; +- rect.width = E->width; rect.height = E->height; +- XSetClipRectangles(theDisp,theGC,0,0,&rect,1,Unsorted); +- XSetForeground(theDisp,theGC,infofg); +- XSetBackground(theDisp,theGC,infobg); +- i = sizeof button/sizeof *button; +- while (--i >= 0) BTRedraw(&button[i]); +- i = sizeof chkbut/sizeof *chkbut; +- while (--i >= 0) CBRedraw(&chkbut[i]); +- i = sizeof menu/sizeof *menu; +- while (--i >= 0) MBRedraw(&menu[i]); +- RBRedraw(radio,-1); +- DrawString(jp2kW,10,10+ASCENT,"Save JPEG 2000 File..."); +- DrawString(jp2kW,10,10+ASCENT+2*LINEHIGH,"Style options:"); +- DrawString(jp2kW,JP2KW-2*MENUW-10,10+ASCENT+2*LINEHIGH, +- "Coding Blk"); +- DrawString(jp2kW,JP2KW-1*MENUW-10,10+ASCENT+2*LINEHIGH, +- " Precinct"); +- DrawString(jp2kW, +- JP2KW-2*MENUW-10,10+ASCENT+SPACING+3*LINEHIGH+2*MENUH, +- "Progression:"); +- DrawString(jp2kW, +- JP2KW-2*TEXTW-10,10+ASCENT+SPACING+3*LINEHIGH+3*MENUH+0*TEXTH, +- "Guard bits:"); +- DrawString(jp2kW, +- JP2KW-2*TEXTW-10,10+ASCENT+SPACING+3*LINEHIGH+3*MENUH+1*TEXTH, +- "Res levels:"); +- DrawString(jp2kW, +- JP2KW-2*TEXTW-10,10+ASCENT+SPACING+3*LINEHIGH+3*MENUH+2*TEXTH, +- "Rate:"); +- XSetClipMask(theDisp,theGC,None); +- ok = 1; +- break; +- }; +- i = sizeof text/sizeof *text; +- while (--i >= 0 && E->window != text[i]); +- if (i >= 0) +- { +- TWRedraw(E->window,textval[i]); +- ok = 1; +- }; +- break; +-# undef E ++ rect.x = E->x; ++ rect.y = E->y; ++ rect.width = E->width; ++ rect.height = E->height; ++ XSetClipRectangles(theDisp, theGC, 0, 0, &rect, 1, Unsorted); ++ XSetForeground(theDisp, theGC, infofg); ++ XSetBackground(theDisp, theGC, infobg); ++ i = sizeof button / sizeof *button; ++ while (--i >= 0) ++ BTRedraw(&button[i]); ++ i = sizeof chkbut / sizeof *chkbut; ++ while (--i >= 0) ++ CBRedraw(&chkbut[i]); ++ i = sizeof menu / sizeof *menu; ++ while (--i >= 0) ++ MBRedraw(&menu[i]); ++ RBRedraw(radio, -1); ++ DrawString(jp2kW, 10, 10 + ASCENT, "Save JPEG 2000 File..."); ++ DrawString(jp2kW, 10, 10 + ASCENT + 2 * LINEHIGH, "Style options:"); ++ DrawString(jp2kW, JP2KW - 2 * MENUW - 10, ++ 10 + ASCENT + 2 * LINEHIGH, "Coding Blk"); ++ DrawString(jp2kW, JP2KW - 1 * MENUW - 10, ++ 10 + ASCENT + 2 * LINEHIGH, " Precinct"); ++ DrawString(jp2kW, JP2KW - 2 * MENUW - 10, ++ 10 + ASCENT + SPACING + 3 * LINEHIGH + 2 * MENUH, ++ "Progression:"); ++ DrawString(jp2kW, JP2KW - 2 * TEXTW - 10, ++ 10 + ASCENT + SPACING + 3 * LINEHIGH + 3 * MENUH + ++ 0 * TEXTH, ++ "Guard bits:"); ++ DrawString(jp2kW, JP2KW - 2 * TEXTW - 10, ++ 10 + ASCENT + SPACING + 3 * LINEHIGH + 3 * MENUH + ++ 1 * TEXTH, ++ "Res levels:"); ++ DrawString(jp2kW, JP2KW - 2 * TEXTW - 10, ++ 10 + ASCENT + SPACING + 3 * LINEHIGH + 3 * MENUH + ++ 2 * TEXTH, ++ "Rate:"); ++ XSetClipMask(theDisp, theGC, None); ++ ok = 1; ++ break; ++ }; ++ i = sizeof text / sizeof *text; ++ while (--i >= 0 && E->window != text[i]) ++ ; ++ if (i >= 0) { ++ TWRedraw(E->window, textval[i]); ++ ok = 1; ++ }; ++ break; ++#undef E + +- /* Check whether the user pressed one of our buttons. */ ++ /* Check whether the user pressed one of our buttons. */ + +- case ButtonPress: +-# define E ((XButtonEvent *)xev) +- if (E->button == Button1 && E->window == jp2kW) +- { register int j; ++ case ButtonPress: ++#define E ((XButtonEvent *)xev) ++ if (E->button == Button1 && E->window == jp2kW) { ++ register int j; + +- ok = 1; /* Check whether a regular button was pressed */ +- i = sizeof button/sizeof *button; +- while ( --i >= 0 +- && !PTINRECT(E->x,E->y,button[i].x,button[i].y,button[i].w,button[i].h) +- ); +- if (i >= 0) /* our button was pressed */ +- { char options[1024]; +- register char *p; +- register const char *q; ++ ok = 1; /* Check whether a regular button was pressed */ ++ i = sizeof button / sizeof *button; ++ while (--i >= 0 && !PTINRECT(E->x, E->y, button[i].x, button[i].y, ++ button[i].w, button[i].h)) ++ ; ++ if (i >= 0) /* our button was pressed */ ++ { ++ char options[1024]; ++ register char *p; ++ register const char *q; + +- if (!BTTrack(&button[i])) break; /* Ignore it */ +- if (i != J_BOK) /* must be "Cancel" button */ +- { +- JP2KDialog(0); +- break; +- }; ++ if (!BTTrack(&button[i])) ++ break; /* Ignore it */ ++ if (i != J_BOK) /* must be "Cancel" button */ ++ { ++ JP2KDialog(0); ++ break; ++ }; + +- /* Our user hit the "Ok" button. At this point, we have an ugly +- job to do: JasPer Library encoder options must be specified +- as an ASCII string of Space (" ")-separated [=] +- entries, so we must collect the values of all of our widgets +- and subwindows, determine whether our user has requested any +- non-default values, then build the string only for the JasPer +- Library to immediately tear it apart again. Yechh! +- */ +- if ((unsigned)textval[J_TGBIT]-1 > 7) +- { +- OpenAlert("No. of guard bits must be 1-8"); +- sleep(3); +- CloseAlert(); +- break; +- }; +- if ((unsigned)textval[J_TRES ] <= 0) +- { +- OpenAlert("Maximum resolution levels must be >= 1"); +- sleep(3); +- CloseAlert(); +- break; +- }; ++ /* Our user hit the "Ok" button. At this point, we have an ugly ++ job to do: JasPer Library encoder options must be specified ++ as an ASCII string of Space (" ")-separated [=] ++ entries, so we must collect the values of all of our widgets ++ and subwindows, determine whether our user has requested any ++ non-default values, then build the string only for the JasPer ++ Library to immediately tear it apart again. Yechh! ++ */ ++ if ((unsigned)textval[J_TGBIT] - 1 > 7) { ++ OpenAlert("No. of guard bits must be 1-8"); ++ sleep(3); ++ CloseAlert(); ++ break; ++ }; ++ if ((unsigned)textval[J_TRES] <= 0) { ++ OpenAlert("Maximum resolution levels must be >= 1"); ++ sleep(3); ++ CloseAlert(); ++ break; ++ }; + +- /* XXX Should we check and complain if the rate is zero? +- JasPer Library Version 1.701 apparently accepts that +- value, even though it seems kinda weird. +- */ +- p = options; +- i = 0; +- do if ((j = MBWhich(&menu[i])) != 5) +- { static const char *parm[2] = +- {"cblkwidth=%u", "cblkheight=%u"}; ++ /* XXX Should we check and complain if the rate is zero? ++ JasPer Library Version 1.701 apparently accepts that ++ value, even though it seems kinda weird. ++ */ ++ p = options; ++ i = 0; ++ do ++ if ((j = MBWhich(&menu[i])) != 5) { ++ static const char *parm[2] = {"cblkwidth=%u", ++ "cblkheight=%u"}; + +- if (p > options) *p++ = ' '; +- sprintf(p,parm[i-J_MCBXW],++j); +- while (*++p); +- } +- while (++i <= J_MCBXH); +- do if ((j = MBWhich(&menu[i])) < 15) +- { static const char *parm[2] = +- {"prcwidth=%u", "prcheight=%u"}; ++ if (p > options) ++ *p++ = ' '; ++ sprintf(p, parm[i - J_MCBXW], ++j); ++ while (*++p) ++ ; ++ } ++ while (++i <= J_MCBXH); ++ do ++ if ((j = MBWhich(&menu[i])) < 15) { ++ static const char *parm[2] = {"prcwidth=%u", ++ "prcheight=%u"}; + +- if (p > options) *p++ = ' '; +- sprintf(p,parm[i-J_MPREW],j); +- while (*++p); +- } +- while (++i <= J_MPREH); +- if ((j = MBWhich(&menu[i]))) +- { +- if (p > options) *p++ = ' '; +- *p++ = 'p'; *p++ = 'r'; *p++ = 'g'; *p = '='; +- q = ProgList[j]; +- while ((*++p = *q++)); +- }; +- if ((i = textval[J_TRES ]) != 6) +- { +- if (p > options) *p++ = ' '; +- sprintf(p,"numrlvls=%u",i); +- while (*++p); +- }; +- i = 0; +- do if (chkbut[i].val) /* append this encoding option */ +- { +- if (p > options) *p++ = ' '; +- q = chkbut[i].str; +- while ((*p++ = *q++)); +- *--p = '\000'; +- } +- while (++i < sizeof chkbut/sizeof *chkbut); +- if ((i = textval[J_TGBIT]) != 2) +- { +- if (p > options) *p++ = ' '; +- sprintf(p,"numgbits=%u",i); +- while (*++p); +- }; +- if ((i = textval[J_TRATE]) != 100) +- { +- if (p > options) *p++ = ' '; +- *p++ = 'r'; *p++ = 'a'; *p++ = 't'; *p++ = 'e'; +- *p++ = '='; +- if (i) /* non-zero rate */ +- { +- if (RBWhich(radio)) sprintf(p,"%uB",i); /* # Bytes */ +- else /* the value is a percentage */ +- { +- if (i > 100) i = 200; /* => Raw size + 1 */ +- sprintf(p,"%u.%.2u",i/100,i%100); +- } +- while (*++p); +- } +- else /* rate = 0 */ +- { ++ if (p > options) ++ *p++ = ' '; ++ sprintf(p, parm[i - J_MPREW], j); ++ while (*++p) ++ ; ++ } ++ while (++i <= J_MPREH); ++ if ((j = MBWhich(&menu[i]))) { ++ if (p > options) ++ *p++ = ' '; ++ *p++ = 'p'; ++ *p++ = 'r'; ++ *p++ = 'g'; ++ *p = '='; ++ q = ProgList[j]; ++ while ((*++p = *q++)) ++ ; ++ }; ++ if ((i = textval[J_TRES]) != 6) { ++ if (p > options) ++ *p++ = ' '; ++ sprintf(p, "numrlvls=%u", i); ++ while (*++p) ++ ; ++ }; ++ i = 0; ++ do ++ if (chkbut[i].val) /* append this encoding option */ ++ { ++ if (p > options) ++ *p++ = ' '; ++ q = chkbut[i].str; ++ while ((*p++ = *q++)) ++ ; ++ *--p = '\000'; ++ } ++ while (++i < sizeof chkbut / sizeof *chkbut); ++ if ((i = textval[J_TGBIT]) != 2) { ++ if (p > options) ++ *p++ = ' '; ++ sprintf(p, "numgbits=%u", i); ++ while (*++p) ++ ; ++ }; ++ if ((i = textval[J_TRATE]) != 100) { ++ if (p > options) ++ *p++ = ' '; ++ *p++ = 'r'; ++ *p++ = 'a'; ++ *p++ = 't'; ++ *p++ = 'e'; ++ *p++ = '='; ++ if (i) /* non-zero rate */ ++ { ++ if (RBWhich(radio)) ++ sprintf(p, "%uB", i); /* # Bytes */ ++ else /* the value is a percentage */ ++ { ++ if (i > 100) ++ i = 200; /* => Raw size + 1 */ ++ sprintf(p, "%u.%.2u", i / 100, i % 100); ++ } ++ while (*++p) ++ ; ++ } else /* rate = 0 */ ++ { + +- /* XXX This is apparently valid, since JasPer Library +- Version 1.701 doesn't complain about it. +- */ +- *p++ = '0'; +- *p = '\000'; +- } +- }; +- StoreJP2K(options); /* Finally, do the *real* work! */ +- JP2KDialog(0); +- p = GetDirFullName(); +- if (!ISPIPE(*p)) +- { +- XVCreatedFile(p); +- StickInCtrlList(0); +- }; +- break; +- }; ++ /* XXX This is apparently valid, since JasPer Library ++ Version 1.701 doesn't complain about it. ++ */ ++ *p++ = '0'; ++ *p = '\000'; ++ } ++ }; ++ StoreJP2K(options); /* Finally, do the *real* work! */ ++ JP2KDialog(0); ++ p = GetDirFullName(); ++ if (!ISPIPE(*p)) { ++ XVCreatedFile(p); ++ StickInCtrlList(0); ++ }; ++ break; ++ }; + +- /* See whether a check-box button was pressed. */ ++ /* See whether a check-box button was pressed. */ + +- i = sizeof chkbut/sizeof *chkbut; +- while (--i >= 0 && !CBClick(&chkbut[i],E->x,E->y)); +- if (i >= 0) /* our button was pressed */ +- { +- (void)CBTrack(&chkbut[i]); +- break; +- }; ++ i = sizeof chkbut / sizeof *chkbut; ++ while (--i >= 0 && !CBClick(&chkbut[i], E->x, E->y)) ++ ; ++ if (i >= 0) /* our button was pressed */ ++ { ++ (void)CBTrack(&chkbut[i]); ++ break; ++ }; + +- /* See whether a menu button was pressed. */ ++ /* See whether a menu button was pressed. */ + +- i = sizeof menu/sizeof *menu; +- while (--i >= 0 && !MBClick(&menu[i],E->x,E->y)); +- if (i >= 0) /* our button was pressed */ +- { register int j; ++ i = sizeof menu / sizeof *menu; ++ while (--i >= 0 && !MBClick(&menu[i], E->x, E->y)) ++ ; ++ if (i >= 0) /* our button was pressed */ ++ { ++ register int j; + +- if ((j = MBTrack(&menu[i])) >= 0) +- { +- switch (i) +- { ++ if ((j = MBTrack(&menu[i])) >= 0) { ++ switch (i) { + +- /* The JasPer Library constrains a coding box's area +- (width x height) to be <= 4096 pixels, so if this +- button-press would violate that condition, then +- quietly limit the box's orthogonal dimension by just +- enough to compensate. +- */ +- case J_MCBXH: +- case J_MCBXW: if (MBWhich(&menu[!i]) + j >= 10) +- MBSelect(&menu[!i],10 - j); +- }; +- MBSelect(&menu[i],j); +- MBSetActive(&menu[i],1); +- }; +- break; +- }; ++ /* The JasPer Library constrains a coding box's area ++ (width x height) to be <= 4096 pixels, so if this ++ button-press would violate that condition, then ++ quietly limit the box's orthogonal dimension by just ++ enough to compensate. ++ */ ++ case J_MCBXH: ++ case J_MCBXW: ++ if (MBWhich(&menu[!i]) + j >= 10) ++ MBSelect(&menu[!i], 10 - j); ++ }; ++ MBSelect(&menu[i], j); ++ MBSetActive(&menu[i], 1); ++ }; ++ break; ++ }; + +- /* See whether a radio button was pressed. */ ++ /* See whether a radio button was pressed. */ + +- if ( (i = RBClick(radio,E->x,E->y)) >= 0 /* button pressed */ +- && RBTrack(radio,i) +- ) +- { +- RBSelect(radio,i); +- RBSetActive(radio,i,1); +- }; +- break; +- }; +- XBell(theDisp,50); +- break; +-# undef E ++ if ((i = RBClick(radio, E->x, E->y)) >= 0 /* button pressed */ ++ && RBTrack(radio, i)) { ++ RBSelect(radio, i); ++ RBSetActive(radio, i, 1); ++ }; ++ break; ++ }; ++ XBell(theDisp, 50); ++ break; ++#undef E + +- /* Translate a few key-press events into simulated button events. */ ++ /* Translate a few key-press events into simulated button events. */ + +- case KeyPress : +-# define E ((XKeyEvent *)xev) +- buf[len = XLookupString(E,buf,sizeof buf,&ks,0)] = '\000'; +- RemapKeyCheck(ks,buf,&len); +- if (E->window == jp2kW) +- { +- ok = 1; +- if (len > 0) +- switch (buf[0]) +- { +- case '\r' : +- case '\n' : FakeButtonPress(&button[J_BOK ]); +- break; +- case '\033': FakeButtonPress(&button[J_BCANC]); +- }; +- break; +- }; +- i = sizeof text/sizeof *text; +- while (--i >= 0 && E->window != text[i]); +- if (i >= 0) /* a key was pressed in our text window */ +- { int oldval = textval[i]; /* Save this subwindow's old value */ +- register int c, j = 0; ++ case KeyPress: ++#define E ((XKeyEvent *)xev) ++ buf[len = XLookupString(E, buf, sizeof buf, &ks, 0)] = '\000'; ++ RemapKeyCheck(ks, buf, &len); ++ if (E->window == jp2kW) { ++ ok = 1; ++ if (len > 0) ++ switch (buf[0]) { ++ case '\r': ++ case '\n': ++ FakeButtonPress(&button[J_BOK]); ++ break; ++ case '\033': ++ FakeButtonPress(&button[J_BCANC]); ++ }; ++ break; ++ }; ++ i = sizeof text / sizeof *text; ++ while (--i >= 0 && E->window != text[i]) ++ ; ++ if (i >= 0) /* a key was pressed in our text window */ ++ { ++ int oldval = textval[i]; /* Save this subwindow's old value */ ++ register int c, j = 0; + +- /* This is a *very* simple text-input editing loop that assembles an +- an unsigned integer from successive ASCII decimal digits, typed +- into one of our 1-line subwindows. For convenience, the only +- character recognized is Backspace. +- */ +- ok = 1; +- L: if (j >= len) break; +- if ((unsigned)(c = buf[j++] - '0') <= 9) +- { +- TWRedraw(text[i],textval[i] = textval[i]*10 + c); +- goto L; +- }; +- if ((c += '0') == '\b') +- { +- TWRedraw(text[i],textval[i] = textval[i]/10); +- goto L; +- }; +- textval[i] = oldval; +- }; +- XBell(theDisp,50); +-# undef E +- }; +- return ok; ++ /* This is a *very* simple text-input editing loop that assembles an ++ an unsigned integer from successive ASCII decimal digits, typed ++ into one of our 1-line subwindows. For convenience, the only ++ character recognized is Backspace. ++ */ ++ ok = 1; ++ L: ++ if (j >= len) ++ break; ++ if ((unsigned)(c = buf[j++] - '0') <= 9) { ++ TWRedraw(text[i], textval[i] = textval[i] * 10 + c); ++ goto L; ++ }; ++ if ((c += '0') == '\b') { ++ TWRedraw(text[i], textval[i] = textval[i] / 10); ++ goto L; ++ }; ++ textval[i] = oldval; ++ }; ++ XBell(theDisp, 50); ++#undef E ++ }; ++ return ok; + } + +- + /*******************************************/ +-void +-VersionInfoJP2K() /* GRR 20070304 */ ++void VersionInfoJP2K() /* GRR 20070304 */ + { +- fprintf(stderr, " Compiled with libjasper %s; using libjasper %s.\n", +- JAS_VERSION, jas_getversion()); ++ fprintf(stderr, " Compiled with libjasper %s; using libjasper %s.\n", ++ JAS_VERSION, jas_getversion()); + } + + #endif /* HAVE_JP2K */