Click here to Skip to main content
15,886,199 members
Articles / Desktop Programming / MFC

WaterMarker

Rate me:
Please Sign up or sign in to vote.
4.75/5 (17 votes)
5 Apr 2006Zlib5 min read 103.8K   3K   64  
An utility to protect yout pictures with a stamp bitmap.
/*
 * Copyright (c) 1999-2000 Image Power, Inc. and the University of
 *   British Columbia.
 * Copyright (c) 2001-2003 Michael David Adams.
 * All rights reserved.
 */

/* __START_OF_JASPER_LICENSE__
 * 
 * JasPer Software License
 * 
 * IMAGE POWER JPEG-2000 PUBLIC LICENSE
 * ************************************
 * 
 * GRANT:
 * 
 * Permission is hereby granted, free of charge, to any person (the "User")
 * obtaining a copy of this software and associated documentation, to deal
 * in the JasPer Software without restriction, including without limitation
 * the right to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the JasPer Software (in source and binary forms),
 * and to permit persons to whom the JasPer Software is furnished to do so,
 * provided further that the License Conditions below are met.
 * 
 * License Conditions
 * ******************
 * 
 * A.  Redistributions of source code must retain the above copyright notice,
 * and this list of conditions, and the following disclaimer.
 * 
 * B.  Redistributions in binary form must reproduce the above copyright
 * notice, and this list of conditions, and the following disclaimer in
 * the documentation and/or other materials provided with the distribution.
 * 
 * C.  Neither the name of Image Power, Inc. nor any other contributor
 * (including, but not limited to, the University of British Columbia and
 * Michael David Adams) may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * 
 * D.  User agrees that it shall not commence any action against Image Power,
 * Inc., the University of British Columbia, Michael David Adams, or any
 * other contributors (collectively "Licensors") for infringement of any
 * intellectual property rights ("IPR") held by the User in respect of any
 * technology that User owns or has a right to license or sublicense and
 * which is an element required in order to claim compliance with ISO/IEC
 * 15444-1 (i.e., JPEG-2000 Part 1).  "IPR" means all intellectual property
 * rights worldwide arising under statutory or common law, and whether
 * or not perfected, including, without limitation, all (i) patents and
 * patent applications owned or licensable by User; (ii) rights associated
 * with works of authorship including copyrights, copyright applications,
 * copyright registrations, mask work rights, mask work applications,
 * mask work registrations; (iii) rights relating to the protection of
 * trade secrets and confidential information; (iv) any right analogous
 * to those set forth in subsections (i), (ii), or (iii) and any other
 * proprietary rights relating to intangible property (other than trademark,
 * trade dress, or service mark rights); and (v) divisions, continuations,
 * renewals, reissues and extensions of the foregoing (as and to the extent
 * applicable) now existing, hereafter filed, issued or acquired.
 * 
 * E.  If User commences an infringement action against any Licensor(s) then
 * such Licensor(s) shall have the right to terminate User's license and
 * all sublicenses that have been granted hereunder by User to other parties.
 * 
 * F.  This software is for use only in hardware or software products that
 * are compliant with ISO/IEC 15444-1 (i.e., JPEG-2000 Part 1).  No license
 * or right to this Software is granted for products that do not comply
 * with ISO/IEC 15444-1.  The JPEG-2000 Part 1 standard can be purchased
 * from the ISO.
 * 
 * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
 * NO USE OF THE JASPER SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 * THIS DISCLAIMER.  THE JASPER SOFTWARE IS PROVIDED BY THE LICENSORS AND
 * CONTRIBUTORS UNDER THIS LICENSE ON AN ``AS-IS'' BASIS, WITHOUT WARRANTY
 * OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
 * WARRANTIES THAT THE JASPER SOFTWARE IS FREE OF DEFECTS, IS MERCHANTABLE,
 * IS FIT FOR A PARTICULAR PURPOSE OR IS NON-INFRINGING.  THOSE INTENDING
 * TO USE THE JASPER SOFTWARE OR MODIFICATIONS THEREOF FOR USE IN HARDWARE
 * OR SOFTWARE PRODUCTS ARE ADVISED THAT THEIR USE MAY INFRINGE EXISTING
 * PATENTS, COPYRIGHTS, TRADEMARKS, OR OTHER INTELLECTUAL PROPERTY RIGHTS.
 * THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE JASPER SOFTWARE
 * IS WITH THE USER.  SHOULD ANY PART OF THE JASPER SOFTWARE PROVE DEFECTIVE
 * IN ANY RESPECT, THE USER (AND NOT THE INITIAL DEVELOPERS, THE UNIVERSITY
 * OF BRITISH COLUMBIA, IMAGE POWER, INC., MICHAEL DAVID ADAMS, OR ANY
 * OTHER CONTRIBUTOR) SHALL ASSUME THE COST OF ANY NECESSARY SERVICING,
 * REPAIR OR CORRECTION.  UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY,
 * WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE
 * INITIAL DEVELOPER, THE UNIVERSITY OF BRITISH COLUMBIA, IMAGE POWER, INC.,
 * MICHAEL DAVID ADAMS, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF THE
 * JASPER SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO
 * THE USER OR ANY OTHER PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
 * CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION,
 * DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR
 * MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF
 * SUCH PARTY HAD BEEN INFORMED, OR OUGHT TO HAVE KNOWN, OF THE POSSIBILITY
 * OF SUCH DAMAGES.  THE JASPER SOFTWARE AND UNDERLYING TECHNOLOGY ARE NOT
 * FAULT-TOLERANT AND ARE NOT DESIGNED, MANUFACTURED OR INTENDED FOR USE OR
 * RESALE AS ON-LINE CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING
 * FAIL-SAFE PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES,
 * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT
 * LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
 * JASPER SOFTWARE OR UNDERLYING TECHNOLOGY OR PRODUCT COULD LEAD DIRECTLY
 * TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE
 * ("HIGH RISK ACTIVITIES").  LICENSOR SPECIFICALLY DISCLAIMS ANY EXPRESS
 * OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.  USER WILL NOT
 * KNOWINGLY USE, DISTRIBUTE OR RESELL THE JASPER SOFTWARE OR UNDERLYING
 * TECHNOLOGY OR PRODUCTS FOR HIGH RISK ACTIVITIES AND WILL ENSURE THAT ITS
 * CUSTOMERS AND END-USERS OF ITS PRODUCTS ARE PROVIDED WITH A COPY OF THE
 * NOTICE SPECIFIED IN THIS SECTION.
 * 
 * __END_OF_JASPER_LICENSE__
 */

/*
 * $Id$
 */

/******************************************************************************\
* Includes.
\******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <float.h>

#include "jasper/jas_string.h"
#include "jasper/jas_malloc.h"
#include "jasper/jas_image.h"
#include "jasper/jas_fix.h"
#include "jasper/jas_tvp.h"
#include "jasper/jas_version.h"
#include "jasper/jas_math.h"
#include "jasper/jas_debug.h"

#include "jpc_flt.h"
#include "jpc_fix.h"
#include "jpc_tagtree.h"
#include "jpc_enc.h"
#include "jpc_cs.h"
#include "jpc_mct.h"
#include "jpc_tsfb.h"
#include "jpc_qmfb.h"
#include "jpc_t1enc.h"
#include "jpc_t2enc.h"
#include "jpc_cod.h"
#include "jpc_math.h"
#include "jpc_util.h"

/******************************************************************************\
*
\******************************************************************************/

#define JPC_POW2(n) \
	(1 << (n))

#define JPC_FLOORTOMULTPOW2(x, n) \
  (((n) > 0) ? ((x) & (~((1 << n) - 1))) : (x))
/* Round to the nearest multiple of the specified power of two in the
  direction of negative infinity. */

#define	JPC_CEILTOMULTPOW2(x, n) \
  (((n) > 0) ? JPC_FLOORTOMULTPOW2(((x) + (1 << (n)) - 1), n) : (x))
/* Round to the nearest multiple of the specified power of two in the
  direction of positive infinity. */

#define	JPC_POW2(n)	\
  (1 << (n))

jpc_enc_tile_t *jpc_enc_tile_create(jpc_enc_cp_t *cp, jas_image_t *image, int tileno);
void jpc_enc_tile_destroy(jpc_enc_tile_t *tile);

static jpc_enc_tcmpt_t *tcmpt_create(jpc_enc_tcmpt_t *tcmpt, jpc_enc_cp_t *cp,
  jas_image_t *image, jpc_enc_tile_t *tile);
static void tcmpt_destroy(jpc_enc_tcmpt_t *tcmpt);
static jpc_enc_rlvl_t *rlvl_create(jpc_enc_rlvl_t *rlvl, jpc_enc_cp_t *cp,
  jpc_enc_tcmpt_t *tcmpt, jpc_tsfb_band_t *bandinfos);
static void rlvl_destroy(jpc_enc_rlvl_t *rlvl);
static jpc_enc_band_t *band_create(jpc_enc_band_t *band, jpc_enc_cp_t *cp,
  jpc_enc_rlvl_t *rlvl, jpc_tsfb_band_t *bandinfos);
static void band_destroy(jpc_enc_band_t *bands);
static jpc_enc_prc_t *prc_create(jpc_enc_prc_t *prc, jpc_enc_cp_t *cp,
  jpc_enc_band_t *band);
static void prc_destroy(jpc_enc_prc_t *prcs);
static jpc_enc_cblk_t *cblk_create(jpc_enc_cblk_t *cblk, jpc_enc_cp_t *cp,
  jpc_enc_prc_t *prc);
static void cblk_destroy(jpc_enc_cblk_t *cblks);
int ratestrtosize(char *s, uint_fast32_t rawsize, uint_fast32_t *size);
static void pass_destroy(jpc_enc_pass_t *pass);
void jpc_enc_dump(jpc_enc_t *enc);

/******************************************************************************\
* Local prototypes.
\******************************************************************************/

int dump_passes(jpc_enc_pass_t *passes, int numpasses, jpc_enc_cblk_t *cblk);
void calcrdslopes(jpc_enc_cblk_t *cblk);
void dump_layeringinfo(jpc_enc_t *enc);
static int jpc_calcssexp(jpc_fix_t stepsize);
static int jpc_calcssmant(jpc_fix_t stepsize);
void quantize(jas_matrix_t *data, jpc_fix_t stepsize);
static int jpc_enc_encodemainhdr(jpc_enc_t *enc);
static int jpc_enc_encodemainbody(jpc_enc_t *enc);
int jpc_enc_encodetiledata(jpc_enc_t *enc);
jpc_enc_t *jpc_enc_create(jpc_enc_cp_t *cp, jas_stream_t *out, jas_image_t *image);
void jpc_enc_destroy(jpc_enc_t *enc);
static int jpc_enc_encodemainhdr(jpc_enc_t *enc);
static int jpc_enc_encodemainbody(jpc_enc_t *enc);
int jpc_enc_encodetiledata(jpc_enc_t *enc);
int rateallocate(jpc_enc_t *enc, int numlyrs, uint_fast32_t *cumlens);
int setins(int numvalues, jpc_flt_t *values, jpc_flt_t value);
static jpc_enc_cp_t *cp_create(char *optstr, jas_image_t *image);
void jpc_enc_cp_destroy(jpc_enc_cp_t *cp);
static uint_fast32_t jpc_abstorelstepsize(jpc_fix_t absdelta, int scaleexpn);

static uint_fast32_t jpc_abstorelstepsize(jpc_fix_t absdelta, int scaleexpn)
{
	int p;
	uint_fast32_t mant;
	uint_fast32_t expn;
	int n;

	if (absdelta < 0) {
		abort();
	}

	p = jpc_firstone(absdelta) - JPC_FIX_FRACBITS;
	n = 11 - jpc_firstone(absdelta);
	mant = ((n < 0) ? (absdelta >> (-n)) : (absdelta << n)) & 0x7ff;
	expn = scaleexpn - p;
	if (scaleexpn < p) {
		abort();
	}
	return JPC_QCX_EXPN(expn) | JPC_QCX_MANT(mant);
}

typedef enum {
	OPT_DEBUG,
	OPT_IMGAREAOFFX,
	OPT_IMGAREAOFFY,
	OPT_TILEGRDOFFX,
	OPT_TILEGRDOFFY,
	OPT_TILEWIDTH,
	OPT_TILEHEIGHT,
	OPT_PRCWIDTH,
	OPT_PRCHEIGHT,
	OPT_CBLKWIDTH,
	OPT_CBLKHEIGHT,
	OPT_MODE,
	OPT_PRG,
	OPT_NOMCT,
	OPT_MAXRLVLS,
	OPT_SOP,
	OPT_EPH,
	OPT_LAZY,
	OPT_TERMALL,
	OPT_SEGSYM,
	OPT_VCAUSAL,
	OPT_RESET,
	OPT_PTERM,
	OPT_NUMGBITS,
	OPT_RATE,
	OPT_ILYRRATES,
	OPT_JP2OVERHEAD
} optid_t;

