aboutsummaryrefslogtreecommitdiff
path: root/graphics/xv
diff options
context:
space:
mode:
authorDirk Meyer <dinoex@FreeBSD.org>2022-03-02 09:56:56 +0000
committerDirk Meyer <dinoex@FreeBSD.org>2022-03-02 09:56:56 +0000
commit27bea38852a7e0f5af8cdada0437c349e5d0aa57 (patch)
treed6772834b0997906e7a387aed3c9f6e723149c5d /graphics/xv
parentbfedd5f1f016c174f3fe18cd38c8517ece7b1e9b (diff)
downloadports-27bea38852a7e0f5af8cdada0437c349e5d0aa57.tar.gz
ports-27bea38852a7e0f5af8cdada0437c349e5d0aa57.zip
graphics/xv: update for jasper 3 support
Diffstat (limited to 'graphics/xv')
-rw-r--r--graphics/xv/Makefile2
-rw-r--r--graphics/xv/files/patch-xvjp2k.c2382
2 files changed, 2375 insertions, 9 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;}
+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 <marovich@hpl.hp.com>, Hewlett-Packard Laboratories,
+ * January 2005.
++ *
++ * Michael Aadams <mdadams@ece.uvic.ca>, 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"
+
+-#define NEEDSARGS
++#define NEEDSARGS
+ #include "xv.h"
+
+ #ifdef HAVE_JP2K
+
+ #include <jasper/jasper.h>
+-/* 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;}
-+int jas_memdump(FILE *fp,const 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);
- int jas_eprintf(const char *fmt,...) /* Handle JasPer Library message */
+- /* 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 <tag>[=<value>]
+- 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 <tag>[=<value>]
++ 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 */