/* * Copyright (c) 1999-2000 Image Power, Inc. and the University of * British Columbia. * Copyright (c) 2001-2002 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__ */ /* * Quadrature Mirror-Image Filter Bank (QMFB) Library * * $Id$ */ /******************************************************************************\ * Includes. \******************************************************************************/ #include #include "jasper/jas_fix.h" #include "jasper/jas_malloc.h" #include "jasper/jas_math.h" #include "jpc_qmfb.h" #include "jpc_tsfb.h" #include "jpc_math.h" /******************************************************************************\ * \******************************************************************************/ static jpc_qmfb1d_t *jpc_qmfb1d_create(void); static int jpc_ft_getnumchans(jpc_qmfb1d_t *qmfb); static int jpc_ft_getanalfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters); static int jpc_ft_getsynfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters); static void jpc_ft_analyze(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x); static void jpc_ft_synthesize(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x); static int jpc_ns_getnumchans(jpc_qmfb1d_t *qmfb); static int jpc_ns_getanalfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters); static int jpc_ns_getsynfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters); static void jpc_ns_analyze(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x); static void jpc_ns_synthesize(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x); /******************************************************************************\ * \******************************************************************************/ jpc_qmfb1dops_t jpc_ft_ops = { jpc_ft_getnumchans, jpc_ft_getanalfilters, jpc_ft_getsynfilters, jpc_ft_analyze, jpc_ft_synthesize }; jpc_qmfb1dops_t jpc_ns_ops = { jpc_ns_getnumchans, jpc_ns_getanalfilters, jpc_ns_getsynfilters, jpc_ns_analyze, jpc_ns_synthesize }; /******************************************************************************\ * \******************************************************************************/ static void jpc_qmfb1d_setup(jpc_fix_t *startptr, int startind, int endind, int intrastep, jpc_fix_t **lstartptr, int *lstartind, int *lendind, jpc_fix_t **hstartptr, int *hstartind, int *hendind) { *lstartind = JPC_CEILDIVPOW2(startind, 1); *lendind = JPC_CEILDIVPOW2(endind, 1); *hstartind = JPC_FLOORDIVPOW2(startind, 1); *hendind = JPC_FLOORDIVPOW2(endind, 1); *lstartptr = startptr; *hstartptr = &startptr[(*lendind - *lstartind) * intrastep]; } static void jpc_qmfb1d_split(jpc_fix_t *startptr, int startind, int endind, register int step, jpc_fix_t *lstartptr, int lstartind, int lendind, jpc_fix_t *hstartptr, int hstartind, int hendind) { #define QMFB_SPLITBUFSIZE 4096 jpc_fix_t splitbuf[QMFB_SPLITBUFSIZE]; jpc_fix_t *buf = splitbuf; int llen; int hlen; int twostep; jpc_fix_t *tmpptr; register jpc_fix_t *ptr; register jpc_fix_t *hptr; register jpc_fix_t *lptr; register int n; int state; twostep = step << 1; llen = lendind - lstartind; hlen = hendind - hstartind; if (hstartind < lstartind) { /* The first sample in the input signal is to appear in the highpass subband signal. */ /* Copy the appropriate samples into the lowpass subband signal, saving any samples destined for the highpass subband signal as they are overwritten. */ tmpptr = buf; ptr = &startptr[step]; lptr = lstartptr; n = llen; state = 1; while (n-- > 0) { if (state) { *tmpptr = *lptr; ++tmpptr; } *lptr = *ptr; ptr += twostep; lptr += step; state ^= 1; } /* Copy the appropriate samples into the highpass subband signal. */ /* Handle the nonoverwritten samples. */ hptr = &hstartptr[(hlen - 1) * step]; ptr = &startptr[(((llen + hlen - 1) >> 1) << 1) * step]; n = hlen - (tmpptr - buf); while (n-- > 0) { *hptr = *ptr; hptr -= step; ptr -= twostep; } /* Handle the overwritten samples. */ n = tmpptr - buf; while (n-- > 0) { --tmpptr; *hptr = *tmpptr; hptr -= step; } } else { /* The first sample in the input signal is to appear in the lowpass subband signal. */ /* Copy the appropriate samples into the lowpass subband signal, saving any samples for the highpass subband signal as they are overwritten. */ state = 0; ptr = startptr; lptr = lstartptr; tmpptr = buf; n = llen; while (n-- > 0) { if (state) { *tmpptr = *lptr; ++tmpptr; } *lptr = *ptr; ptr += twostep; lptr += step; state ^= 1; } /* Copy the appropriate samples into the highpass subband signal. */ /* Handle the nonoverwritten samples. */ ptr = &startptr[((((llen + hlen) >> 1) << 1) - 1) * step]; hptr = &hstartptr[(hlen - 1) * step]; n = hlen - (tmpptr - buf); while (n-- > 0) { *hptr = *ptr; ptr -= twostep; hptr -= step; } /* Handle the overwritten samples. */ n = tmpptr - buf; while (n-- > 0) { --tmpptr; *hptr = *tmpptr; hptr -= step; } } } static void jpc_qmfb1d_join(jpc_fix_t *startptr, int startind, int endind, register int step, jpc_fix_t *lstartptr, int lstartind, int lendind, jpc_fix_t *hstartptr, int hstartind, int hendind) { #define QMFB_JOINBUFSIZE 4096 jpc_fix_t joinbuf[QMFB_JOINBUFSIZE]; jpc_fix_t *buf = joinbuf; int llen; int hlen; int twostep; jpc_fix_t *tmpptr; register jpc_fix_t *ptr; register jpc_fix_t *hptr; register jpc_fix_t *lptr; register int n; int state; twostep = step << 1; llen = lendind - lstartind; hlen = hendind - hstartind; if (hstartind < lstartind) { /* The first sample in the highpass subband signal is to appear first in the output signal. */ /* Copy the appropriate samples into the first phase of the output signal. */ tmpptr = buf; hptr = hstartptr; ptr = startptr; n = (llen + 1) >> 1; while (n-- > 0) { *tmpptr = *ptr; *ptr = *hptr; ++tmpptr; ptr += twostep; hptr += step; } n = hlen - ((llen + 1) >> 1); while (n-- > 0) { *ptr = *hptr; ptr += twostep; hptr += step; } /* Copy the appropriate samples into the second phase of the output signal. */ ptr -= (lendind > hendind) ? (step) : (step + twostep); state = !((llen - 1) & 1); lptr = &lstartptr[(llen - 1) * step]; n = llen; while (n-- > 0) { if (state) { --tmpptr; *ptr = *tmpptr; } else { *ptr = *lptr; } lptr -= step; ptr -= twostep; state ^= 1; } } else { /* The first sample in the lowpass subband signal is to appear first in the output signal. */ /* Copy the appropriate samples into the first phase of the output signal (corresponding to even indexed samples). */ lptr = &lstartptr[(llen - 1) * step]; ptr = &startptr[((llen - 1) << 1) * step]; n = llen >> 1; tmpptr = buf; while (n-- > 0) { *tmpptr = *ptr; *ptr = *lptr; ++tmpptr; ptr -= twostep; lptr -= step; } n = llen - (llen >> 1); while (n-- > 0) { *ptr = *lptr; ptr -= twostep; lptr -= step; } /* Copy the appropriate samples into the second phase of the output signal (corresponding to odd indexed samples). */ ptr = &startptr[step]; hptr = hstartptr; state = !(llen & 1); n = hlen; while (n-- > 0) { if (state) { --tmpptr; *ptr = *tmpptr; } else { *ptr = *hptr; } hptr += step; ptr += twostep; state ^= 1; } } } /******************************************************************************\ * Code for 5/3 transform. \******************************************************************************/ static int jpc_ft_getnumchans(jpc_qmfb1d_t *qmfb) { return 2; } static int jpc_ft_getanalfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters) { abort(); return -1; } static int jpc_ft_getsynfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters) { jas_seq_t *lf; jas_seq_t *hf; lf = 0; hf = 0; if (len > 1 || (!len)) { if (!(lf = jas_seq_create(-1, 2))) { goto error; } jas_seq_set(lf, -1, jpc_dbltofix(0.5)); jas_seq_set(lf, 0, jpc_dbltofix(1.0)); jas_seq_set(lf, 1, jpc_dbltofix(0.5)); if (!(hf = jas_seq_create(-1, 4))) { goto error; } jas_seq_set(hf, -1, jpc_dbltofix(-0.125)); jas_seq_set(hf, 0, jpc_dbltofix(-0.25)); jas_seq_set(hf, 1, jpc_dbltofix(0.75)); jas_seq_set(hf, 2, jpc_dbltofix(-0.25)); jas_seq_set(hf, 3, jpc_dbltofix(-0.125)); } else if (len == 1) { if (!(lf = jas_seq_create(0, 1))) { goto error; } jas_seq_set(lf, 0, jpc_dbltofix(1.0)); if (!(hf = jas_seq_create(0, 1))) { goto error; } jas_seq_set(hf, 0, jpc_dbltofix(2.0)); } else { abort(); } filters[0] = lf; filters[1] = hf; return 0; error: if (lf) { jas_seq_destroy(lf); } if (hf) { jas_seq_destroy(hf); } return -1; } #define NFT_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, step, pluseq) \ { \ register jpc_fix_t *lptr = (lstartptr); \ register jpc_fix_t *hptr = (hstartptr); \ register int n = (hendind) - (hstartind); \ if ((hstartind) < (lstartind)) { \ pluseq(*hptr, *lptr); \ hptr += (step); \ --n; \ } \ if ((hendind) >= (lendind)) { \ --n; \ } \ while (n-- > 0) { \ pluseq(*hptr, jpc_fix_asr(jpc_fix_add(*lptr, lptr[(step)]), 1)); \ hptr += (step); \ lptr += (step); \ } \ if ((hendind) >= (lendind)) { \ pluseq(*hptr, *lptr); \ } \ } #define NFT_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, step, pluseq) \ { \ register jpc_fix_t *lptr = (lstartptr); \ register jpc_fix_t *hptr = (hstartptr); \ register int n = (lendind) - (lstartind); \ if ((hstartind) >= (lstartind)) { \ pluseq(*lptr, *hptr); \ lptr += (step); \ --n; \ } \ if ((lendind) > (hendind)) { \ --n; \ } \ while (n-- > 0) { \ pluseq(*lptr, jpc_fix_asr(jpc_fix_add(*hptr, hptr[(step)]), 2)); \ lptr += (step); \ hptr += (step); \ } \ if ((lendind) > (hendind)) { \ pluseq(*lptr, *hptr); \ } \ } #define RFT_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, step, pmeqop) \ { \ register jpc_fix_t *lptr = (lstartptr); \ register jpc_fix_t *hptr = (hstartptr); \ register int n = (hendind) - (hstartind); \ if ((hstartind) < (lstartind)) { \ *hptr pmeqop *lptr; \ hptr += (step); \ --n; \ } \ if ((hendind) >= (lendind)) { \ --n; \ } \ while (n-- > 0) { \ *hptr pmeqop (*lptr + lptr[(step)]) >> 1; \ hptr += (step); \ lptr += (step); \ } \ if ((hendind) >= (lendind)) { \ *hptr pmeqop *lptr; \ } \ } #define RFT_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, step, pmeqop) \ { \ register jpc_fix_t *lptr = (lstartptr); \ register jpc_fix_t *hptr = (hstartptr); \ register int n = (lendind) - (lstartind); \ if ((hstartind) >= (lstartind)) { \ *lptr pmeqop ((*hptr << 1) + 2) >> 2; \ lptr += (step); \ --n; \ } \ if ((lendind) > (hendind)) { \ --n; \ } \ while (n-- > 0) { \ *lptr pmeqop ((*hptr + hptr[(step)]) + 2) >> 2; \ lptr += (step); \ hptr += (step); \ } \ if ((lendind) > (hendind)) { \ *lptr pmeqop ((*hptr << 1) + 2) >> 2; \ } \ } static void jpc_ft_analyze(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x) { jpc_fix_t *startptr; int startind; int endind; jpc_fix_t * lstartptr; int lstartind; int lendind; jpc_fix_t * hstartptr; int hstartind; int hendind; int interstep; int intrastep; int numseq; if (flags & JPC_QMFB1D_VERT) { interstep = 1; intrastep = jas_seq2d_rowstep(x); numseq = jas_seq2d_width(x); startind = jas_seq2d_ystart(x); endind = jas_seq2d_yend(x); } else { interstep = jas_seq2d_rowstep(x); intrastep = 1; numseq = jas_seq2d_height(x); startind = jas_seq2d_xstart(x); endind = jas_seq2d_xend(x); } assert(startind < endind); startptr = jas_seq2d_getref(x, jas_seq2d_xstart(x), jas_seq2d_ystart(x)); if (flags & JPC_QMFB1D_RITIMODE) { while (numseq-- > 0) { jpc_qmfb1d_setup(startptr, startind, endind, intrastep, &lstartptr, &lstartind, &lendind, &hstartptr, &hstartind, &hendind); if (endind - startind > 1) { jpc_qmfb1d_split(startptr, startind, endind, intrastep, lstartptr, lstartind, lendind, hstartptr, hstartind, hendind); RFT_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, -=); RFT_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, +=); } else { if (lstartind == lendind) { *startptr <<= 1; } } startptr += interstep; } } else { while (numseq-- > 0) { jpc_qmfb1d_setup(startptr, startind, endind, intrastep, &lstartptr, &lstartind, &lendind, &hstartptr, &hstartind, &hendind); if (endind - startind > 1) { jpc_qmfb1d_split(startptr, startind, endind, intrastep, lstartptr, lstartind, lendind, hstartptr, hstartind, hendind); NFT_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, jpc_fix_minuseq); NFT_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, jpc_fix_pluseq); } else { if (lstartind == lendind) { *startptr = jpc_fix_asl(*startptr, 1); } } startptr += interstep; } } } static void jpc_ft_synthesize(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x) { jpc_fix_t *startptr; int startind; int endind; jpc_fix_t *lstartptr; int lstartind; int lendind; jpc_fix_t *hstartptr; int hstartind; int hendind; int interstep; int intrastep; int numseq; if (flags & JPC_QMFB1D_VERT) { interstep = 1; intrastep = jas_seq2d_rowstep(x); numseq = jas_seq2d_width(x); startind = jas_seq2d_ystart(x); endind = jas_seq2d_yend(x); } else { interstep = jas_seq2d_rowstep(x); intrastep = 1; numseq = jas_seq2d_height(x); startind = jas_seq2d_xstart(x); endind = jas_seq2d_xend(x); } assert(startind < endind); startptr = jas_seq2d_getref(x, jas_seq2d_xstart(x), jas_seq2d_ystart(x)); if (flags & JPC_QMFB1D_RITIMODE) { while (numseq-- > 0) { jpc_qmfb1d_setup(startptr, startind, endind, intrastep, &lstartptr, &lstartind, &lendind, &hstartptr, &hstartind, &hendind); if (endind - startind > 1) { RFT_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, -=); RFT_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, +=); jpc_qmfb1d_join(startptr, startind, endind, intrastep, lstartptr, lstartind, lendind, hstartptr, hstartind, hendind); } else { if (lstartind == lendind) { *startptr >>= 1; } } startptr += interstep; } } else { while (numseq-- > 0) { jpc_qmfb1d_setup(startptr, startind, endind, intrastep, &lstartptr, &lstartind, &lendind, &hstartptr, &hstartind, &hendind); if (endind - startind > 1) { NFT_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, jpc_fix_minuseq); NFT_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, jpc_fix_pluseq); jpc_qmfb1d_join(startptr, startind, endind, intrastep, lstartptr, lstartind, lendind, hstartptr, hstartind, hendind); } else { if (lstartind == lendind) { *startptr = jpc_fix_asr(*startptr, 1); } } startptr += interstep; } } } /******************************************************************************\ * Code for 9/7 transform. \******************************************************************************/ static int jpc_ns_getnumchans(jpc_qmfb1d_t *qmfb) { return 2; } static int jpc_ns_getanalfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters) { abort(); return -1; } static int jpc_ns_getsynfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters) { jas_seq_t *lf; jas_seq_t *hf; lf = 0; hf = 0; if (len > 1 || (!len)) { if (!(lf = jas_seq_create(-3, 4))) { goto error; } jas_seq_set(lf, -3, jpc_dbltofix(-0.09127176311424948)); jas_seq_set(lf, -2, jpc_dbltofix(-0.05754352622849957)); jas_seq_set(lf, -1, jpc_dbltofix(0.5912717631142470)); jas_seq_set(lf, 0, jpc_dbltofix(1.115087052456994)); jas_seq_set(lf, 1, jpc_dbltofix(0.5912717631142470)); jas_seq_set(lf, 2, jpc_dbltofix(-0.05754352622849957)); jas_seq_set(lf, 3, jpc_dbltofix(-0.09127176311424948)); if (!(hf = jas_seq_create(-3, 6))) { goto error; } jas_seq_set(hf, -3, jpc_dbltofix(-0.02674875741080976 * 2.0)); jas_seq_set(hf, -2, jpc_dbltofix(-0.01686411844287495 * 2.0)); jas_seq_set(hf, -1, jpc_dbltofix(0.07822326652898785 * 2.0)); jas_seq_set(hf, 0, jpc_dbltofix(0.2668641184428723 * 2.0)); jas_seq_set(hf, 1, jpc_dbltofix(-0.6029490182363579 * 2.0)); jas_seq_set(hf, 2, jpc_dbltofix(0.2668641184428723 * 2.0)); jas_seq_set(hf, 3, jpc_dbltofix(0.07822326652898785 * 2.0)); jas_seq_set(hf, 4, jpc_dbltofix(-0.01686411844287495 * 2.0)); jas_seq_set(hf, 5, jpc_dbltofix(-0.02674875741080976 * 2.0)); } else if (len == 1) { if (!(lf = jas_seq_create(0, 1))) { goto error; } jas_seq_set(lf, 0, jpc_dbltofix(1.0)); if (!(hf = jas_seq_create(0, 1))) { goto error; } jas_seq_set(hf, 0, jpc_dbltofix(2.0)); } else { abort(); } filters[0] = lf; filters[1] = hf; return 0; error: if (lf) { jas_seq_destroy(lf); } if (hf) { jas_seq_destroy(hf); } return -1; } #define NNS_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, step, alpha) \ { \ register jpc_fix_t *lptr = (lstartptr); \ register jpc_fix_t *hptr = (hstartptr); \ register int n = (hendind) - (hstartind); \ jpc_fix_t twoalpha = jpc_fix_mulbyint(alpha, 2); \ if ((hstartind) < (lstartind)) { \ jpc_fix_pluseq(*hptr, jpc_fix_mul(*lptr, (twoalpha))); \ hptr += (step); \ --n; \ } \ if ((hendind) >= (lendind)) { \ --n; \ } \ while (n-- > 0) { \ jpc_fix_pluseq(*hptr, jpc_fix_mul(jpc_fix_add(*lptr, lptr[(step)]), (alpha))); \ hptr += (step); \ lptr += (step); \ } \ if ((hendind) >= (lendind)) { \ jpc_fix_pluseq(*hptr, jpc_fix_mul(*lptr, (twoalpha))); \ } \ } #define NNS_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, step, alpha) \ { \ register jpc_fix_t *lptr = (lstartptr); \ register jpc_fix_t *hptr = (hstartptr); \ register int n = (lendind) - (lstartind); \ int twoalpha = jpc_fix_mulbyint(alpha, 2); \ if ((hstartind) >= (lstartind)) { \ jpc_fix_pluseq(*lptr, jpc_fix_mul(*hptr, (twoalpha))); \ lptr += (step); \ --n; \ } \ if ((lendind) > (hendind)) { \ --n; \ } \ while (n-- > 0) { \ jpc_fix_pluseq(*lptr, jpc_fix_mul(jpc_fix_add(*hptr, hptr[(step)]), (alpha))); \ lptr += (step); \ hptr += (step); \ } \ if ((lendind) > (hendind)) { \ jpc_fix_pluseq(*lptr, jpc_fix_mul(*hptr, (twoalpha))); \ } \ } #define NNS_SCALE(startptr, startind, endind, step, alpha) \ { \ register jpc_fix_t *ptr = (startptr); \ register int n = (endind) - (startind); \ while (n-- > 0) { \ jpc_fix_muleq(*ptr, alpha); \ ptr += (step); \ } \ } static void jpc_ns_analyze(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x) { jpc_fix_t *startptr; int startind; int endind; jpc_fix_t *lstartptr; int lstartind; int lendind; jpc_fix_t *hstartptr; int hstartind; int hendind; int interstep; int intrastep; int numseq; if (flags & JPC_QMFB1D_VERT) { interstep = 1; intrastep = jas_seq2d_rowstep(x); numseq = jas_seq2d_width(x); startind = jas_seq2d_ystart(x); endind = jas_seq2d_yend(x); } else { interstep = jas_seq2d_rowstep(x); intrastep = 1; numseq = jas_seq2d_height(x); startind = jas_seq2d_xstart(x); endind = jas_seq2d_xend(x); } assert(startind < endind); startptr = jas_seq2d_getref(x, jas_seq2d_xstart(x), jas_seq2d_ystart(x)); if (!(flags & JPC_QMFB1D_RITIMODE)) { while (numseq-- > 0) { jpc_qmfb1d_setup(startptr, startind, endind, intrastep, &lstartptr, &lstartind, &lendind, &hstartptr, &hstartind, &hendind); if (endind - startind > 1) { jpc_qmfb1d_split(startptr, startind, endind, intrastep, lstartptr, lstartind, lendind, hstartptr, hstartind, hendind); NNS_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, jpc_dbltofix(-1.586134342)); NNS_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, jpc_dbltofix(-0.052980118)); NNS_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, jpc_dbltofix(0.882911075)); NNS_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, jpc_dbltofix(0.443506852)); NNS_SCALE(lstartptr, lstartind, lendind, intrastep, jpc_dbltofix(1.0/1.23017410558578)); NNS_SCALE(hstartptr, hstartind, hendind, intrastep, jpc_dbltofix(1.0/1.62578613134411)); } else { #if 0 if (lstartind == lendind) { *startptr = jpc_fix_asl(*startptr, 1); } #endif } startptr += interstep; } } else { /* The reversible integer-to-integer mode is not valid for this transform. */ abort(); } } static void jpc_ns_synthesize(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x) { jpc_fix_t *startptr; int startind; int endind; jpc_fix_t *lstartptr; int lstartind; int lendind; jpc_fix_t *hstartptr; int hstartind; int hendind; int interstep; int intrastep; int numseq; if (flags & JPC_QMFB1D_VERT) { interstep = 1; intrastep = jas_seq2d_rowstep(x); numseq = jas_seq2d_width(x); startind = jas_seq2d_ystart(x); endind = jas_seq2d_yend(x); } else { interstep = jas_seq2d_rowstep(x); intrastep = 1; numseq = jas_seq2d_height(x); startind = jas_seq2d_xstart(x); endind = jas_seq2d_xend(x); } assert(startind < endind); startptr = jas_seq2d_getref(x, jas_seq2d_xstart(x), jas_seq2d_ystart(x)); if (!(flags & JPC_QMFB1D_RITIMODE)) { while (numseq-- > 0) { jpc_qmfb1d_setup(startptr, startind, endind, intrastep, &lstartptr, &lstartind, &lendind, &hstartptr, &hstartind, &hendind); if (endind - startind > 1) { NNS_SCALE(lstartptr, lstartind, lendind, intrastep, jpc_dbltofix(1.23017410558578)); NNS_SCALE(hstartptr, hstartind, hendind, intrastep, jpc_dbltofix(1.62578613134411)); NNS_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, jpc_dbltofix(-0.443506852)); NNS_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, jpc_dbltofix(-0.882911075)); NNS_LIFT1(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, jpc_dbltofix(0.052980118)); NNS_LIFT0(lstartptr, lstartind, lendind, hstartptr, hstartind, hendind, intrastep, jpc_dbltofix(1.586134342)); jpc_qmfb1d_join(startptr, startind, endind, intrastep, lstartptr, lstartind, lendind, hstartptr, hstartind, hendind); } else { #if 0 if (lstartind == lendind) { *startptr = jpc_fix_asr(*startptr, 1); } #endif } startptr += interstep; } } else { /* The reversible integer-to-integer mode is not valid for this transform. */ abort(); } } /******************************************************************************\ * \******************************************************************************/ jpc_qmfb1d_t *jpc_qmfb1d_make(int qmfbid) { jpc_qmfb1d_t *qmfb; if (!(qmfb = jpc_qmfb1d_create())) { return 0; } switch (qmfbid) { case JPC_QMFB1D_FT: qmfb->ops = &jpc_ft_ops; break; case JPC_QMFB1D_NS: qmfb->ops = &jpc_ns_ops; break; default: jpc_qmfb1d_destroy(qmfb); return 0; break; } return qmfb; } static jpc_qmfb1d_t *jpc_qmfb1d_create() { jpc_qmfb1d_t *qmfb; if (!(qmfb = jas_malloc(sizeof(jpc_qmfb1d_t)))) { return 0; } qmfb->ops = 0; return qmfb; } jpc_qmfb1d_t *jpc_qmfb1d_copy(jpc_qmfb1d_t *qmfb) { jpc_qmfb1d_t *newqmfb; if (!(newqmfb = jpc_qmfb1d_create())) { return 0; } newqmfb->ops = qmfb->ops; return newqmfb; } void jpc_qmfb1d_destroy(jpc_qmfb1d_t *qmfb) { jas_free(qmfb); } /******************************************************************************\ * \******************************************************************************/ void jpc_qmfb1d_getbands(jpc_qmfb1d_t *qmfb, int flags, uint_fast32_t xstart, uint_fast32_t ystart, uint_fast32_t xend, uint_fast32_t yend, int maxbands, int *numbandsptr, jpc_qmfb1dband_t *bands) { int start; int end; if (flags & JPC_QMFB1D_VERT) { start = ystart; end = yend; } else { start = xstart; end = xend; } assert(jpc_qmfb1d_getnumchans(qmfb) == 2); assert(start <= end); bands[0].start = JPC_CEILDIVPOW2(start, 1); bands[0].end = JPC_CEILDIVPOW2(end, 1); bands[0].locstart = start; bands[0].locend = start + bands[0].end - bands[0].start; bands[1].start = JPC_FLOORDIVPOW2(start, 1); bands[1].end = JPC_FLOORDIVPOW2(end, 1); bands[1].locstart = bands[0].locend; bands[1].locend = bands[1].locstart + bands[1].end - bands[1].start; assert(bands[1].locend == end); *numbandsptr = 2; } /******************************************************************************\ * \******************************************************************************/ int jpc_qmfb1d_getnumchans(jpc_qmfb1d_t *qmfb) { return (*qmfb->ops->getnumchans)(qmfb); } int jpc_qmfb1d_getanalfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters) { return (*qmfb->ops->getanalfilters)(qmfb, len, filters); } int jpc_qmfb1d_getsynfilters(jpc_qmfb1d_t *qmfb, int len, jas_seq2d_t **filters) { return (*qmfb->ops->getsynfilters)(qmfb, len, filters); } void jpc_qmfb1d_analyze(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x) { (*qmfb->ops->analyze)(qmfb, flags, x); } void jpc_qmfb1d_synthesize(jpc_qmfb1d_t *qmfb, int flags, jas_seq2d_t *x) { (*qmfb->ops->synthesize)(qmfb, flags, x); }