jas_taginfo_t encopts[] = {
	{OPT_DEBUG, "debug"},
	{OPT_IMGAREAOFFX, "imgareatlx"},
	{OPT_IMGAREAOFFY, "imgareatly"},
	{OPT_TILEGRDOFFX, "tilegrdtlx"},
	{OPT_TILEGRDOFFY, "tilegrdtly"},
	{OPT_TILEWIDTH, "tilewidth"},
	{OPT_TILEHEIGHT, "tileheight"},
	{OPT_PRCWIDTH, "prcwidth"},
	{OPT_PRCHEIGHT, "prcheight"},
	{OPT_CBLKWIDTH, "cblkwidth"},
	{OPT_CBLKHEIGHT, "cblkheight"},
	{OPT_MODE, "mode"},
	{OPT_PRG, "prg"},
	{OPT_NOMCT, "nomct"},
	{OPT_MAXRLVLS, "numrlvls"},
	{OPT_SOP, "sop"},
	{OPT_EPH, "eph"},
	{OPT_LAZY, "lazy"},
	{OPT_TERMALL, "termall"},
	{OPT_SEGSYM, "segsym"},
	{OPT_VCAUSAL, "vcausal"},
	{OPT_PTERM, "pterm"},
	{OPT_RESET, "resetprob"},
	{OPT_NUMGBITS, "numgbits"},
	{OPT_RATE, "rate"},
	{OPT_ILYRRATES, "ilyrrates"},
	{OPT_JP2OVERHEAD, "_jp2overhead"},
	{-1, 0}
};

typedef enum {
	PO_L = 0,
	PO_R
} poid_t;


jas_taginfo_t prgordtab[] = {
	{JPC_COD_LRCPPRG, "lrcp"},
	{JPC_COD_RLCPPRG, "rlcp"},
	{JPC_COD_RPCLPRG, "rpcl"},
	{JPC_COD_PCRLPRG, "pcrl"},
	{JPC_COD_CPRLPRG, "cprl"},
	{-1, 0}
};

typedef enum {
	MODE_INT,
	MODE_REAL
} modeid_t;

jas_taginfo_t modetab[] = {
	{MODE_INT, "int"},
	{MODE_REAL, "real"},
	{-1, 0}
};

/******************************************************************************\
* The main encoder entry point.
\******************************************************************************/

int jpc_encode(jas_image_t *image, jas_stream_t *out, char *optstr)
{
	jpc_enc_t *enc;
	jpc_enc_cp_t *cp;

	enc = 0;
	cp = 0;

	jpc_initluts();

	if (!(cp = cp_create(optstr, image))) {
		fprintf(stderr, "invalid JP encoder options\n");
		goto error;
	}

	if (!(enc = jpc_enc_create(cp, out, image))) {
		goto error;
	}
	cp = 0;

	/* Encode the main header. */
	if (jpc_enc_encodemainhdr(enc)) {
		goto error;
	}

	/* Encode the main body.  This constitutes most of the encoding work. */
	if (jpc_enc_encodemainbody(enc)) {
		goto error;
	}

	/* Write EOC marker segment. */
	if (!(enc->mrk = jpc_ms_create(JPC_MS_EOC))) {
		goto error;
	}
	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
		fprintf(stderr, "cannot write EOI marker\n");
		goto error;
	}
	jpc_ms_destroy(enc->mrk);
	enc->mrk = 0;

	if (jas_stream_flush(enc->out)) {
		goto error;
	}

	jpc_enc_destroy(enc);

	return 0;

error:
	if (cp) {
		jpc_enc_cp_destroy(cp);
	}
	if (enc) {
		jpc_enc_destroy(enc);
	}
	return -1;
}

/******************************************************************************\
* Option parsing code.
\******************************************************************************/

static jpc_enc_cp_t *cp_create(char *optstr, jas_image_t *image)
{
	jpc_enc_cp_t *cp;
	jas_tvparser_t *tvp;
	int ret;
	int numilyrrates;
	double *ilyrrates;
	int i;
	int tagid;
	jpc_enc_tcp_t *tcp;
	jpc_enc_tccp_t *tccp;
	jpc_enc_ccp_t *ccp;
	int cmptno;
	uint_fast16_t rlvlno;
	uint_fast16_t prcwidthexpn;
	uint_fast16_t prcheightexpn;
	bool enablemct;
	uint_fast32_t jp2overhead;
	uint_fast16_t lyrno;
	uint_fast32_t hsteplcm;
	uint_fast32_t vsteplcm;
	bool mctvalid;

	tvp = 0;
	cp = 0;
	ilyrrates = 0;
	numilyrrates = 0;

	if (!(cp = jas_malloc(sizeof(jpc_enc_cp_t)))) {
		goto error;
	}

	prcwidthexpn = 15;
	prcheightexpn = 15;
	enablemct = true;
	jp2overhead = 0;

	cp->ccps = 0;
	cp->debug = 0;
	cp->imgareatlx = UINT_FAST32_MAX;
	cp->imgareatly = UINT_FAST32_MAX;
	cp->refgrdwidth = 0;
	cp->refgrdheight = 0;
	cp->tilegrdoffx = UINT_FAST32_MAX;
	cp->tilegrdoffy = UINT_FAST32_MAX;
	cp->tilewidth = 0;
	cp->tileheight = 0;
	cp->numcmpts = jas_image_numcmpts(image);

	hsteplcm = 1;
	vsteplcm = 1;
	for (cmptno = 0; cmptno < jas_image_numcmpts(image); ++cmptno) {
		if (jas_image_cmptbrx(image, cmptno) + jas_image_cmpthstep(image, cmptno) <=
		  jas_image_brx(image) || jas_image_cmptbry(image, cmptno) +
		  jas_image_cmptvstep(image, cmptno) <= jas_image_bry(image)) {
			fprintf(stderr, "unsupported image type\n");
			goto error;
		}
		/* Note: We ought to be calculating the LCMs here.  Fix some day. */
		hsteplcm *= jas_image_cmpthstep(image, cmptno);
		vsteplcm *= jas_image_cmptvstep(image, cmptno);
	}

	if (!(cp->ccps = jas_malloc(cp->numcmpts * sizeof(jpc_enc_ccp_t)))) {
		goto error;
	}
	for (cmptno = 0, ccp = cp->ccps; cmptno < JAS_CAST(int, cp->numcmpts); ++cmptno,
	  ++ccp) {
		ccp->sampgrdstepx = jas_image_cmpthstep(image, cmptno);
		ccp->sampgrdstepy = jas_image_cmptvstep(image, cmptno);
		/* XXX - this isn't quite correct for more general image */
		ccp->sampgrdsubstepx = 0;
		ccp->sampgrdsubstepx = 0;
		ccp->prec = jas_image_cmptprec(image, cmptno);
		ccp->sgnd = jas_image_cmptsgnd(image, cmptno);
		ccp->numstepsizes = 0;
		memset(ccp->stepsizes, 0, sizeof(ccp->stepsizes));
	}

	cp->rawsize = jas_image_rawsize(image);
	cp->totalsize = UINT_FAST32_MAX;

	tcp = &cp->tcp;
	tcp->csty = 0;
	tcp->intmode = true;
	tcp->prg = JPC_COD_LRCPPRG;
	tcp->numlyrs = 1;
	tcp->ilyrrates = 0;

	tccp = &cp->tccp;
	tccp->csty = 0;
	tccp->maxrlvls = 6;
	tccp->cblkwidthexpn = 6;
	tccp->cblkheightexpn = 6;
	tccp->cblksty = 0;
	tccp->numgbits = 2;

	if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) {
		goto error;
	}

	while (!(ret = jas_tvparser_next(tvp))) {
		switch (jas_taginfo_nonull(jas_taginfos_lookup(encopts,
		  jas_tvparser_gettag(tvp)))->id) {
		case OPT_DEBUG:
			cp->debug = atoi(jas_tvparser_getval(tvp));
			break;
		case OPT_IMGAREAOFFX:
			cp->imgareatlx = atoi(jas_tvparser_getval(tvp));
			break;
		case OPT_IMGAREAOFFY:
			cp->imgareatly = atoi(jas_tvparser_getval(tvp));
			break;
		case OPT_TILEGRDOFFX:
			cp->tilegrdoffx = atoi(jas_tvparser_getval(tvp));
			break;
		case OPT_TILEGRDOFFY:
			cp->tilegrdoffy = atoi(jas_tvparser_getval(tvp));
			break;
		case OPT_TILEWIDTH:
			cp->tilewidth = atoi(jas_tvparser_getval(tvp));
			break;
		case OPT_TILEHEIGHT:
			cp->tileheight = atoi(jas_tvparser_getval(tvp));
			break;
		case OPT_PRCWIDTH:
			prcwidthexpn = jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
			break;
		case OPT_PRCHEIGHT:
			prcheightexpn = jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
			break;
		case OPT_CBLKWIDTH:
			tccp->cblkwidthexpn =
			  jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
			break;
		case OPT_CBLKHEIGHT:
			tccp->cblkheightexpn =
			  jpc_floorlog2(atoi(jas_tvparser_getval(tvp)));
			break;
		case OPT_MODE:
			if ((tagid = jas_taginfo_nonull(jas_taginfos_lookup(modetab,
			  jas_tvparser_getval(tvp)))->id) < 0) {
				fprintf(stderr,
				  "ignoring invalid mode %s\n",
				  jas_tvparser_getval(tvp));
			} else {
				tcp->intmode = (tagid == MODE_INT);
			}
			break;
		case OPT_PRG:
			if ((tagid = jas_taginfo_nonull(jas_taginfos_lookup(prgordtab,
			  jas_tvparser_getval(tvp)))->id) < 0) {
				fprintf(stderr,
				  "ignoring invalid progression order %s\n",
				  jas_tvparser_getval(tvp));
			} else {
				tcp->prg = tagid;
			}
			break;
		case OPT_NOMCT:
			enablemct = false;
			break;
		case OPT_MAXRLVLS:
			tccp->maxrlvls = atoi(jas_tvparser_getval(tvp));
			break;
		case OPT_SOP:
			cp->tcp.csty |= JPC_COD_SOP;
			break;
		case OPT_EPH:
			cp->tcp.csty |= JPC_COD_EPH;
			break;
		case OPT_LAZY:
			tccp->cblksty |= JPC_COX_LAZY;
			break;
		case OPT_TERMALL:
			tccp->cblksty |= JPC_COX_TERMALL;
			break;
		case OPT_SEGSYM:
			tccp->cblksty |= JPC_COX_SEGSYM;
			break;
		case OPT_VCAUSAL:
			tccp->cblksty |= JPC_COX_VSC;
			break;
		case OPT_RESET:
			tccp->cblksty |= JPC_COX_RESET;
			break;
		case OPT_PTERM:
			tccp->cblksty |= JPC_COX_PTERM;
			break;
		case OPT_NUMGBITS:
			cp->tccp.numgbits = atoi(jas_tvparser_getval(tvp));
			break;
		case OPT_RATE:
			if (ratestrtosize(jas_tvparser_getval(tvp), cp->rawsize,
			  &cp->totalsize)) {
				fprintf(stderr,
				  "ignoring bad rate specifier %s\n",
				  jas_tvparser_getval(tvp));
			}
			break;
		case OPT_ILYRRATES:
			if (jpc_atoaf(jas_tvparser_getval(tvp), &numilyrrates,
			  &ilyrrates)) {
				fprintf(stderr,
				  "warning: invalid intermediate layer rates specifier ignored (%s)\n",
				  jas_tvparser_getval(tvp));
			}
			break;

		case OPT_JP2OVERHEAD:
			jp2overhead = atoi(jas_tvparser_getval(tvp));
			break;
		default:
			fprintf(stderr, "warning: ignoring invalid option %s\n",
			 jas_tvparser_gettag(tvp));
			break;
		}
	}

	jas_tvparser_destroy(tvp);
	tvp = 0;

	if (cp->totalsize != UINT_FAST32_MAX) {
		cp->totalsize = (cp->totalsize > jp2overhead) ?
		  (cp->totalsize - jp2overhead) : 0;
	}

	if (cp->imgareatlx == UINT_FAST32_MAX) {
		cp->imgareatlx = 0;
	} else {
		if (hsteplcm != 1) {
			fprintf(stderr, "warning: overriding imgareatlx value\n");
		}
		cp->imgareatlx *= hsteplcm;
	}
	if (cp->imgareatly == UINT_FAST32_MAX) {
		cp->imgareatly = 0;
	} else {
		if (vsteplcm != 1) {
			fprintf(stderr, "warning: overriding imgareatly value\n");
		}
		cp->imgareatly *= vsteplcm;
	}
	cp->refgrdwidth = cp->imgareatlx + jas_image_width(image);
	cp->refgrdheight = cp->imgareatly + jas_image_height(image);
	if (cp->tilegrdoffx == UINT_FAST32_MAX) {
		cp->tilegrdoffx = cp->imgareatlx;
	}
	if (cp->tilegrdoffy == UINT_FAST32_MAX) {
		cp->tilegrdoffy = cp->imgareatly;
	}
	if (!cp->tilewidth) {
		cp->tilewidth = cp->refgrdwidth - cp->tilegrdoffx;
	}
	if (!cp->tileheight) {
		cp->tileheight = cp->refgrdheight - cp->tilegrdoffy;
	}

	if (cp->numcmpts == 3) {
		mctvalid = true;
		for (cmptno = 0; cmptno < jas_image_numcmpts(image); ++cmptno) {
			if (jas_image_cmptprec(image, cmptno) != jas_image_cmptprec(image, 0) ||
			  jas_image_cmptsgnd(image, cmptno) != jas_image_cmptsgnd(image, 0) ||
			  jas_image_cmptwidth(image, cmptno) != jas_image_cmptwidth(image, 0) ||
			  jas_image_cmptheight(image, cmptno) != jas_image_cmptheight(image, 0)) {
				mctvalid = false;
			}
		}
	} else {
		mctvalid = false;
	}
	if (mctvalid && enablemct && jas_clrspc_fam(jas_image_clrspc(image)) != JAS_CLRSPC_FAM_RGB) {
		fprintf(stderr, "warning: color space apparently not RGB\n");
	}
	if (mctvalid && enablemct && jas_clrspc_fam(jas_image_clrspc(image)) == JAS_CLRSPC_FAM_RGB) {
		tcp->mctid = (tcp->intmode) ? (JPC_MCT_RCT) : (JPC_MCT_ICT);
	} else {
		tcp->mctid = JPC_MCT_NONE;
	}
	tccp->qmfbid = (tcp->intmode) ? (JPC_COX_RFT) : (JPC_COX_INS);

	for (rlvlno = 0; rlvlno < tccp->maxrlvls; ++rlvlno) {
		tccp->prcwidthexpns[rlvlno] = prcwidthexpn;
		tccp->prcheightexpns[rlvlno] = prcheightexpn;
	}
	if (prcwidthexpn != 15 || prcheightexpn != 15) {
		tccp->csty |= JPC_COX_PRT;
	}

	/* Ensure that the tile width and height is valid. */
	if (!cp->tilewidth) {
		fprintf(stderr, "invalid tile width %lu\n", (unsigned long)
		  cp->tilewidth);
		goto error;
	}
	if (!cp->tileheight) {
		fprintf(stderr, "invalid tile height %lu\n", (unsigned long)
		  cp->tileheight);
		goto error;
	}

	/* Ensure that the tile grid offset is valid. */
	if (cp->tilegrdoffx > cp->imgareatlx ||
	  cp->tilegrdoffy > cp->imgareatly ||
	  cp->tilegrdoffx + cp->tilewidth < cp->imgareatlx ||
	  cp->tilegrdoffy + cp->tileheight < cp->imgareatly) {
		fprintf(stderr, "invalid tile grid offset (%lu, %lu)\n",
		  (unsigned long) cp->tilegrdoffx, (unsigned long)
		  cp->tilegrdoffy);
		goto error;
	}

	cp->numhtiles = JPC_CEILDIV(cp->refgrdwidth - cp->tilegrdoffx,
	  cp->tilewidth);
	cp->numvtiles = JPC_CEILDIV(cp->refgrdheight - cp->tilegrdoffy,
	  cp->tileheight);
	cp->numtiles = cp->numhtiles * cp->numvtiles;

	if (ilyrrates && numilyrrates > 0) {
		tcp->numlyrs = numilyrrates + 1;
		if (!(tcp->ilyrrates = jas_malloc((tcp->numlyrs - 1) *
		  sizeof(jpc_fix_t)))) {
			goto error;
		}
		for (i = 0; i < JAS_CAST(int, tcp->numlyrs - 1); ++i) {
			tcp->ilyrrates[i] = jpc_dbltofix(ilyrrates[i]);
		}
	}

	/* Ensure that the integer mode is used in the case of lossless
	  coding. */
	if (cp->totalsize == UINT_FAST32_MAX && (!cp->tcp.intmode)) {
		fprintf(stderr, "cannot use real mode for lossless coding\n");
		goto error;
	}

	/* Ensure that the precinct width is valid. */
	if (prcwidthexpn > 15) {
		fprintf(stderr, "invalid precinct width\n");
		goto error;
	}

	/* Ensure that the precinct height is valid. */
	if (prcheightexpn > 15) {
		fprintf(stderr, "invalid precinct height\n");
		goto error;
	}

	/* Ensure that the code block width is valid. */
	if (cp->tccp.cblkwidthexpn < 2 || cp->tccp.cblkwidthexpn > 12) {
		fprintf(stderr, "invalid code block width %d\n",
		  JPC_POW2(cp->tccp.cblkwidthexpn));
		goto error;
	}

	/* Ensure that the code block height is valid. */
	if (cp->tccp.cblkheightexpn < 2 || cp->tccp.cblkheightexpn > 12) {
		fprintf(stderr, "invalid code block height %d\n",
		  JPC_POW2(cp->tccp.cblkheightexpn));
		goto error;
	}

	/* Ensure that the code block size is not too large. */
	if (cp->tccp.cblkwidthexpn + cp->tccp.cblkheightexpn > 12) {
		fprintf(stderr, "code block size too large\n");
		goto error;
	}

	/* Ensure that the number of layers is valid. */
	if (cp->tcp.numlyrs > 16384) {
		fprintf(stderr, "too many layers\n");
		goto error;
	}

	/* There must be at least one resolution level. */
	if (cp->tccp.maxrlvls < 1) {
		fprintf(stderr, "must be at least one resolution level\n");
		goto error;
	}

	/* Ensure that the number of guard bits is valid. */
	if (cp->tccp.numgbits > 8) {
		fprintf(stderr, "invalid number of guard bits\n");
		goto error;
	}

	/* Ensure that the rate is within the legal range. */
	if (cp->totalsize != UINT_FAST32_MAX && cp->totalsize > cp->rawsize) {
		fprintf(stderr, "warning: specified rate is unreasonably large (%lu > %lu)\n", (unsigned long) cp->totalsize, (unsigned long) cp->rawsize);
	}

	/* Ensure that the intermediate layer rates are valid. */
	if (tcp->numlyrs > 1) {
		/* The intermediate layers rates must increase monotonically. */
		for (lyrno = 0; lyrno + 2 < tcp->numlyrs; ++lyrno) {
			if (tcp->ilyrrates[lyrno] >= tcp->ilyrrates[lyrno + 1]) {
				fprintf(stderr, "intermediate layer rates must increase monotonically\n");
				goto error;
			}
		}
		/* The intermediate layer rates must be less than the overall rate. */
		if (cp->totalsize != UINT_FAST32_MAX) {
			for (lyrno = 0; lyrno < tcp->numlyrs - 1; ++lyrno) {
				if (jpc_fixtodbl(tcp->ilyrrates[lyrno]) > ((double) cp->totalsize)
				  / cp->rawsize) {
					fprintf(stderr, "warning: intermediate layer rates must be less than overall rate\n");
					goto error;
				}
			}
		}
	}

	if (ilyrrates) {
		jas_free(ilyrrates);
	}

	return cp;

error:

	if (ilyrrates) {
		jas_free(ilyrrates);
	}
	if (tvp) {
		jas_tvparser_destroy(tvp);
	}
	if (cp) {
		jpc_enc_cp_destroy(cp);
	}
	return 0;
}

void jpc_enc_cp_destroy(jpc_enc_cp_t *cp)
{
	if (cp->ccps) {
		if (cp->tcp.ilyrrates) {
			jas_free(cp->tcp.ilyrrates);
		}
		jas_free(cp->ccps);
	}
	jas_free(cp);
}

int ratestrtosize(char *s, uint_fast32_t rawsize, uint_fast32_t *size)
{
	char *cp;
	jpc_flt_t f;

	/* Note: This function must not modify output size on failure. */
	if ((cp = strchr(s, 'B'))) {
		*size = atoi(s);
	} else {
		f = atof(s);
		if (f < 0) {
			*size = 0;
		} else if (f > 1.0) {
			*size = rawsize + 1;
		} else {
			*size = (unsigned int)(f * rawsize);
		}
	}
	return 0;
}

/******************************************************************************\
* Encoder constructor and destructor.
\******************************************************************************/

jpc_enc_t *jpc_enc_create(jpc_enc_cp_t *cp, jas_stream_t *out, jas_image_t *image)
{
	jpc_enc_t *enc;

	enc = 0;

	if (!(enc = jas_malloc(sizeof(jpc_enc_t)))) {
		goto error;
	}

	enc->image = image;
	enc->out = out;
	enc->cp = cp;
	enc->cstate = 0;
	enc->tmpstream = 0;
	enc->mrk = 0;
	enc->curtile = 0;

	if (!(enc->cstate = jpc_cstate_create())) {
		goto error;
	}
	enc->len = 0;
	enc->mainbodysize = 0;

	return enc;

error:

	if (enc) {
		jpc_enc_destroy(enc);
	}
	return 0;
}

void jpc_enc_destroy(jpc_enc_t *enc)
{
	/* The image object (i.e., enc->image) and output stream object
	(i.e., enc->out) are created outside of the encoder.
	Therefore, they must not be destroyed here. */

	if (enc->curtile) {
		jpc_enc_tile_destroy(enc->curtile);
	}
	if (enc->cp) {
		jpc_enc_cp_destroy(enc->cp);
	}
	if (enc->cstate) {
		jpc_cstate_destroy(enc->cstate);
	}
	if (enc->tmpstream) {
		jas_stream_close(enc->tmpstream);
	}

	jas_free(enc);
}

/******************************************************************************\
* Code.
\******************************************************************************/

static int jpc_calcssmant(jpc_fix_t stepsize)
{
	int n;
	int e;
	int m;

	n = jpc_firstone(stepsize);
	e = n - JPC_FIX_FRACBITS;
	if (n >= 11) {
		m = (stepsize >> (n - 11)) & 0x7ff;
	} else {
		m = (stepsize & ((1 << n) - 1)) << (11 - n);
	}
	return m;
}

static int jpc_calcssexp(jpc_fix_t stepsize)
{
	return jpc_firstone(stepsize) - JPC_FIX_FRACBITS;
}

static int jpc_enc_encodemainhdr(jpc_enc_t *enc)
{
	jpc_siz_t *siz;
	jpc_cod_t *cod;
	jpc_qcd_t *qcd;
	int i;
long startoff;
long mainhdrlen;
	jpc_enc_cp_t *cp;
	jpc_qcc_t *qcc;
	jpc_enc_tccp_t *tccp;
	uint_fast16_t cmptno;
	jpc_tsfb_band_t bandinfos[JPC_MAXBANDS];
	jpc_fix_t mctsynweight;
	jpc_enc_tcp_t *tcp;
	jpc_tsfb_t *tsfb;
	jpc_tsfb_band_t *bandinfo;
	uint_fast16_t numbands;
	uint_fast16_t bandno;
	uint_fast16_t rlvlno;
	uint_fast16_t analgain;
	jpc_fix_t absstepsize;
	char buf[1024];
	jpc_com_t *com;

	cp = enc->cp;

startoff = jas_stream_getrwcount(enc->out);

	/* Write SOC marker segment. */
	if (!(enc->mrk = jpc_ms_create(JPC_MS_SOC))) {
		return -1;
	}
	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
		fprintf(stderr, "cannot write SOC marker\n");
		return -1;
	}
	jpc_ms_destroy(enc->mrk);
	enc->mrk = 0;

	/* Write SIZ marker segment. */
	if (!(enc->mrk = jpc_ms_create(JPC_MS_SIZ))) {
		return -1;
	}
	siz = &enc->mrk->parms.siz;
	siz->caps = 0;
	siz->xoff = cp->imgareatlx;
	siz->yoff = cp->imgareatly;
	siz->width = cp->refgrdwidth;
	siz->height = cp->refgrdheight;
	siz->tilexoff = cp->tilegrdoffx;
	siz->tileyoff = cp->tilegrdoffy;
	siz->tilewidth = cp->tilewidth;
	siz->tileheight = cp->tileheight;
	siz->numcomps = cp->numcmpts;
	siz->comps = jas_malloc(siz->numcomps * sizeof(jpc_sizcomp_t));
	assert(siz->comps);
	for (i = 0; i < JAS_CAST(int, cp->numcmpts); ++i) {
		siz->comps[i].prec = cp->ccps[i].prec;
		siz->comps[i].sgnd = cp->ccps[i].sgnd;
		siz->comps[i].hsamp = cp->ccps[i].sampgrdstepx;
		siz->comps[i].vsamp = cp->ccps[i].sampgrdstepy;
	}
	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
		fprintf(stderr, "cannot write SIZ marker\n");
		return -1;
	}
	jpc_ms_destroy(enc->mrk);
	enc->mrk = 0;

	if (!(enc->mrk = jpc_ms_create(JPC_MS_COM))) {
		return -1;
	}
	sprintf(buf, "Creator: JasPer Version %s", jas_getversion());
	com = &enc->mrk->parms.com;
	com->len = strlen(buf);
	com->regid = JPC_COM_LATIN;
	if (!(com->data = JAS_CAST(uchar *, jas_strdup(buf)))) {
		abort();
	}
	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
		fprintf(stderr, "cannot write COM marker\n");
		return -1;
	}
	jpc_ms_destroy(enc->mrk);
	enc->mrk = 0;

#if 0
	if (!(enc->mrk = jpc_ms_create(JPC_MS_CRG))) {
		return -1;
	}
	crg = &enc->mrk->parms.crg;
	crg->comps = jas_malloc(crg->numcomps * sizeof(jpc_crgcomp_t));
	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
		fprintf(stderr, "cannot write CRG marker\n");
		return -1;
	}
	jpc_ms_destroy(enc->mrk);
	enc->mrk = 0;
#endif

	tcp = &cp->tcp;
	tccp = &cp->tccp;
	for (cmptno = 0; cmptno < cp->numcmpts; ++cmptno) {
		tsfb = jpc_cod_gettsfb(tccp->qmfbid, tccp->maxrlvls - 1);
		jpc_tsfb_getbands(tsfb, 0, 0, 1 << tccp->maxrlvls, 1 << tccp->maxrlvls,
		  bandinfos);
		jpc_tsfb_destroy(tsfb);
		mctsynweight = jpc_mct_getsynweight(tcp->mctid, cmptno);
		numbands = 3 * tccp->maxrlvls - 2;
		for (bandno = 0, bandinfo = bandinfos; bandno < numbands;
		  ++bandno, ++bandinfo) {
			rlvlno = (bandno) ? ((bandno - 1) / 3 + 1) : 0;
			analgain = JPC_NOMINALGAIN(tccp->qmfbid, tccp->maxrlvls,
			  rlvlno, bandinfo->orient);
			if (!tcp->intmode) {
				absstepsize = jpc_fix_div(jpc_inttofix(1 <<
				  (analgain + 1)), bandinfo->synenergywt);
			} else {
				absstepsize = jpc_inttofix(1);
			}	
			cp->ccps[cmptno].stepsizes[bandno] =
			  jpc_abstorelstepsize(absstepsize,
			  cp->ccps[cmptno].prec + analgain);
		}
		cp->ccps[cmptno].numstepsizes = numbands;
	}

	if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) {
		return -1;
	}
	cod = &enc->mrk->parms.cod;
	cod->csty = cp->tccp.csty | cp->tcp.csty;
	cod->compparms.csty = cp->tccp.csty | cp->tcp.csty;
	cod->compparms.numdlvls = cp->tccp.maxrlvls - 1;
	cod->compparms.numrlvls = cp->tccp.maxrlvls;
	cod->prg = cp->tcp.prg;
	cod->numlyrs = cp->tcp.numlyrs;
	cod->compparms.cblkwidthval = JPC_COX_CBLKSIZEEXPN(cp->tccp.cblkwidthexpn);
	cod->compparms.cblkheightval = JPC_COX_CBLKSIZEEXPN(cp->tccp.cblkheightexpn);
	cod->compparms.cblksty = cp->tccp.cblksty;
	cod->compparms.qmfbid = cp->tccp.qmfbid;
	cod->mctrans = (cp->tcp.mctid != JPC_MCT_NONE);
	if (tccp->csty & JPC_COX_PRT) {
		for (rlvlno = 0; rlvlno < tccp->maxrlvls; ++rlvlno) {
			cod->compparms.rlvls[rlvlno].parwidthval = tccp->prcwidthexpns[rlvlno];
			cod->compparms.rlvls[rlvlno].parheightval = tccp->prcheightexpns[rlvlno];
		}
	}
	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
		fprintf(stderr, "cannot write COD marker\n");
		return -1;
	}
	jpc_ms_destroy(enc->mrk);
	enc->mrk = 0;

	if (!(enc->mrk = jpc_ms_create(JPC_MS_QCD))) {
		return -1;
	}
	qcd = &enc->mrk->parms.qcd;
	qcd->compparms.qntsty = (tccp->qmfbid == JPC_COX_INS) ?
	  JPC_QCX_SEQNT : JPC_QCX_NOQNT;
	qcd->compparms.numstepsizes = cp->ccps[0].numstepsizes;
	qcd->compparms.numguard = cp->tccp.numgbits;
	qcd->compparms.stepsizes = cp->ccps[0].stepsizes;
	if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
		return -1;
	}
	/* We do not want the step size array to be freed! */
	qcd->compparms.stepsizes = 0;
	jpc_ms_destroy(enc->mrk);
	enc->mrk = 0;

	tccp = &cp->tccp;
	for (cmptno = 1; cmptno < cp->numcmpts; ++cmptno) {
		if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) {
			return -1;
		}
		qcc = &enc->mrk->parms.qcc;
		qcc->compno = cmptno;
		qcc->compparms.qntsty = (tccp->qmfbid == JPC_COX_INS) ?
		  JPC_QCX_SEQNT : JPC_QCX_NOQNT;
		qcc->compparms.numstepsizes = cp->ccps[cmptno].numstepsizes;
		qcc->compparms.numguard = cp->tccp.numgbits;
		qcc->compparms.stepsizes = cp->ccps[cmptno].stepsizes;
		if (jpc_putms(enc->out, enc->cstate, enc->mrk)) {
			return -1;
		}
		/* We do not want the step size array to be freed! */
		qcc->compparms.stepsizes = 0;
		jpc_ms_destroy(enc->mrk);
		enc->mrk = 0;
	}

#define MAINTLRLEN	2
	mainhdrlen = jas_stream_getrwcount(enc->out) - startoff;
	enc->len += mainhdrlen;
	if (enc->cp->totalsize != UINT_FAST32_MAX) {
		uint_fast32_t overhead;
		overhead = mainhdrlen + MAINTLRLEN;
		enc->mainbodysize = (enc->cp->totalsize >= overhead) ?
		  (enc->cp->totalsize - overhead) : 0;
	} else {
		enc->mainbodysize = UINT_FAST32_MAX;
	}

	return 0;
}

static int jpc_enc_encodemainbody(jpc_enc_t *enc)
{
	int tileno;
	int tilex;
	int tiley;
	int i;
	jpc_sot_t *sot;
	jpc_enc_tcmpt_t *comp;
	jpc_enc_tcmpt_t *endcomps;
	jpc_enc_band_t *band;
	jpc_enc_band_t *endbands;
	jpc_enc_rlvl_t *lvl;
	int rlvlno;
	jpc_qcc_t *qcc;
	jpc_cod_t *cod;
	int adjust;
	int j;
	int absbandno;
	long numbytes;
	long tilehdrlen;
	long tilelen;
	jpc_enc_tile_t *tile;
	jpc_enc_cp_t *cp;
	double rho;
	int lyrno;
	int cmptno;
	int samestepsizes;
	jpc_enc_ccp_t *ccps;
	jpc_enc_tccp_t *tccp;
int bandno;
uint_fast32_t x;
uint_fast32_t y;
int mingbits;
int actualnumbps;
jpc_fix_t mxmag;
jpc_fix_t mag;
int numgbits;

	cp = enc->cp;

	/* Avoid compile warnings. */
	numbytes = 0;

	for (tileno = 0; tileno < JAS_CAST(int, cp->numtiles); ++tileno) {
		tilex = tileno % cp->numhtiles;
		tiley = tileno / cp->numhtiles;

		if (!(enc->curtile = jpc_enc_tile_create(enc->cp, enc->image, tileno))) {
			abort();
		}

		tile = enc->curtile;

		if (jas_getdbglevel() >= 10) {
			jpc_enc_dump(enc);
		}

		endcomps = &tile->tcmpts[tile->numtcmpts];
		for (cmptno = 0, comp = tile->tcmpts; cmptno < tile->numtcmpts; ++cmptno, ++comp) {
			if (!cp->ccps[cmptno].sgnd) {
				adjust = 1 << (cp->ccps[cmptno].prec - 1);
				for (i = 0; i < jas_matrix_numrows(comp->data); ++i) {
					for (j = 0; j < jas_matrix_numcols(comp->data); ++j) {
						*jas_matrix_getref(comp->data, i, j) -= adjust;
					}
				}
			}
		}

		if (!tile->intmode) {
				endcomps = &tile->tcmpts[tile->numtcmpts];
				for (comp = tile->tcmpts; comp != endcomps; ++comp) {
					jas_matrix_asl(comp->data, JPC_FIX_FRACBITS);
				}
		}

		switch (tile->mctid) {
		case JPC_MCT_RCT:
assert(jas_image_numcmpts(enc->image) == 3);
			jpc_rct(tile->tcmpts[0].data, tile->tcmpts[1].data,
			  tile->tcmpts[2].data);
			break;
		case JPC_MCT_ICT:
assert(jas_image_numcmpts(enc->image) == 3);
			jpc_ict(tile->tcmpts[0].data, tile->tcmpts[1].data,
			  tile->tcmpts[2].data);
			break;
		default:
			break;
		}

		for (i = 0; i < jas_image_numcmpts(enc->image); ++i) {
			comp = &tile->tcmpts[i];
			jpc_tsfb_analyze(comp->tsfb, ((comp->qmfbid == JPC_COX_RFT) ? JPC_TSFB_RITIMODE : 0), comp->data);

		}


		endcomps = &tile->tcmpts[tile->numtcmpts];
		for (cmptno = 0, comp = tile->tcmpts; comp != endcomps; ++cmptno, ++comp) {
			mingbits = 0;
			absbandno = 0;
			/* All bands must have a corresponding quantizer step size,
			  even if they contain no samples and are never coded. */
			/* Some bands may not be hit by the loop below, so we must
			  initialize all of the step sizes to a sane value. */
			memset(comp->stepsizes, 0, sizeof(comp->stepsizes));
			for (rlvlno = 0, lvl = comp->rlvls; rlvlno < comp->numrlvls; ++rlvlno, ++lvl) {
				if (!lvl->bands) {
					absbandno += rlvlno ? 3 : 1;
					continue;
				}
				endbands = &lvl->bands[lvl->numbands];
				for (band = lvl->bands; band != endbands; ++band) {
					if (!band->data) {
						++absbandno;
						continue;
					}
					actualnumbps = 0;
					mxmag = 0;
					for (y = 0; y < JAS_CAST(uint_fast32_t, jas_matrix_numrows(band->data)); ++y) {
						for (x = 0; x < JAS_CAST(uint_fast32_t, jas_matrix_numcols(band->data)); ++x) {
							mag = abs(jas_matrix_get(band->data, y, x));
							if (mag > mxmag) {
								mxmag = mag;
							}
						}
					}
					if (tile->intmode) {
						actualnumbps = jpc_firstone(mxmag) + 1;
					} else {
						actualnumbps = jpc_firstone(mxmag) + 1 - JPC_FIX_FRACBITS;
					}
					numgbits = actualnumbps - (cp->ccps[cmptno].prec - 1 +
					  band->analgain);
#if 0
fprintf(stderr, "%d %d mag=%d actual=%d numgbits=%d\n", cp->ccps[cmptno].prec, band->analgain, mxmag, actualnumbps, numgbits);
#endif
					if (numgbits > mingbits) {
						mingbits = numgbits;
					}
					if (!tile->intmode) {
						band->absstepsize = jpc_fix_div(jpc_inttofix(1
						  << (band->analgain + 1)),
						  band->synweight);
					} else {
						band->absstepsize = jpc_inttofix(1);
					}
					band->stepsize = jpc_abstorelstepsize(
					  band->absstepsize, cp->ccps[cmptno].prec +
					  band->analgain);
					band->numbps = cp->tccp.numgbits +
					  JPC_QCX_GETEXPN(band->stepsize) - 1;

					if ((!tile->intmode) && band->data) {
						quantize(band->data, band->absstepsize);
					}

					comp->stepsizes[absbandno] = band->stepsize;
					++absbandno;
				}
			}

			assert(JPC_FIX_FRACBITS >= JPC_NUMEXTRABITS);
			if (!tile->intmode) {
				jas_matrix_divpow2(comp->data, JPC_FIX_FRACBITS - JPC_NUMEXTRABITS);
			} else {
				jas_matrix_asl(comp->data, JPC_NUMEXTRABITS);
			}

#if 0
fprintf(stderr, "mingbits %d\n", mingbits);
#endif
			if (mingbits > cp->tccp.numgbits) {
				fprintf(stderr, "error: too few guard bits (need at least %d)\n",
				  mingbits);
				return -1;
			}
		}

		if (!(enc->tmpstream = jas_stream_memopen(0, 0))) {
			fprintf(stderr, "cannot open tmp file\n");
			return -1;
		}

		/* Write the tile header. */
		if (!(enc->mrk = jpc_ms_create(JPC_MS_SOT))) {
			return -1;
		}
		sot = &enc->mrk->parms.sot;
		sot->len = 0;
		sot->tileno = tileno;
		sot->partno = 0;
		sot->numparts = 1;
		if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
			fprintf(stderr, "cannot write SOT marker\n");
			return -1;
		}
		jpc_ms_destroy(enc->mrk);
		enc->mrk = 0;

/************************************************************************/
/************************************************************************/
/************************************************************************/

		tccp = &cp->tccp;
		for (cmptno = 0; cmptno < JAS_CAST(int, cp->numcmpts); ++cmptno) {
			comp = &tile->tcmpts[cmptno];
			if (comp->numrlvls != tccp->maxrlvls) {
				if (!(enc->mrk = jpc_ms_create(JPC_MS_COD))) {
					return -1;
				}
/* XXX = this is not really correct. we are using comp #0's precint sizes
and other characteristics */
				comp = &tile->tcmpts[0];
				cod = &enc->mrk->parms.cod;
				cod->compparms.csty = 0;
				cod->compparms.numdlvls = comp->numrlvls - 1;
				cod->prg = tile->prg;
				cod->numlyrs = tile->numlyrs;
				cod->compparms.cblkwidthval = JPC_COX_CBLKSIZEEXPN(comp->cblkwidthexpn);
				cod->compparms.cblkheightval = JPC_COX_CBLKSIZEEXPN(comp->cblkheightexpn);
				cod->compparms.cblksty = comp->cblksty;
				cod->compparms.qmfbid = comp->qmfbid;
				cod->mctrans = (tile->mctid != JPC_MCT_NONE);
				for (i = 0; i < comp->numrlvls; ++i) {
					cod->compparms.rlvls[i].parwidthval = comp->rlvls[i].prcwidthexpn;
					cod->compparms.rlvls[i].parheightval = comp->rlvls[i].prcheightexpn;
				}
				if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
					return -1;
				}
				jpc_ms_destroy(enc->mrk);
				enc->mrk = 0;
			}
		}

		for (cmptno = 0, comp = tile->tcmpts; cmptno < JAS_CAST(int, cp->numcmpts); ++cmptno, ++comp) {
			ccps = &cp->ccps[cmptno];
			if (JAS_CAST(int, ccps->numstepsizes) == comp->numstepsizes) {
				samestepsizes = 1;
				for (bandno = 0; bandno < JAS_CAST(int, ccps->numstepsizes); ++bandno) {
					if (ccps->stepsizes[bandno] != comp->stepsizes[bandno]) {
						samestepsizes = 0;
						break;
					}
				}
			} else {
				samestepsizes = 0;
			}
			if (!samestepsizes) {
				if (!(enc->mrk = jpc_ms_create(JPC_MS_QCC))) {
					return -1;
				}
				qcc = &enc->mrk->parms.qcc;
				qcc->compno = cmptno;
				qcc->compparms.numguard = cp->tccp.numgbits;
				qcc->compparms.qntsty = (comp->qmfbid == JPC_COX_INS) ?
				  JPC_QCX_SEQNT : JPC_QCX_NOQNT;
				qcc->compparms.numstepsizes = comp->numstepsizes;
				qcc->compparms.stepsizes = comp->stepsizes;
				if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
					return -1;
				}
				qcc->compparms.stepsizes = 0;
				jpc_ms_destroy(enc->mrk);
				enc->mrk = 0;
			}
		}

		/* Write a SOD marker to indicate the end of the tile header. */
		if (!(enc->mrk = jpc_ms_create(JPC_MS_SOD))) {
			return -1;
		}
		if (jpc_putms(enc->tmpstream, enc->cstate, enc->mrk)) {
			fprintf(stderr, "cannot write SOD marker\n");
			return -1;
		}
		jpc_ms_destroy(enc->mrk);
		enc->mrk = 0;
tilehdrlen = jas_stream_getrwcount(enc->tmpstream);

/************************************************************************/
/************************************************************************/
/************************************************************************/

if (jpc_enc_enccblks(enc)) {
	abort();
	return -1;
}

		cp = enc->cp;
		rho = (double) (tile->brx - tile->tlx) * (tile->bry - tile->tly) /
		  ((cp->refgrdwidth - cp->imgareatlx) * (cp->refgrdheight -
		  cp->imgareatly));
		tile->rawsize = (unsigned int)(cp->rawsize * rho);

		for (lyrno = 0; lyrno < tile->numlyrs - 1; ++lyrno) {
			tile->lyrsizes[lyrno] = (unsigned int)(tile->rawsize * jpc_fixtodbl(
			  cp->tcp.ilyrrates[lyrno]));
		}
		tile->lyrsizes[tile->numlyrs - 1] = (cp->totalsize != UINT_FAST32_MAX) ?
		  (unsigned int)(rho * enc->mainbodysize) : UINT_FAST32_MAX;
		for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) {
			if (tile->lyrsizes[lyrno] != UINT_FAST32_MAX) {
				if (tilehdrlen <= JAS_CAST(long, tile->lyrsizes[lyrno])) {
					tile->lyrsizes[lyrno] -= tilehdrlen;
				} else {
					tile->lyrsizes[lyrno] = 0;
				}
			}
		}

		if (rateallocate(enc, tile->numlyrs, tile->lyrsizes)) {
			return -1;
		}

#if 0
fprintf(stderr, "ENCODE TILE DATA\n");
#endif
		if (jpc_enc_encodetiledata(enc)) {
			fprintf(stderr, "dotile failed\n");
			return -1;
		}

/************************************************************************/
/************************************************************************/
/************************************************************************/

/************************************************************************/
/************************************************************************/
/************************************************************************/

		tilelen = jas_stream_tell(enc->tmpstream);

		if (jas_stream_seek(enc->tmpstream, 6, SEEK_SET) < 0) {
			return -1;
		}
		jpc_putuint32(enc->tmpstream, tilelen);

		if (jas_stream_seek(enc->tmpstream, 0, SEEK_SET) < 0) {
			return -1;
		}
		if (jpc_putdata(enc->out, enc->tmpstream, -1)) {
			return -1;
		}
		enc->len += tilelen;

		jas_stream_close(enc->tmpstream);
		enc->tmpstream = 0;

		jpc_enc_tile_destroy(enc->curtile);
		enc->curtile = 0;

	}

	return 0;
}

int jpc_enc_encodetiledata(jpc_enc_t *enc)
{
assert(enc->tmpstream);
	if (jpc_enc_encpkts(enc, enc->tmpstream)) {
		return -1;
	}
	return 0;
}

int dump_passes(jpc_enc_pass_t *passes, int numpasses, jpc_enc_cblk_t *cblk)
{
	jpc_enc_pass_t *pass;
	int i;
	jas_stream_memobj_t *smo;

	smo = cblk->stream->obj_;

	pass = passes;
	for (i = 0; i < numpasses; ++i) {
		fprintf(stderr, "start=%d end=%d type=%d term=%d lyrno=%d firstchar=%02x size=%ld pos=%ld\n",
		  (int)pass->start, (int)pass->end, (int)pass->type, (int)pass->term, (int)pass->lyrno,
		  smo->buf_[pass->start], (long)smo->len_, (long)smo->pos_);
#if 0
		jas_memdump(stderr, &smo->buf_[pass->start], pass->end - pass->start);
#endif
		++pass;
	}
	return 0;
}

void quantize(jas_matrix_t *data, jpc_fix_t stepsize)
{
	int i;
	int j;
	jpc_fix_t t;

	if (stepsize == jpc_inttofix(1)) {
		return;
	}

	for (i = 0; i < jas_matrix_numrows(data); ++i) {
		for (j = 0; j < jas_matrix_numcols(data); ++j) {
			t = jas_matrix_get(data, i, j);

{
	if (t < 0) {
		t = jpc_fix_neg(jpc_fix_div(jpc_fix_neg(t), stepsize));
	} else {
		t = jpc_fix_div(t, stepsize);
	}
}

			jas_matrix_set(data, i, j, t);
		}
	}
}

void calcrdslopes(jpc_enc_cblk_t *cblk)
{
	jpc_enc_pass_t *endpasses;
	jpc_enc_pass_t *pass0;
	jpc_enc_pass_t *pass1;
	jpc_enc_pass_t *pass2;
	jpc_flt_t slope0;
	jpc_flt_t slope;
	jpc_flt_t dd;
	long dr;

	endpasses = &cblk->passes[cblk->numpasses];
	pass2 = cblk->passes;
	slope0 = 0;
	while (pass2 != endpasses) {
		pass0 = 0;
		for (pass1 = cblk->passes; pass1 != endpasses; ++pass1) {
			dd = pass1->cumwmsedec;
			dr = pass1->end;
			if (pass0) {
				dd -= pass0->cumwmsedec;
				dr -= pass0->end;
			}
			if (dd <= 0) {
				pass1->rdslope = JPC_BADRDSLOPE;
				if (pass1 >= pass2) {
					pass2 = &pass1[1];
				}
				continue;
			}
			if (pass1 < pass2 && pass1->rdslope <= 0) {
				continue;
			}
			if (!dr) {
				assert(pass0);
				pass0->rdslope = 0;
				break;
			}
			slope = dd / dr;
			if (pass0 && slope >= slope0) {
				pass0->rdslope = 0;
				break;
			}
			pass1->rdslope = slope;
			if (pass1 >= pass2) {
				pass2 = &pass1[1];
			}
			pass0 = pass1;
			slope0 = slope;
		}
	}

#if 0
	for (pass0 = cblk->passes; pass0 != endpasses; ++pass0) {
if (pass0->rdslope > 0.0) {
		fprintf(stderr, "pass %02d nmsedec=%lf dec=%lf end=%d %lf\n", pass0 - cblk->passes,
		  fixtodbl(pass0->nmsedec), pass0->wmsedec, pass0->end, pass0->rdslope);
}
	}
#endif
}

void dump_layeringinfo(jpc_enc_t *enc)
{

	jpc_enc_tcmpt_t *tcmpt;
	int tcmptno;
	jpc_enc_rlvl_t *rlvl;
	int rlvlno;
	jpc_enc_band_t *band;
	int bandno;
	jpc_enc_prc_t *prc;
	int prcno;
	jpc_enc_cblk_t *cblk;
	int cblkno;
	jpc_enc_pass_t *pass;
	int passno;
	int lyrno;
	jpc_enc_tile_t *tile;

	tile = enc->curtile;

	for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) {
		fprintf(stderr, "lyrno = %02d\n", lyrno);
		for (tcmptno = 0, tcmpt = tile->tcmpts; tcmptno < tile->numtcmpts;
		  ++tcmptno, ++tcmpt) {
			for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
			  ++rlvlno, ++rlvl) {
				if (!rlvl->bands) {
					continue;
				}
				for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
				  ++bandno, ++band) {
					if (!band->data) {
						continue;
					}
					for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs;
					  ++prcno, ++prc) {
						if (!prc->cblks) {
							continue;
						}
						for (cblkno = 0, cblk = prc->cblks; cblkno <
						  prc->numcblks; ++cblkno, ++cblk) {
							for (passno = 0, pass = cblk->passes; passno <
							  cblk->numpasses && pass->lyrno == lyrno;
							  ++passno, ++pass) {
								fprintf(stderr, "lyrno=%02d cmptno=%02d rlvlno=%02d bandno=%02d prcno=%02d cblkno=%03d passno=%03d\n", lyrno, tcmptno, rlvlno, bandno, prcno, cblkno, passno);
							}
						}
					}
				}
			}
		}
	}
}

int rateallocate(jpc_enc_t *enc, int numlyrs, uint_fast32_t *cumlens)
{
	jpc_flt_t lo;
	jpc_flt_t hi;
	jas_stream_t *out;
	long cumlen;
	int lyrno;
	jpc_flt_t thresh;
	jpc_flt_t goodthresh;
	int success;
	long pos;
	long oldpos;
	int numiters;

	jpc_enc_tcmpt_t *comp;
	jpc_enc_tcmpt_t *endcomps;
	jpc_enc_rlvl_t *lvl;
	jpc_enc_rlvl_t *endlvls;
	jpc_enc_band_t *band;
	jpc_enc_band_t *endbands;
	jpc_enc_cblk_t *cblk;
	jpc_enc_cblk_t *endcblks;
	jpc_enc_pass_t *pass;
	jpc_enc_pass_t *endpasses;
	jpc_enc_pass_t *pass1;
	jpc_flt_t mxrdslope;
	jpc_flt_t mnrdslope;
	jpc_enc_tile_t *tile;
	jpc_enc_prc_t *prc;
	int prcno;

	tile = enc->curtile;

	for (lyrno = 1; lyrno < numlyrs - 1; ++lyrno) {
		if (cumlens[lyrno - 1] > cumlens[lyrno]) {
			abort();
		}
	}

	if (!(out = jas_stream_memopen(0, 0))) {
		return -1;
	}


	/* Find minimum and maximum R-D slope values. */
	mnrdslope = DBL_MAX;
	mxrdslope = 0;
	endcomps = &tile->tcmpts[tile->numtcmpts];
	for (comp = tile->tcmpts; comp != endcomps; ++comp) {
		endlvls = &comp->rlvls[comp->numrlvls];
		for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
			if (!lvl->bands) {
				continue;
			}
			endbands = &lvl->bands[lvl->numbands];
			for (band = lvl->bands; band != endbands; ++band) {
				if (!band->data) {
					continue;
				}
				for (prcno = 0, prc = band->prcs; prcno < lvl->numprcs; ++prcno, ++prc) {
					if (!prc->cblks) {
						continue;
					}
					endcblks = &prc->cblks[prc->numcblks];
					for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
						calcrdslopes(cblk);
						endpasses = &cblk->passes[cblk->numpasses];
						for (pass = cblk->passes; pass != endpasses; ++pass) {
							if (pass->rdslope > 0) {
								if (pass->rdslope < mnrdslope) {
									mnrdslope = pass->rdslope;
								}
								if (pass->rdslope > mxrdslope) {
									mxrdslope = pass->rdslope;
								}
							}
						}
					}
				}
			}
		}
	}
if (jas_getdbglevel()) {
	fprintf(stderr, "min rdslope = %f max rdslope = %f\n", mnrdslope, mxrdslope);
}

	jpc_init_t2state(enc, 1);

	for (lyrno = 0; lyrno < numlyrs; ++lyrno) {

		lo = mnrdslope;
		hi = mxrdslope;

		success = 0;
		goodthresh = 0;
		numiters = 0;

		do {

			cumlen = cumlens[lyrno];
			if (cumlen == UINT_FAST32_MAX) {
				/* Only the last layer can be free of a rate
				  constraint (e.g., for lossless coding). */
				assert(lyrno == numlyrs - 1);
				goodthresh = -1;
				success = 1;
				break;
			}

			thresh = (lo + hi) / 2;

			/* Save the tier 2 coding state. */
			jpc_save_t2state(enc);
			oldpos = jas_stream_tell(out);
			assert(oldpos >= 0);

			/* Assign all passes with R-D slopes greater than or
			  equal to the current threshold to this layer. */
			endcomps = &tile->tcmpts[tile->numtcmpts];
			for (comp = tile->tcmpts; comp != endcomps; ++comp) {
				endlvls = &comp->rlvls[comp->numrlvls];
				for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
					if (!lvl->bands) {
						continue;
					}
					endbands = &lvl->bands[lvl->numbands];
					for (band = lvl->bands; band != endbands; ++band) {
						if (!band->data) {
							continue;
						}
						for (prcno = 0, prc = band->prcs; prcno < lvl->numprcs; ++prcno, ++prc) {
							if (!prc->cblks) {
								continue;
							}
							endcblks = &prc->cblks[prc->numcblks];
							for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
								if (cblk->curpass) {
									endpasses = &cblk->passes[cblk->numpasses];
									pass1 = cblk->curpass;
									for (pass = cblk->curpass; pass != endpasses; ++pass) {
										if (pass->rdslope >= thresh) {
											pass1 = &pass[1];
										}
									}
									for (pass = cblk->curpass; pass != pass1; ++pass) {
										pass->lyrno = lyrno;
									}
									for (; pass != endpasses; ++pass) {
										pass->lyrno = -1;
									}
								}
							}
						}
					}
				}
			}

			/* Perform tier 2 coding. */
			endcomps = &tile->tcmpts[tile->numtcmpts];
			for (comp = tile->tcmpts; comp != endcomps; ++comp) {
				endlvls = &comp->rlvls[comp->numrlvls];
				for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
					if (!lvl->bands) {
						continue;
					}
					for (prcno = 0; prcno < lvl->numprcs; ++prcno) {
						if (jpc_enc_encpkt(enc, out, comp - tile->tcmpts, lvl - comp->rlvls, prcno, lyrno)) {
							return -1;
						}
					}
				}
			}

			pos = jas_stream_tell(out);

			/* Check the rate constraint. */
			assert(pos >= 0);
			if (pos > cumlen) {
				/* The rate is too high. */
				lo = thresh;
			} else if (pos <= cumlen) {
				/* The rate is low enough, so try higher. */
				hi = thresh;
				if (!success || thresh < goodthresh) {
					goodthresh = thresh;
					success = 1;
				}
			}

			/* Save the tier 2 coding state. */
			jpc_restore_t2state(enc);
			if (jas_stream_seek(out, oldpos, SEEK_SET) < 0) {
				abort();
			}

if (jas_getdbglevel()) {
fprintf(stderr, "maxlen=%08ld actuallen=%08ld thresh=%f\n", cumlen, pos, thresh);
}

			++numiters;
		} while (lo < hi - 1e-3 && numiters < 32);

		if (!success) {
			fprintf(stderr, "warning: empty layer generated\n");
		}

if (jas_getdbglevel()) {
fprintf(stderr, "success %d goodthresh %f\n", success, goodthresh);
}

		/* Assign all passes with R-D slopes greater than or
		  equal to the selected threshold to this layer. */
		endcomps = &tile->tcmpts[tile->numtcmpts];
		for (comp = tile->tcmpts; comp != endcomps; ++comp) {
			endlvls = &comp->rlvls[comp->numrlvls];
			for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
if (!lvl->bands) {
	continue;
}
				endbands = &lvl->bands[lvl->numbands];
				for (band = lvl->bands; band != endbands; ++band) {
					if (!band->data) {
						continue;
					}
					for (prcno = 0, prc = band->prcs; prcno < lvl->numprcs; ++prcno, ++prc) {
						if (!prc->cblks) {
							continue;
						}
						endcblks = &prc->cblks[prc->numcblks];
						for (cblk = prc->cblks; cblk != endcblks; ++cblk) {
							if (cblk->curpass) {
								endpasses = &cblk->passes[cblk->numpasses];
								pass1 = cblk->curpass;
								if (success) {
									for (pass = cblk->curpass; pass != endpasses; ++pass) {
										if (pass->rdslope >= goodthresh) {
											pass1 = &pass[1];
										}
									}
								}
								for (pass = cblk->curpass; pass != pass1; ++pass) {
									pass->lyrno = lyrno;
								}
								for (; pass != endpasses; ++pass) {
									pass->lyrno = -1;
								}
							}
						}
					}
				}
			}
		}

		/* Perform tier 2 coding. */
		endcomps = &tile->tcmpts[tile->numtcmpts];
		for (comp = tile->tcmpts; comp != endcomps; ++comp) {
			endlvls = &comp->rlvls[comp->numrlvls];
			for (lvl = comp->rlvls; lvl != endlvls; ++lvl) {
				if (!lvl->bands) {
					continue;
				}
				for (prcno = 0; prcno < lvl->numprcs; ++prcno) {
					if (jpc_enc_encpkt(enc, out, comp - tile->tcmpts, lvl - comp->rlvls, prcno, lyrno)) {
						return -1;
					}
				}
			}
		}
	}

	if (jas_getdbglevel() >= 5) {
		dump_layeringinfo(enc);
	}

	jas_stream_close(out);

	JAS_DBGLOG(10, ("done doing rateallocation\n"));
#if 0
fprintf(stderr, "DONE RATE ALLOCATE\n");
#endif

	return 0;
}

/******************************************************************************\
* Tile constructors and destructors.
\******************************************************************************/

jpc_enc_tile_t *jpc_enc_tile_create(jpc_enc_cp_t *cp, jas_image_t *image, int tileno)
{
	jpc_enc_tile_t *tile;
	uint_fast32_t htileno;
	uint_fast32_t vtileno;
	uint_fast16_t lyrno;
	uint_fast16_t cmptno;
	jpc_enc_tcmpt_t *tcmpt;

	if (!(tile = jas_malloc(sizeof(jpc_enc_tile_t)))) {
		goto error;
	}

	/* Initialize a few members used in error recovery. */
	tile->tcmpts = 0;
	tile->lyrsizes = 0;
	tile->numtcmpts = cp->numcmpts;
	tile->pi = 0;

	tile->tileno = tileno;
	htileno = tileno % cp->numhtiles;
	vtileno = tileno / cp->numhtiles;

	/* Calculate the coordinates of the top-left and bottom-right
	  corners of the tile. */
	tile->tlx = JAS_MAX(cp->tilegrdoffx + htileno * cp->tilewidth,
	  cp->imgareatlx);
	tile->tly = JAS_MAX(cp->tilegrdoffy + vtileno * cp->tileheight,
	  cp->imgareatly);
	tile->brx = JAS_MIN(cp->tilegrdoffx + (htileno + 1) * cp->tilewidth,
	  cp->refgrdwidth);
	tile->bry = JAS_MIN(cp->tilegrdoffy + (vtileno + 1) * cp->tileheight,
	  cp->refgrdheight);

	/* Initialize some tile coding parameters. */
	tile->intmode = cp->tcp.intmode;
	tile->csty = cp->tcp.csty;
	tile->prg = cp->tcp.prg;
	tile->mctid = cp->tcp.mctid;

	tile->numlyrs = cp->tcp.numlyrs;
	if (!(tile->lyrsizes = jas_malloc(tile->numlyrs *
	  sizeof(uint_fast32_t)))) {
		goto error;
	}
	for (lyrno = 0; lyrno < tile->numlyrs; ++lyrno) {
		tile->lyrsizes[lyrno] = 0;
	}

	/* Allocate an array for the per-tile-component information. */
	if (!(tile->tcmpts = jas_malloc(cp->numcmpts * sizeof(jpc_enc_tcmpt_t)))) {
		goto error;
	}
	/* Initialize a few members critical for error recovery. */
	for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts;
	  ++cmptno, ++tcmpt) {
		tcmpt->rlvls = 0;
		tcmpt->tsfb = 0;
		tcmpt->data = 0;
	}
	/* Initialize the per-tile-component information. */
	for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts;
	  ++cmptno, ++tcmpt) {
		if (!tcmpt_create(tcmpt, cp, image, tile)) {
			goto error;
		}
	}

	/* Initialize the synthesis weights for the MCT. */
	switch (tile->mctid) {
	case JPC_MCT_RCT:
		tile->tcmpts[0].synweight = jpc_dbltofix(sqrt(3.0));
		tile->tcmpts[1].synweight = jpc_dbltofix(sqrt(0.6875));
		tile->tcmpts[2].synweight = jpc_dbltofix(sqrt(0.6875));
		break;
	case JPC_MCT_ICT:
		tile->tcmpts[0].synweight = jpc_dbltofix(sqrt(3.0000));
		tile->tcmpts[1].synweight = jpc_dbltofix(sqrt(3.2584));
		tile->tcmpts[2].synweight = jpc_dbltofix(sqrt(2.4755));
		break;
	default:
	case JPC_MCT_NONE:
		for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < cp->numcmpts;
		  ++cmptno, ++tcmpt) {
			tcmpt->synweight = JPC_FIX_ONE;
		}
		break;
	}

	if (!(tile->pi = jpc_enc_pi_create(cp, tile))) {
		goto error;
	}

	return tile;

error:

	if (tile) {
		jpc_enc_tile_destroy(tile);
	}
	return 0;
}

void jpc_enc_tile_destroy(jpc_enc_tile_t *tile)
{
	jpc_enc_tcmpt_t *tcmpt;
	uint_fast16_t cmptno;

	if (tile->tcmpts) {
		for (cmptno = 0, tcmpt = tile->tcmpts; cmptno <
		  tile->numtcmpts; ++cmptno, ++tcmpt) {
			tcmpt_destroy(tcmpt);
		}
		jas_free(tile->tcmpts);
	}
	if (tile->lyrsizes) {
		jas_free(tile->lyrsizes);
	}
	if (tile->pi) {
		jpc_pi_destroy(tile->pi);
	}
	jas_free(tile);
}

static jpc_enc_tcmpt_t *tcmpt_create(jpc_enc_tcmpt_t *tcmpt, jpc_enc_cp_t *cp,
  jas_image_t *image, jpc_enc_tile_t *tile)
{
	uint_fast16_t cmptno;
	uint_fast16_t rlvlno;
	jpc_enc_rlvl_t *rlvl;
	uint_fast32_t tlx;
	uint_fast32_t tly;
	uint_fast32_t brx;
	uint_fast32_t bry;
	uint_fast32_t cmpttlx;
	uint_fast32_t cmpttly;
	jpc_enc_ccp_t *ccp;
	jpc_tsfb_band_t bandinfos[JPC_MAXBANDS];

	tcmpt->tile = tile;
	tcmpt->tsfb = 0;
	tcmpt->data = 0;
	tcmpt->rlvls = 0;

	/* Deduce the component number. */
	cmptno = tcmpt - tile->tcmpts;

	ccp = &cp->ccps[cmptno];

	/* Compute the coordinates of the top-left and bottom-right
	  corners of this tile-component. */
	tlx = JPC_CEILDIV(tile->tlx, ccp->sampgrdstepx);
	tly = JPC_CEILDIV(tile->tly, ccp->sampgrdstepy);
	brx = JPC_CEILDIV(tile->brx, ccp->sampgrdstepx);
	bry = JPC_CEILDIV(tile->bry, ccp->sampgrdstepy);

	/* Create a sequence to hold the tile-component sample data. */
	if (!(tcmpt->data = jas_seq2d_create(tlx, tly, brx, bry))) {
		goto error;
	}

	/* Get the image data associated with this tile-component. */
	cmpttlx = JPC_CEILDIV(cp->imgareatlx, ccp->sampgrdstepx);
	cmpttly = JPC_CEILDIV(cp->imgareatly, ccp->sampgrdstepy);
	if (jas_image_readcmpt(image, cmptno, tlx - cmpttlx, tly - cmpttly,
	  brx - tlx, bry - tly, tcmpt->data)) {
		goto error;
	}

	tcmpt->synweight = 0;
	tcmpt->qmfbid = cp->tccp.qmfbid;
	tcmpt->numrlvls = cp->tccp.maxrlvls;
	tcmpt->numbands = 3 * tcmpt->numrlvls - 2;
	if (!(tcmpt->tsfb = jpc_cod_gettsfb(tcmpt->qmfbid, tcmpt->numrlvls - 1))) {
		goto error;
	}

	for (rlvlno = 0; rlvlno < tcmpt->numrlvls; ++rlvlno) {
		tcmpt->prcwidthexpns[rlvlno] = cp->tccp.prcwidthexpns[rlvlno];
		tcmpt->prcheightexpns[rlvlno] = cp->tccp.prcheightexpns[rlvlno];
	}
	tcmpt->cblkwidthexpn = cp->tccp.cblkwidthexpn;
	tcmpt->cblkheightexpn = cp->tccp.cblkheightexpn;
	tcmpt->cblksty = cp->tccp.cblksty;
	tcmpt->csty = cp->tccp.csty;

	tcmpt->numstepsizes = tcmpt->numbands;
	assert(tcmpt->numstepsizes <= JPC_MAXBANDS);
	memset(tcmpt->stepsizes, 0, sizeof(tcmpt->numstepsizes *
	  sizeof(uint_fast16_t)));

	/* Retrieve information about the various bands. */
	jpc_tsfb_getbands(tcmpt->tsfb, jas_seq2d_xstart(tcmpt->data),
	  jas_seq2d_ystart(tcmpt->data), jas_seq2d_xend(tcmpt->data),
	  jas_seq2d_yend(tcmpt->data), bandinfos);

	if (!(tcmpt->rlvls = jas_malloc(tcmpt->numrlvls * sizeof(jpc_enc_rlvl_t)))) {
		goto error;
	}
	for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
	  ++rlvlno, ++rlvl) {
		rlvl->bands = 0;
		rlvl->tcmpt = tcmpt;
	}
	for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
	  ++rlvlno, ++rlvl) {
		if (!rlvl_create(rlvl, cp, tcmpt, bandinfos)) {
			goto error;
		}
	}

	return tcmpt;

error:

	tcmpt_destroy(tcmpt);
	return 0;

}

static void tcmpt_destroy(jpc_enc_tcmpt_t *tcmpt)
{
	jpc_enc_rlvl_t *rlvl;
	uint_fast16_t rlvlno;

	if (tcmpt->rlvls) {
		for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
		  ++rlvlno, ++rlvl) {
			rlvl_destroy(rlvl);
		}
		jas_free(tcmpt->rlvls);
	}

	if (tcmpt->data) {
		jas_seq2d_destroy(tcmpt->data);
	}
	if (tcmpt->tsfb) {
		jpc_tsfb_destroy(tcmpt->tsfb);
	}
}

static jpc_enc_rlvl_t *rlvl_create(jpc_enc_rlvl_t *rlvl, jpc_enc_cp_t *cp,
  jpc_enc_tcmpt_t *tcmpt, jpc_tsfb_band_t *bandinfos)
{
	uint_fast16_t rlvlno;
	uint_fast32_t tlprctlx;
	uint_fast32_t tlprctly;
	uint_fast32_t brprcbrx;
	uint_fast32_t brprcbry;
	uint_fast16_t bandno;
	jpc_enc_band_t *band;

	/* Deduce the resolution level. */
	rlvlno = rlvl - tcmpt->rlvls;

	/* Initialize members required for error recovery. */
	rlvl->bands = 0;
	rlvl->tcmpt = tcmpt;

	/* Compute the coordinates of the top-left and bottom-right
	  corners of the tile-component at this resolution. */
	rlvl->tlx = JPC_CEILDIVPOW2(jas_seq2d_xstart(tcmpt->data), tcmpt->numrlvls -
	  1 - rlvlno);
	rlvl->tly = JPC_CEILDIVPOW2(jas_seq2d_ystart(tcmpt->data), tcmpt->numrlvls -
	  1 - rlvlno);
	rlvl->brx = JPC_CEILDIVPOW2(jas_seq2d_xend(tcmpt->data), tcmpt->numrlvls -
	  1 - rlvlno);
	rlvl->bry = JPC_CEILDIVPOW2(jas_seq2d_yend(tcmpt->data), tcmpt->numrlvls -
	  1 - rlvlno);

	if (rlvl->tlx >= rlvl->brx || rlvl->tly >= rlvl->bry) {
		rlvl->numhprcs = 0;
		rlvl->numvprcs = 0;
		rlvl->numprcs = 0;
		return rlvl;
	}

	rlvl->numbands = (!rlvlno) ? 1 : 3;
	rlvl->prcwidthexpn = cp->tccp.prcwidthexpns[rlvlno];
	rlvl->prcheightexpn = cp->tccp.prcheightexpns[rlvlno];
	if (!rlvlno) {
		rlvl->cbgwidthexpn = rlvl->prcwidthexpn;
		rlvl->cbgheightexpn = rlvl->prcheightexpn;
	} else {
		rlvl->cbgwidthexpn = rlvl->prcwidthexpn - 1;
		rlvl->cbgheightexpn = rlvl->prcheightexpn - 1;
	}
	rlvl->cblkwidthexpn = JAS_MIN(cp->tccp.cblkwidthexpn, rlvl->cbgwidthexpn);
	rlvl->cblkheightexpn = JAS_MIN(cp->tccp.cblkheightexpn, rlvl->cbgheightexpn);

	/* Compute the number of precincts. */
	tlprctlx = JPC_FLOORTOMULTPOW2(rlvl->tlx, rlvl->prcwidthexpn);
	tlprctly = JPC_FLOORTOMULTPOW2(rlvl->tly, rlvl->prcheightexpn);
	brprcbrx = JPC_CEILTOMULTPOW2(rlvl->brx, rlvl->prcwidthexpn);
	brprcbry = JPC_CEILTOMULTPOW2(rlvl->bry, rlvl->prcheightexpn);
	rlvl->numhprcs = JPC_FLOORDIVPOW2(brprcbrx - tlprctlx, rlvl->prcwidthexpn);
	rlvl->numvprcs = JPC_FLOORDIVPOW2(brprcbry - tlprctly, rlvl->prcheightexpn);
	rlvl->numprcs = rlvl->numhprcs * rlvl->numvprcs;

	if (!(rlvl->bands = jas_malloc(rlvl->numbands * sizeof(jpc_enc_band_t)))) {
		goto error;
	}
	for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
	  ++bandno, ++band) {
		band->prcs = 0;
		band->data = 0;
		band->rlvl = rlvl;
	}
	for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
	  ++bandno, ++band) {
		if (!band_create(band, cp, rlvl, bandinfos)) {
			goto error;
		}
	}

	return rlvl;
error:

	rlvl_destroy(rlvl);
	return 0;
}

static void rlvl_destroy(jpc_enc_rlvl_t *rlvl)
{
	jpc_enc_band_t *band;
	uint_fast16_t bandno;

	if (rlvl->bands) {
		for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
		  ++bandno, ++band) {
			band_destroy(band);
		}
		jas_free(rlvl->bands);
	}
}

static jpc_enc_band_t *band_create(jpc_enc_band_t *band, jpc_enc_cp_t *cp,
  jpc_enc_rlvl_t *rlvl, jpc_tsfb_band_t *bandinfos)
{
	uint_fast16_t bandno;
	uint_fast16_t gblbandno;
	uint_fast16_t rlvlno;
	jpc_tsfb_band_t *bandinfo;
	jpc_enc_tcmpt_t *tcmpt;
	uint_fast32_t prcno;
	jpc_enc_prc_t *prc;

	tcmpt = rlvl->tcmpt;
	band->data = 0;
	band->prcs = 0;
	band->rlvl = rlvl;

	/* Deduce the resolution level and band number. */
	rlvlno = rlvl - rlvl->tcmpt->rlvls;
	bandno = band - rlvl->bands;
	gblbandno = (!rlvlno) ? 0 : (3 * (rlvlno - 1) + bandno + 1);

	bandinfo = &bandinfos[gblbandno];

if (bandinfo->xstart != bandinfo->xend && bandinfo->ystart != bandinfo->yend) {
	if (!(band->data = jas_seq2d_create(0, 0, 0, 0))) {
		goto error;
	}
	jas_seq2d_bindsub(band->data, tcmpt->data, bandinfo->locxstart,
	  bandinfo->locystart, bandinfo->locxend, bandinfo->locyend);
	jas_seq2d_setshift(band->data, bandinfo->xstart, bandinfo->ystart);
}
	band->orient = bandinfo->orient;
	band->analgain = JPC_NOMINALGAIN(cp->tccp.qmfbid, tcmpt->numrlvls, rlvlno,
	  band->orient);
	band->numbps = 0;
	band->absstepsize = 0;
	band->stepsize = 0;
	band->synweight = bandinfo->synenergywt;

if (band->data) {
	if (!(band->prcs = jas_malloc(rlvl->numprcs * sizeof(jpc_enc_prc_t)))) {
		goto error;
	}
	for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; ++prcno,
	  ++prc) {
		prc->cblks = 0;
		prc->incltree = 0;
		prc->nlibtree = 0;
		prc->savincltree = 0;
		prc->savnlibtree = 0;
		prc->band = band;
	}
	for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs; ++prcno,
	  ++prc) {
		if (!prc_create(prc, cp, band)) {
			goto error;
		}
	}
}

	return band;

error:
	band_destroy(band);
	return 0;
}

static void band_destroy(jpc_enc_band_t *band)
{
	jpc_enc_prc_t *prc;
	jpc_enc_rlvl_t *rlvl;
	uint_fast32_t prcno;

	if (band->prcs) {
		rlvl = band->rlvl;
		for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs;
		  ++prcno, ++prc) {
			prc_destroy(prc);
		}
		jas_free(band->prcs);
	}
	if (band->data) {
		jas_seq2d_destroy(band->data);
	}
}

static jpc_enc_prc_t *prc_create(jpc_enc_prc_t *prc, jpc_enc_cp_t *cp, jpc_enc_band_t *band)
{
	uint_fast32_t prcno;
	uint_fast32_t prcxind;
	uint_fast32_t prcyind;
	uint_fast32_t cbgtlx;
	uint_fast32_t cbgtly;
	uint_fast32_t tlprctlx;
	uint_fast32_t tlprctly;
	uint_fast32_t tlcbgtlx;
	uint_fast32_t tlcbgtly;
	uint_fast16_t rlvlno;
	jpc_enc_rlvl_t *rlvl;
	uint_fast32_t tlcblktlx;
	uint_fast32_t tlcblktly;
	uint_fast32_t brcblkbrx;
	uint_fast32_t brcblkbry;
	uint_fast32_t cblkno;
	jpc_enc_cblk_t *cblk;
	jpc_enc_tcmpt_t *tcmpt;

	prc->cblks = 0;
	prc->incltree = 0;
	prc->savincltree = 0;
	prc->nlibtree = 0;
	prc->savnlibtree = 0;

	rlvl = band->rlvl;
	tcmpt = rlvl->tcmpt;
rlvlno = rlvl - tcmpt->rlvls;
	prcno = prc - band->prcs;
	prcxind = prcno % rlvl->numhprcs;
	prcyind = prcno / rlvl->numhprcs;
	prc->band = band;

tlprctlx = JPC_FLOORTOMULTPOW2(rlvl->tlx, rlvl->prcwidthexpn);
tlprctly = JPC_FLOORTOMULTPOW2(rlvl->tly, rlvl->prcheightexpn);
if (!rlvlno) {
	tlcbgtlx = tlprctlx;
	tlcbgtly = tlprctly;
} else {
	tlcbgtlx = JPC_CEILDIVPOW2(tlprctlx, 1);
	tlcbgtly = JPC_CEILDIVPOW2(tlprctly, 1);
}

	/* Compute the coordinates of the top-left and bottom-right
	  corners of the precinct. */
	cbgtlx = tlcbgtlx + (prcxind << rlvl->cbgwidthexpn);
	cbgtly = tlcbgtly + (prcyind << rlvl->cbgheightexpn);
	prc->tlx = JAS_MAX(jas_seq2d_xstart(band->data), cbgtlx);
	prc->tly = JAS_MAX(jas_seq2d_ystart(band->data), cbgtly);
	prc->brx = JAS_MIN(jas_seq2d_xend(band->data), cbgtlx +
	  (1 << rlvl->cbgwidthexpn));
	prc->bry = JAS_MIN(jas_seq2d_yend(band->data), cbgtly +
	  (1 << rlvl->cbgheightexpn));

	if (prc->tlx < prc->brx && prc->tly < prc->bry) {
		/* The precinct contains at least one code block. */

		tlcblktlx = JPC_FLOORTOMULTPOW2(prc->tlx, rlvl->cblkwidthexpn);
		tlcblktly = JPC_FLOORTOMULTPOW2(prc->tly, rlvl->cblkheightexpn);
		brcblkbrx = JPC_CEILTOMULTPOW2(prc->brx, rlvl->cblkwidthexpn);
		brcblkbry = JPC_CEILTOMULTPOW2(prc->bry, rlvl->cblkheightexpn);
		prc->numhcblks = JPC_FLOORDIVPOW2(brcblkbrx - tlcblktlx,
		  rlvl->cblkwidthexpn);
		prc->numvcblks = JPC_FLOORDIVPOW2(brcblkbry - tlcblktly,
		  rlvl->cblkheightexpn);
		prc->numcblks = prc->numhcblks * prc->numvcblks;

		if (!(prc->incltree = jpc_tagtree_create(prc->numhcblks,
		  prc->numvcblks))) {
			goto error;
		}
		if (!(prc->nlibtree = jpc_tagtree_create(prc->numhcblks,
		  prc->numvcblks))) {
			goto error;
		}
		if (!(prc->savincltree = jpc_tagtree_create(prc->numhcblks,
		  prc->numvcblks))) {
			goto error;
		}
		if (!(prc->savnlibtree = jpc_tagtree_create(prc->numhcblks,
		  prc->numvcblks))) {
			goto error;
		}

		if (!(prc->cblks = jas_malloc(prc->numcblks * sizeof(jpc_enc_cblk_t)))) {
			goto error;
		}
		for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
		  ++cblkno, ++cblk) {
			cblk->passes = 0;
			cblk->stream = 0;
			cblk->mqenc = 0;
			cblk->data = 0;
			cblk->flags = 0;
			cblk->prc = prc;
		}
		for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
		  ++cblkno, ++cblk) {
			if (!cblk_create(cblk, cp, prc)) {
				goto error;
			}
		}
	} else {
		/* The precinct does not contain any code blocks. */
		prc->tlx = prc->brx;
		prc->tly = prc->bry;
		prc->numcblks = 0;
		prc->numhcblks = 0;
		prc->numvcblks = 0;
		prc->cblks = 0;
		prc->incltree = 0;
		prc->nlibtree = 0;
		prc->savincltree = 0;
		prc->savnlibtree = 0;
	}

	return prc;

error:
	prc_destroy(prc);
	return 0;
}

static void prc_destroy(jpc_enc_prc_t *prc)
{
	jpc_enc_cblk_t *cblk;
	uint_fast32_t cblkno;

	if (prc->cblks) {
		for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
		  ++cblkno, ++cblk) {
			cblk_destroy(cblk);
		}
		jas_free(prc->cblks);
	}
	if (prc->incltree) {
		jpc_tagtree_destroy(prc->incltree);
	}
	if (prc->nlibtree) {
		jpc_tagtree_destroy(prc->nlibtree);
	}
	if (prc->savincltree) {
		jpc_tagtree_destroy(prc->savincltree);
	}
	if (prc->savnlibtree) {
		jpc_tagtree_destroy(prc->savnlibtree);
	}
}

static jpc_enc_cblk_t *cblk_create(jpc_enc_cblk_t *cblk, jpc_enc_cp_t *cp, jpc_enc_prc_t *prc)
{
	jpc_enc_band_t *band;
	uint_fast32_t cblktlx;
	uint_fast32_t cblktly;
	uint_fast32_t cblkbrx;
	uint_fast32_t cblkbry;
	jpc_enc_rlvl_t *rlvl;
	uint_fast32_t cblkxind;
	uint_fast32_t cblkyind;
	uint_fast32_t cblkno;
	uint_fast32_t tlcblktlx;
	uint_fast32_t tlcblktly;

	cblkno = cblk - prc->cblks;
	cblkxind = cblkno % prc->numhcblks;
	cblkyind = cblkno / prc->numhcblks;
	rlvl = prc->band->rlvl;
	cblk->prc = prc;

	cblk->numpasses = 0;
	cblk->passes = 0;
	cblk->numencpasses = 0;
	cblk->numimsbs = 0;
	cblk->numlenbits = 0;
	cblk->stream = 0;
	cblk->mqenc = 0;
	cblk->flags = 0;
	cblk->numbps = 0;
	cblk->curpass = 0;
	cblk->data = 0;
	cblk->savedcurpass = 0;
	cblk->savednumlenbits = 0;
	cblk->savednumencpasses = 0;

	band = prc->band;
	tlcblktlx = JPC_FLOORTOMULTPOW2(prc->tlx, rlvl->cblkwidthexpn);
	tlcblktly = JPC_FLOORTOMULTPOW2(prc->tly, rlvl->cblkheightexpn);
	cblktlx = JAS_MAX(tlcblktlx + (cblkxind << rlvl->cblkwidthexpn), prc->tlx);
	cblktly = JAS_MAX(tlcblktly + (cblkyind << rlvl->cblkheightexpn), prc->tly);
	cblkbrx = JAS_MIN(tlcblktlx + ((cblkxind + 1) << rlvl->cblkwidthexpn),
	  prc->brx);
	cblkbry = JAS_MIN(tlcblktly + ((cblkyind + 1) << rlvl->cblkheightexpn),
	  prc->bry);

	assert(cblktlx < cblkbrx && cblktly < cblkbry);
	if (!(cblk->data = jas_seq2d_create(0, 0, 0, 0))) {
		goto error;
	}
	jas_seq2d_bindsub(cblk->data, band->data, cblktlx, cblktly, cblkbrx, cblkbry);

	return cblk;

error:
	cblk_destroy(cblk);
	return 0;
}

static void cblk_destroy(jpc_enc_cblk_t *cblk)
{
	uint_fast16_t passno;
	jpc_enc_pass_t *pass;
	if (cblk->passes) {
		for (passno = 0, pass = cblk->passes; passno < cblk->numpasses;
		  ++passno, ++pass) {
			pass_destroy(pass);
		}
		jas_free(cblk->passes);
	}
	if (cblk->stream) {
		jas_stream_close(cblk->stream);
	}
	if (cblk->mqenc) {
		jpc_mqenc_destroy(cblk->mqenc);
	}
	if (cblk->data) {
		jas_seq2d_destroy(cblk->data);
	}
	if (cblk->flags) {
		jas_seq2d_destroy(cblk->flags);
	}
}

static void pass_destroy(jpc_enc_pass_t *pass)
{
	/* XXX - need to free resources here */
}

void jpc_enc_dump(jpc_enc_t *enc)
{
	jpc_enc_tile_t *tile;
	jpc_enc_tcmpt_t *tcmpt;
	jpc_enc_rlvl_t *rlvl;
	jpc_enc_band_t *band;
	jpc_enc_prc_t *prc;
	jpc_enc_cblk_t *cblk;
	uint_fast16_t cmptno;
	uint_fast16_t rlvlno;
	uint_fast16_t bandno;
	uint_fast32_t prcno;
	uint_fast32_t cblkno;

	tile = enc->curtile;

	for (cmptno = 0, tcmpt = tile->tcmpts; cmptno < tile->numtcmpts; ++cmptno,
	  ++tcmpt) {
		fprintf(stderr, "  tcmpt %5d %5d %5d %5d\n", jas_seq2d_xstart(tcmpt->data), jas_seq2d_ystart(tcmpt->data), jas_seq2d_xend(tcmpt->data), jas_seq2d_yend(tcmpt->data));
		for (rlvlno = 0, rlvl = tcmpt->rlvls; rlvlno < tcmpt->numrlvls;
		  ++rlvlno, ++rlvl) {
			fprintf(stderr, "    rlvl %5d %5d %5d %5d\n", rlvl->tlx, rlvl->tly, rlvl->brx, rlvl->bry);
			for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
			  ++bandno, ++band) {
				if (!band->data) {
					continue;
				}
				fprintf(stderr, "      band %5d %5d %5d %5d\n", jas_seq2d_xstart(band->data), jas_seq2d_ystart(band->data), jas_seq2d_xend(band->data), jas_seq2d_yend(band->data));
				for (prcno = 0, prc = band->prcs; prcno < rlvl->numprcs;
				  ++prcno, ++prc) {
					fprintf(stderr, "        prc %5d %5d %5d %5d (%5d %5d)\n", prc->tlx, prc->tly, prc->brx, prc->bry, prc->brx - prc->tlx, prc->bry - prc->tly);
					if (!prc->cblks) {
						continue;
					}
					for (cblkno = 0, cblk = prc->cblks; cblkno < prc->numcblks;
					  ++cblkno, ++cblk) {
						fprintf(stderr, "         cblk %5d %5d %5d %5d\n", jas_seq2d_xstart(cblk->data), jas_seq2d_ystart(cblk->data), jas_seq2d_xend(cblk->data), jas_seq2d_yend(cblk->data));
					}
				}
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The zlib/libpng License


Written By
Software Developer
France France
KOCH David, 41 years old
Coder (embedded, C/C++, ASM, Erlang)

Comments and Discussions