001/*
002 * $RCSfile: HeaderEncoder.java,v $
003 * $Revision: 1.1 $
004 * $Date: 2005/02/11 05:02:02 $
005 * $State: Exp $
006 *
007 * Class:                   HeaderEncoder
008 *
009 * Description:             Write codestream headers.
010 *
011 *
012 *
013 * COPYRIGHT:
014 *
015 * This software module was originally developed by Raphaël Grosbois and
016 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
017 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
018 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
019 * Centre France S.A) in the course of development of the JPEG2000
020 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
021 * software module is an implementation of a part of the JPEG 2000
022 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
023 * Systems AB and Canon Research Centre France S.A (collectively JJ2000
024 * Partners) agree not to assert against ISO/IEC and users of the JPEG
025 * 2000 Standard (Users) any of their rights under the copyright, not
026 * including other intellectual property rights, for this software module
027 * with respect to the usage by ISO/IEC and Users of this software module
028 * or modifications thereof for use in hardware or software products
029 * claiming conformance to the JPEG 2000 Standard. Those intending to use
030 * this software module in hardware or software products are advised that
031 * their use may infringe existing patents. The original developers of
032 * this software module, JJ2000 Partners and ISO/IEC assume no liability
033 * for use of this software module or modifications thereof. No license
034 * or right to this software module is granted for non JPEG 2000 Standard
035 * conforming products. JJ2000 Partners have full right to use this
036 * software module for his/her own purpose, assign or donate this
037 * software module to any third party and to inhibit third parties from
038 * using this software module for non JPEG 2000 Standard conforming
039 * products. This copyright notice must be included in all copies or
040 * derivative works of this software module.
041 *
042 * Copyright (c) 1999/2000 JJ2000 Partners.
043 * */
044package jj2000.j2k.codestream.writer;
045import java.awt.Point;
046
047import jj2000.j2k.quantization.quantizer.*;
048import jj2000.j2k.wavelet.analysis.*;
049import jj2000.j2k.entropy.encoder.*;
050import jj2000.j2k.quantization.*;
051import jj2000.j2k.image.input.*;
052import jj2000.j2k.roi.encoder.*;
053import jj2000.j2k.codestream.*;
054import jj2000.j2k.wavelet.*;
055import jj2000.j2k.entropy.*;
056import jj2000.j2k.image.*;
057import jj2000.j2k.util.*;
058import jj2000.j2k.io.*;
059import jj2000.j2k.*;
060
061import java.util.*;
062import java.io.*;
063
064import com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageWriteParamJava;
065/**
066 * This class writes almost of the markers and marker segments in main header
067 * and in tile-part headers. It is created by the run() method of the Encoder
068 * instance.
069 *
070 * <p>A marker segment includes a marker and eventually marker segment
071 * parameters. It is designed by the three letter code of the marker
072 * associated with the marker segment. JPEG 2000 part I defines 6 types of
073 * markers: <ul> <li> Delimiting : SOC,SOT,SOD,EOC (written in
074 * FileCodestreamWriter).</li> <li> Fixed information: SIZ.</li> <li>
075 * Functional: COD,COC,RGN,QCD,QCC,POC.</li> <li> In bit-stream: SOP,EPH.</li>
076 * <li> Pointer: TLM,PLM,PLT,PPM,PPT.</li> <li> Informational:
077 * CRG,COM.</li></ul>
078 *
079 * <p>Main Header is written when Encoder instance calls encodeMainHeader
080 * whereas tile-part headers are written when the EBCOTRateAllocator instance
081 * calls encodeTilePartHeader.
082 *
083 * @see Encoder
084 * @see Markers
085 * @see EBCOTRateAllocator
086 * */
087public class HeaderEncoder implements Markers, StdEntropyCoderOptions {
088
089    /** Nominal range bit of the component defining default values in QCD for
090     * main header */
091    private int defimgn;
092
093    /** Nominal range bit of the component defining default values in QCD for
094     * tile headers */
095    private int deftilenr;
096
097    /** The number of components in the image */
098    protected int nComp;
099
100    /** Whether or not to write the JJ2000 COM marker segment */
101    private boolean enJJ2KMarkSeg = true;
102
103    /** Other COM marker segments specified in the command line */
104    private String otherCOMMarkSeg = null;
105
106    /** The ByteArrayOutputStream to store header data. This handler
107     * is kept in order to use methods not accessible from a general
108     * DataOutputStream. For the other methods, it's better to use
109     * variable hbuf.
110     *
111     * @see #hbuf */
112    protected ByteArrayOutputStream baos;
113
114    /** The DataOutputStream to store header data. This kind of object
115     * is useful to write short, int, .... It's constructor takes
116     * baos as parameter.
117     *
118     * @see #baos
119     **/
120    protected DataOutputStream hbuf;
121
122    /** The image data reader. Source of original data info */
123    protected ImgData origSrc;
124
125    /** An array specifying, for each component,if the data was signed
126        or not */
127    protected boolean isOrigSig[];
128
129    /** Reference to the rate allocator */
130    protected PostCompRateAllocator ralloc;
131
132    /** Reference to the DWT module */
133    protected ForwardWT dwt;
134
135    /** Reference to the tiler module */
136    protected Tiler tiler;
137
138    /** Reference to the ROI module */
139    protected ROIScaler roiSc;
140
141    /** The encoder specifications */
142    protected J2KImageWriteParamJava wp;
143
144    /**
145     * Initializes the header writer with the references to the coding chain.
146     *
147     * @param origsrc The original image data (before any component mixing,
148     * tiling, etc.)
149     *
150     * @param isorigsig An array specifying for each component if it was
151     * originally signed or not.
152     *
153     * @param dwt The discrete wavelet transform module.
154     *
155     * @param tiler The tiler module.
156     *
157     * @param encSpec The encoder specifications
158     *
159     * @param roiSc The ROI scaler module.
160     *
161     * @param ralloc The post compression rate allocator.
162     * */
163    public HeaderEncoder(ImgData origsrc, boolean isorigsig[],
164                         ForwardWT dwt, Tiler tiler,J2KImageWriteParamJava wp,
165                         ROIScaler roiSc, PostCompRateAllocator ralloc) {
166        if (origsrc.getNumComps() != isorigsig.length) {
167            throw new IllegalArgumentException();
168        }
169        this.origSrc   = origsrc;
170        this.isOrigSig = isorigsig;
171        this.dwt       = dwt;
172        this.tiler     = tiler;
173        this.wp   = wp;
174        this.roiSc     = roiSc;
175        this.ralloc    = ralloc;
176
177        baos = new ByteArrayOutputStream();
178        hbuf = new DataOutputStream(baos);
179        nComp = origsrc.getNumComps();
180//        enJJ2KMarkSeg = wp.getHjj2000_COM();
181//        otherCOMMarkSeg = wp.getHCOM();
182    }
183
184    /**
185     * Resets the contents of this HeaderEncoder to its initial state. It
186     * erases all the data in the header buffer and reactualizes the
187     * headerLength field of the bit stream writer.
188     * */
189    public void reset() {
190        baos.reset();
191        hbuf = new DataOutputStream(baos);
192    }
193
194    /**
195     * Returns the byte-buffer used to store the codestream header.
196     *
197     * @return A byte array countaining codestream header
198     * */
199    protected byte[] getBuffer(){
200        return baos.toByteArray();
201    }
202
203    /**
204     * Returns the length of the header.
205     *
206     * @return The length of the header in bytes
207     * */
208    public int getLength() {
209        return hbuf.size();
210    }
211
212    /**
213     * Writes the header to the specified BinaryDataOutput.
214     *
215     * @param out Where to write the header.
216     * */
217    public void writeTo(BinaryDataOutput out) throws IOException {
218        int i,len;
219        byte buf[];
220
221        buf = getBuffer();
222        len = getLength();
223
224        for (i=0; i<len; i++) {
225            out.writeByte(buf[i]);
226        }
227    }
228
229    /**
230     * Returns the number of bytes used in the codestream header's
231     * buffer.
232     *
233     * @return Header length in buffer (without any header
234     * overhead)
235     * */
236    protected int getBufferLength(){
237        return baos.size();
238    }
239
240    /**
241     * Writes the header to the specified OutputStream.
242     *
243     * @param out Where to write the header.
244     * */
245    public void writeTo(OutputStream out) throws IOException {
246        out.write(getBuffer(),0,getBufferLength());
247    }
248
249    /**
250     * Start Of Codestream marker (SOC) signalling the beginning of a
251     * codestream.
252     * */
253    private void writeSOC() throws IOException {
254        hbuf.writeShort(SOC);
255    }
256
257    /**
258     * Writes SIZ marker segment of the codestream header. It is a fixed
259     * information marker segment containing informations about image and tile
260     * sizes. It is required in the main header immediately after SOC marker
261     * segment.
262     * */
263    private void writeSIZ() throws IOException {
264        int tmp;
265
266        // SIZ marker
267        hbuf.writeShort(SIZ);
268
269        // Lsiz (Marker length) corresponding to
270        // Lsiz(2 bytes)+Rsiz(2)+Xsiz(4)+Ysiz(4)+XOsiz(4)+YOsiz(4)+
271        // XTsiz(4)+YTsiz(4)+XTOsiz(4)+YTOsiz(4)+Csiz(2)+
272        // (Ssiz(1)+XRsiz(1)+YRsiz(1))*nComp
273        // markSegLen = 38 + 3*nComp;
274        int markSegLen = 38 + 3*nComp;
275        hbuf.writeShort(markSegLen);
276
277        // Rsiz (codestream capabilities)
278        hbuf.writeShort(0); // JPEG 2000 - Part I
279
280        // Xsiz (original image width)
281        hbuf.writeInt(tiler.getImgWidth()+tiler.getImgULX());
282
283        // Ysiz (original image height)
284        hbuf.writeInt(tiler.getImgHeight()+tiler.getImgULY());
285
286        // XOsiz (horizontal offset from the origin of the reference
287        // grid to the left side of the image area)
288        hbuf.writeInt(tiler.getImgULX());
289
290        // YOsiz (vertical offset from the origin of the reference
291        // grid to the top side of the image area)
292        hbuf.writeInt(tiler.getImgULY());
293
294        // XTsiz (nominal tile width)
295        hbuf.writeInt(tiler.getNomTileWidth());
296
297        // YTsiz (nominal tile height)
298        hbuf.writeInt(tiler.getNomTileHeight());
299
300        Point torig = tiler.getTilingOrigin(null);
301        // XTOsiz (Horizontal offset from the origin of the reference
302        // grid to the left side of the first tile)
303        hbuf.writeInt(torig.x);
304
305        // YTOsiz (Vertical offset from the origin of the reference
306        // grid to the top side of the first tile)
307        hbuf.writeInt(torig.y);
308
309        // Csiz (number of components)
310        hbuf.writeShort(nComp);
311
312        // Bit-depth and downsampling factors.
313        for(int c=0; c<nComp; c++){ // Loop on each component
314
315            // Ssiz bit-depth before mixing
316            tmp = origSrc.getNomRangeBits(c)-1;
317
318            tmp |= ( (isOrigSig[c]?1:0)<<SSIZ_DEPTH_BITS );
319            hbuf.write(tmp);
320
321            // XRsiz (component sub-sampling value x-wise)
322            hbuf.write(tiler.getCompSubsX(c));
323
324            // YRsiz (component sub-sampling value y-wise)
325            hbuf.write(tiler.getCompSubsY(c));
326
327        } // End loop on each component
328
329    }
330
331    /**
332     * Writes COD marker segment. COD is a functional marker segment
333     * containing the code style default (coding style, decomposition,
334     * layering) used for compressing all the components in an image.
335     *
336     * <p>The values can be overriden for an individual component by a COC
337     * marker in either the main or the tile header.
338     *
339     * @param mh Flag indicating whether this marker belongs to the main
340     * header
341     *
342     * @param tileIdx Tile index if the marker belongs to a tile-part header
343     *
344     * @see #writeCOC
345     * */
346    protected void writeCOD(boolean mh, int tileIdx)
347        throws IOException {
348        AnWTFilter[][] filt;
349        boolean precinctPartitionUsed;
350        int tmp;
351        int mrl=0,a=0;
352        int ppx=0, ppy=0;
353        Progression[] prog;
354
355        if (mh) {
356            mrl = ((Integer)wp.getDecompositionLevel().getDefault()).intValue();
357            // get default precinct size
358            ppx = wp.getPrecinctPartition().getPPX(-1,-1,mrl);
359            ppy = wp.getPrecinctPartition().getPPY(-1,-1,mrl);
360            prog = (Progression[])(wp.getProgressionType().getDefault());
361        }
362        else {
363            mrl = ((Integer)wp.getDecompositionLevel().getTileDef(tileIdx)).intValue();
364            // get precinct size for specified tile
365            ppx = wp.getPrecinctPartition().getPPX(tileIdx,-1,mrl);
366            ppy = wp.getPrecinctPartition().getPPY(tileIdx,-1,mrl);
367            prog = (Progression[])(wp.getProgressionType().getTileDef(tileIdx));
368        }
369
370        if ( ppx != PRECINCT_PARTITION_DEF_SIZE ||
371             ppy != PRECINCT_PARTITION_DEF_SIZE ) {
372            precinctPartitionUsed = true;
373        }
374        else {
375            precinctPartitionUsed = false;
376        }
377
378        if ( precinctPartitionUsed ) {
379            // If precinct partition is used we add one byte per resolution
380            // level i.e. mrl+1 (+1 for resolution 0).
381            a = mrl+1;
382        }
383
384        // Write COD marker
385        hbuf.writeShort(COD);
386
387        // Lcod (marker segment length (in bytes)) Basic : Lcod(2
388        // bytes)+Scod(1)+SGcod(4)+SPcod(5+a)  where:
389        // a=0 if no precinct partition is used
390        // a=mrl+1 if precinct partition used
391        int markSegLen = 12+a;
392        hbuf.writeShort(markSegLen);
393
394        // Scod (coding style parameter)
395        tmp=0;
396        if ( precinctPartitionUsed )
397            tmp=SCOX_PRECINCT_PARTITION;
398
399        // Are SOP markers used ?
400        if (mh) {
401            if( ((String)wp.getSOP().getDefault().toString())
402                 .equalsIgnoreCase("true") ) {
403                tmp |= SCOX_USE_SOP;
404            }
405        }
406        else {
407            if ( ((String)wp.getSOP().getTileDef(tileIdx).toString())
408                 .equalsIgnoreCase("true") ) {
409                tmp |= SCOX_USE_SOP;
410            }
411        }
412
413        // Are EPH markers used ?
414        if(mh){
415            if ( ((String)wp.getEPH().getDefault().toString())
416                 .equalsIgnoreCase("true") ) {
417                tmp |= SCOX_USE_EPH;
418            }
419        }
420        else{
421            if ( ((String)wp.getEPH().getTileDef(tileIdx).toString())
422                 .equalsIgnoreCase("true") ) {
423                tmp |= SCOX_USE_EPH;
424            }
425        }
426        if (dwt.getCbULX()!=0) tmp |= SCOX_HOR_CB_PART;
427        if (dwt.getCbULY()!=0) tmp |= SCOX_VER_CB_PART;
428        hbuf.write(tmp);
429
430        // SGcod
431        // Progression order
432        hbuf.write(prog[0].type);
433
434        // Number of layers
435        hbuf.writeShort(ralloc.getNumLayers());
436
437        // Multiple component transform
438        // CSsiz (Color transform)
439        String str = null;
440        if(mh)
441            str = (String)wp.getComponentTransformation().getDefault();
442        else
443            str = (String)wp.getComponentTransformation().getTileDef(tileIdx);
444
445        if(str.equals("none"))
446            hbuf.write(0);
447        else
448            hbuf.write(1);
449
450        // SPcod
451        // Number of decomposition levels
452        hbuf.write(mrl);
453
454        // Code-block width and height
455        if ( mh ) {
456            // main header, get default values
457            tmp = wp.getCodeBlockSize().
458                getCBlkWidth(ModuleSpec.SPEC_DEF,-1,-1);
459            hbuf.write(MathUtil.log2(tmp)-2);
460            tmp = wp.getCodeBlockSize().
461                getCBlkHeight(ModuleSpec.SPEC_DEF,-1,-1);
462            hbuf.write(MathUtil.log2(tmp)-2);
463        }
464        else {
465            // tile header, get tile default values
466            tmp = wp.getCodeBlockSize().
467                getCBlkWidth(ModuleSpec.SPEC_TILE_DEF,tileIdx,-1);
468            hbuf.write(MathUtil.log2(tmp)-2);
469            tmp = wp.getCodeBlockSize().
470                getCBlkHeight(ModuleSpec.SPEC_TILE_DEF,tileIdx,-1);
471            hbuf.write(MathUtil.log2(tmp)-2);
472        }
473
474        // Style of the code-block coding passes
475        tmp = 0;
476        if(mh){ // Main header
477            // Selective arithmetic coding bypass ?
478            if( ((String)wp.getBypass().getDefault()).equals("true")) {
479                tmp |= OPT_BYPASS;
480            }
481            // MQ reset after each coding pass ?
482            if( ((String)wp.getResetMQ().getDefault()).equals("true")) {
483                tmp |= OPT_RESET_MQ;
484            }
485            // MQ termination after each arithmetically coded coding pass ?
486            if(  ((String)wp.getTerminateOnByte().getDefault()).equals("true") ) {
487                tmp |= OPT_TERM_PASS;
488            }
489            // Vertically stripe-causal context mode ?
490            if(  ((String)wp.getCausalCXInfo().getDefault()).equals("true") ) {
491                tmp |= OPT_VERT_STR_CAUSAL;
492            }
493            // Predictable termination ?
494            if( ((String)wp.getMethodForMQTermination().getDefault()).equals("predict")){
495                tmp |= OPT_PRED_TERM;
496            }
497            // Error resilience segmentation symbol insertion ?
498            if(  ((String)wp.getCodeSegSymbol().getDefault()).equals("true")) {
499                tmp |= OPT_SEG_SYMBOLS;
500            }
501        }
502        else{ // Tile header
503
504            // Selective arithmetic coding bypass ?
505            if( ((String)wp.getBypass().getTileDef(tileIdx)).equals("true")) {
506                tmp |= OPT_BYPASS;
507            }
508            // MQ reset after each coding pass ?
509            if( ((String)wp.getResetMQ().getTileDef(tileIdx)).equals("true")) {
510                tmp |= OPT_RESET_MQ;
511            }
512            // MQ termination after each arithmetically coded coding pass ?
513            if(  ((String)wp.getTerminateOnByte().getTileDef(tileIdx)).equals("true") ) {
514                tmp |= OPT_TERM_PASS;
515            }
516            // Vertically stripe-causal context mode ?
517            if(  ((String)wp.getCausalCXInfo().getTileDef(tileIdx)).equals("true") ) {
518                tmp |= OPT_VERT_STR_CAUSAL;
519            }
520            // Predictable termination ?
521            if( ((String)wp.getMethodForMQTermination().getTileDef(tileIdx)).equals("predict")){
522                tmp |= OPT_PRED_TERM;
523            }
524            // Error resilience segmentation symbol insertion ?
525            if(  ((String)wp.getCodeSegSymbol().getTileDef(tileIdx)).equals("true")) {
526                tmp |= OPT_SEG_SYMBOLS;
527            }
528        }
529        hbuf.write(tmp);
530
531        // Wavelet transform
532        // Wavelet Filter
533        if(mh){
534            filt=((AnWTFilter[][])wp.getFilters().getDefault());
535            hbuf.write(filt[0][0].getFilterType());
536        }else{
537            filt=((AnWTFilter[][])wp.getFilters().getTileDef(tileIdx));
538            hbuf.write(filt[0][0].getFilterType());
539        }
540
541        // Precinct partition
542        if ( precinctPartitionUsed ) {
543            // Write the precinct size for each resolution level + 1
544            // (resolution 0) if precinct partition is used.
545            Vector v[] = null;
546            if ( mh ) {
547                v = (Vector[])wp.getPrecinctPartition().getDefault();
548            }
549            else {
550                v = (Vector[])wp.getPrecinctPartition().getTileDef(tileIdx);
551            }
552            for (int r=mrl ; r>=0 ; r--) {
553                if ( r>=v[1].size() ) {
554                    tmp = ((Integer)v[1].elementAt(v[1].size()-1)).
555                        intValue();
556                }
557                else {
558                    tmp = ((Integer)v[1].elementAt(r)).intValue();
559                }
560                int yExp = (MathUtil.log2(tmp)<< 4) & 0x00F0;
561
562                if ( r>=v[0].size() ) {
563                    tmp = ((Integer)v[0].elementAt(v[0].size()-1)).
564                        intValue();
565                }
566                else {
567                    tmp = ((Integer)v[0].elementAt(r)).intValue();
568                }
569                int xExp = MathUtil.log2(tmp) & 0x000F;
570                hbuf.write(yExp|xExp);
571            }
572        }
573    }
574
575    /**
576     * Writes COC marker segment . It is a functional marker containing the
577     * coding style for one component (coding style, decomposition, layering).
578     *
579     * <P>Its values overrides any value previously set in COD in the main
580     * header or in the tile header.
581     *
582     * @param mh Flag indicating whether the main header is to be written
583     *
584     * @param tileIdx Tile index
585     *
586     * @param compIdx index of the component which need use of the COC marker
587     * segment.
588     *
589     * @see #writeCOD
590     * */
591    protected void writeCOC(boolean mh, int tileIdx, int compIdx)
592        throws IOException {
593        AnWTFilter[][] filt;
594        boolean precinctPartitionUsed;
595        int tmp;
596        int mrl=0,a=0;
597        int ppx=0, ppy=0;
598        Progression[] prog;
599
600        if (mh) {
601            mrl = ((Integer)wp.getDecompositionLevel().getCompDef(compIdx)).intValue();
602            // Get precinct size for specified component
603            ppx = wp.getPrecinctPartition().getPPX(-1, compIdx, mrl);
604            ppy = wp.getPrecinctPartition().getPPY(-1, compIdx, mrl);
605            prog = (Progression[])(wp.getProgressionType().getCompDef(compIdx));
606        }
607        else {
608            mrl = ((Integer)wp.getDecompositionLevel().getTileCompVal(tileIdx,compIdx)).
609                intValue();
610            // Get precinct size for specified component/tile
611            ppx = wp.getPrecinctPartition().getPPX(tileIdx, compIdx, mrl);
612            ppy = wp.getPrecinctPartition().getPPY(tileIdx, compIdx, mrl);
613            prog = (Progression[])(wp.getProgressionType().getTileCompVal(tileIdx,compIdx));
614        }
615
616        if ( ppx != Markers.PRECINCT_PARTITION_DEF_SIZE ||
617             ppy != Markers.PRECINCT_PARTITION_DEF_SIZE ) {
618            precinctPartitionUsed = true;
619        }
620        else {
621            precinctPartitionUsed = false;
622        }
623        if ( precinctPartitionUsed ) {
624            // If precinct partition is used we add one byte per resolution
625            // level  i.e. mrl+1 (+1 for resolution 0).
626            a = mrl+1;
627        }
628
629        // COC marker
630        hbuf.writeShort(COC);
631
632        // Lcoc (marker segment length (in bytes))
633        // Basic: Lcoc(2 bytes)+Scoc(1)+ Ccoc(1 or 2)+SPcod(5+a)
634        int markSegLen = 8 + ((nComp < 257) ? 1 : 2)+a;
635
636        // Rounded to the nearest even value greater or equals
637        hbuf.writeShort(markSegLen);
638
639        // Ccoc
640        if(nComp < 257) {
641            hbuf.write(compIdx);
642        }
643        else {
644            hbuf.writeShort(compIdx);
645        }
646
647        // Scod (coding style parameter)
648        tmp=0;
649        if ( precinctPartitionUsed ) {
650            tmp=SCOX_PRECINCT_PARTITION;
651        }
652        hbuf.write(tmp);
653
654
655        // SPcoc
656
657        // Number of decomposition levels
658        hbuf.write(mrl);
659
660        // Code-block width and height
661        if ( mh ) {
662            // main header, get component default values
663            tmp = wp.getCodeBlockSize().
664                getCBlkWidth(ModuleSpec.SPEC_COMP_DEF, -1, compIdx);
665            hbuf.write(MathUtil.log2(tmp)-2);
666            tmp = wp.getCodeBlockSize().
667                getCBlkHeight(ModuleSpec.SPEC_COMP_DEF, -1, compIdx);
668            hbuf.write(MathUtil.log2(tmp)-2);
669        }
670        else {
671            // tile header, get tile component values
672            tmp = wp.getCodeBlockSize().
673                getCBlkWidth(ModuleSpec.SPEC_TILE_COMP, tileIdx, compIdx);
674            hbuf.write(MathUtil.log2(tmp)-2);
675            tmp = wp.getCodeBlockSize().
676                getCBlkHeight(ModuleSpec.SPEC_TILE_COMP, tileIdx, compIdx);
677            hbuf.write(MathUtil.log2(tmp)-2);
678        }
679
680        // Entropy coding mode options
681        tmp = 0;
682        if(mh){ // Main header
683            // Lazy coding mode ?
684            if( ((String)wp.getBypass().getCompDef(compIdx)).equals("true")) {
685                tmp |= OPT_BYPASS;
686            }
687            // MQ reset after each coding pass ?
688            if( ((String)wp.getResetMQ().getCompDef(compIdx)).
689                equalsIgnoreCase("true")) {
690                tmp |= OPT_RESET_MQ;
691            }
692            // MQ termination after each arithmetically coded coding pass ?
693            if(  ((String)wp.getTerminateOnByte().getCompDef(compIdx)).equals("true") ) {
694                tmp |= OPT_TERM_PASS;
695            }
696            // Vertically stripe-causal context mode ?
697            if(  ((String)wp.getCausalCXInfo().getCompDef(compIdx)).equals("true") ) {
698                tmp |= OPT_VERT_STR_CAUSAL;
699            }
700            // Predictable termination ?
701            if( ((String)wp.getMethodForMQTermination().getCompDef(compIdx)).equals("predict")){
702                tmp |= OPT_PRED_TERM;
703            }
704            // Error resilience segmentation symbol insertion ?
705            if(  ((String)wp.getCodeSegSymbol().getCompDef(compIdx)).equals("true")) {
706                tmp |= OPT_SEG_SYMBOLS;
707            }
708        }
709        else{ // Tile Header
710            if( ((String)wp.getBypass().getTileCompVal(tileIdx,compIdx)).
711                equals("true")) {
712                tmp |= OPT_BYPASS;
713            }
714            // MQ reset after each coding pass ?
715            if( ((String)wp.getResetMQ().getTileCompVal(tileIdx,compIdx)).
716                equals("true")) {
717                tmp |= OPT_RESET_MQ;
718            }
719            // MQ termination after each arithmetically coded coding pass ?
720            if(  ((String)wp.getTerminateOnByte().getTileCompVal(tileIdx,compIdx)).
721                 equals("true") ) {
722                tmp |= OPT_TERM_PASS;
723            }
724            // Vertically stripe-causal context mode ?
725            if(  ((String)wp.getCausalCXInfo().getTileCompVal(tileIdx,compIdx)).
726                 equals("true") ) {
727                tmp |= OPT_VERT_STR_CAUSAL;
728            }
729            // Predictable termination ?
730            if( ((String)wp.getMethodForMQTermination().getTileCompVal(tileIdx,compIdx)).
731                equals("predict")){
732                tmp |= OPT_PRED_TERM;
733            }
734            // Error resilience segmentation symbol insertion ?
735            if(  ((String)wp.getCodeSegSymbol().getTileCompVal(tileIdx,compIdx)).
736                 equals("true")) {
737                tmp |= OPT_SEG_SYMBOLS;
738            }
739        }
740        hbuf.write(tmp);
741
742        // Wavelet transform
743        // Wavelet Filter
744        if(mh){
745            filt=((AnWTFilter[][])wp.getFilters().getCompDef(compIdx));
746            hbuf.write(filt[0][0].getFilterType());
747        }else{
748            filt=((AnWTFilter[][])wp.getFilters().getTileCompVal(tileIdx,compIdx));
749            hbuf.write(filt[0][0].getFilterType());
750        }
751
752        // Precinct partition
753        if ( precinctPartitionUsed ) {
754            // Write the precinct size for each resolution level + 1
755            // (resolution 0) if precinct partition is used.
756            Vector v[] = null;
757            if ( mh ) {
758                v = (Vector[])wp.getPrecinctPartition().getCompDef(compIdx);
759            }
760            else {
761                v = (Vector[])wp.getPrecinctPartition().getTileCompVal(tileIdx, compIdx);
762            }
763            for (int r=mrl ; r>=0 ; r--) {
764                if ( r>=v[1].size() ) {
765                    tmp = ((Integer)v[1].elementAt(v[1].size()-1)).
766                        intValue();
767                }
768                else {
769                    tmp = ((Integer)v[1].elementAt(r)).intValue();
770                }
771                int yExp = (MathUtil.log2(tmp)<< 4) & 0x00F0;
772
773                if ( r>=v[0].size() ) {
774                    tmp = ((Integer)v[0].elementAt(v[0].size()-1)).
775                        intValue();
776                }
777                else {
778                    tmp = ((Integer)v[0].elementAt(r)).intValue();
779                }
780                int xExp = MathUtil.log2(tmp) & 0x000F;
781                hbuf.write(yExp|xExp);
782            }
783        }
784
785    }
786
787    /**
788     * Writes QCD marker segment in main header. QCD is a functional marker
789     * segment countaining the quantization default used for compressing all
790     * the components in an image. The values can be overriden for an
791     * individual component by a QCC marker in either the main or the tile
792     * header.
793     * */
794    protected void writeMainQCD() throws IOException{
795        float step;
796
797        String qType = (String)wp.getQuantizationType().getDefault();
798        float baseStep = ((Float)wp.getQuantizationStep().getDefault()).floatValue();
799        int gb = ((Integer)wp.getGuardBits().getDefault()).intValue();
800
801        boolean isDerived   = qType.equals("derived");
802        boolean isReversible = qType.equals("reversible");
803        int mrl = ((Integer)wp.getDecompositionLevel().getDefault()).intValue();
804
805        int nt = dwt.getNumTiles();
806        int nc = dwt.getNumComps();
807        int tmpI;
808        int[] tcIdx = new int[2];
809        String tmpStr;
810        boolean notFound = true;
811        for(int t=0; t<nt && notFound; t++) {
812            for(int c=0; c<nc && notFound; c++) {
813                tmpI = ((Integer)wp.getDecompositionLevel().getTileCompVal(t,c)).intValue();
814                tmpStr = (String)wp.getQuantizationType().getTileCompVal(t,c);
815                if(tmpI==mrl && tmpStr.equals(qType)) {
816                    tcIdx[0] = t; tcIdx[1] = c;
817                    notFound = false;
818                }
819            }
820        }
821        if(notFound) {
822            throw new Error("Default representative for quantization type "+
823                            " and number of decomposition levels not found "+
824                            " in main QCD marker segment. "+
825                            "You have found a JJ2000 bug.");
826        }
827        SubbandAn sb,csb,
828            sbRoot = dwt.getAnSubbandTree(tcIdx[0],tcIdx[1]);
829        defimgn = dwt.getNomRangeBits(tcIdx[1]);
830
831        int nqcd; // Number of quantization step-size to transmit
832
833        // Get the quantization style
834        int qstyle = (isReversible) ? SQCX_NO_QUANTIZATION :
835            ((isDerived) ? SQCX_SCALAR_DERIVED : SQCX_SCALAR_EXPOUNDED);
836
837        // QCD marker
838        hbuf.writeShort(QCD);
839
840
841        // Compute the number of steps to send
842        switch (qstyle) {
843        case SQCX_SCALAR_DERIVED:
844            nqcd = 1; // Just the LL value
845            break;
846        case SQCX_NO_QUANTIZATION:
847        case SQCX_SCALAR_EXPOUNDED:
848            // One value per subband
849            nqcd=0;
850
851            sb=sbRoot;
852
853            // Get the subband at first resolution level
854            sb = (SubbandAn) sb.getSubbandByIdx(0,0);
855
856            // Count total number of subbands
857            for (int j=0; j<=mrl; j++) {
858                csb = sb;
859                while (csb != null) {
860                    nqcd++;
861                    csb = (SubbandAn) csb.nextSubband();
862                }
863                // Go up one resolution level
864                sb = (SubbandAn) sb.getNextResLevel();
865            }
866            break;
867        default:
868            throw new Error("Internal JJ2000 error");
869        }
870
871        // Lqcd (marker segment length (in bytes))
872        // Lqcd(2 bytes)+Sqcd(1)+ SPqcd (2*Nqcd)
873        int markSegLen = 3 + ((isReversible) ? nqcd : 2*nqcd);
874
875        // Rounded to the nearest even value greater or equals
876        hbuf.writeShort(markSegLen);
877
878        // Sqcd
879        hbuf.write(qstyle+(gb<<SQCX_GB_SHIFT));
880
881        // SPqcd
882        switch (qstyle) {
883        case SQCX_NO_QUANTIZATION:
884            sb = sbRoot;
885            sb = (SubbandAn)sb.getSubbandByIdx(0,0);
886
887            // Output one exponent per subband
888            for (int j=0; j<=mrl; j++) {
889                csb = sb;
890                while(csb != null) {
891                    int tmp = (defimgn + csb.anGainExp);
892                    hbuf.write(tmp<<SQCX_EXP_SHIFT);
893
894                    csb = (SubbandAn)csb.nextSubband();
895                    // Go up one resolution level
896                }
897                sb = (SubbandAn)sb.getNextResLevel();
898            }
899            break;
900        case SQCX_SCALAR_DERIVED:
901            sb = sbRoot;
902            sb = (SubbandAn)sb.getSubbandByIdx(0,0);
903
904            // Calculate subband step (normalized to unit
905            // dynamic range)
906            step = baseStep/(1<<sb.level);
907
908            // Write exponent-mantissa, 16 bits
909            hbuf.writeShort(StdQuantizer.
910                            convertToExpMantissa(step));
911            break;
912        case SQCX_SCALAR_EXPOUNDED:
913            sb = sbRoot;
914            sb = (SubbandAn)sb.getSubbandByIdx(0,0);
915
916            // Output one step per subband
917            for (int j=0; j<=mrl; j++) {
918                csb = sb;
919                while(csb != null) {
920                    // Calculate subband step (normalized to unit
921                    // dynamic range)
922                    step = baseStep/(csb.l2Norm*(1<<csb.anGainExp));
923
924                    // Write exponent-mantissa, 16 bits
925                    hbuf.writeShort(StdQuantizer.
926                                    convertToExpMantissa(step));
927
928                    csb = (SubbandAn)csb.nextSubband();
929                }
930                // Go up one resolution level
931                sb = (SubbandAn)sb.getNextResLevel();
932            }
933            break;
934        default:
935            throw new Error("Internal JJ2000 error");
936        }
937    }
938
939    /**
940     * Writes QCC marker segment in main header. It is a functional
941     * marker segment countaining the quantization used for
942     * compressing the specified component in an image. The values
943     * override for the specified component what was defined by a QCC
944     * marker in either the main or the tile header.
945     *
946     * @param compIdx Index of the component which needs QCC marker
947     * segment.
948     * */
949    protected void writeMainQCC(int compIdx)
950        throws IOException{
951
952        int mrl;
953        int qstyle;
954        int tIdx = 0;
955        float step;
956
957        SubbandAn sb,sb2;
958        SubbandAn sbRoot;
959
960        int imgnr = dwt.getNomRangeBits(compIdx);
961        String qType = (String)wp.getQuantizationType().getCompDef(compIdx);
962        float baseStep = ((Float)wp.getQuantizationStep().getCompDef(compIdx)).floatValue();
963        int gb = ((Integer)wp.getGuardBits().getCompDef(compIdx)).intValue();
964
965        boolean isReversible = qType.equals("reversible");
966        boolean isDerived   = qType.equals("derived");
967
968        mrl = ((Integer)wp.getDecompositionLevel().getCompDef(compIdx)).intValue();
969
970        int nt = dwt.getNumTiles();
971        int nc = dwt.getNumComps();
972        int tmpI;
973        String tmpStr;
974        boolean notFound = true;
975        for(int t=0; t<nt && notFound; t++) {
976            for(int c=0; c<nc && notFound; c++) {
977                tmpI = ((Integer)wp.getDecompositionLevel().getTileCompVal(t,c)).intValue();
978                tmpStr = (String)wp.getQuantizationType().getTileCompVal(t,c);
979                if(tmpI==mrl && tmpStr.equals(qType)) {
980                    tIdx = t;
981                    notFound = false;
982                }
983            }
984        }
985        if(notFound) {
986            throw new Error("Default representative for quantization type "+
987                            " and number of decomposition levels not found "+
988                            " in main QCC (c="+compIdx+") marker segment. "+
989                            "You have found a JJ2000 bug.");
990        }
991        sbRoot = dwt.getAnSubbandTree(tIdx,compIdx);
992
993        int nqcc; // Number of quantization step-size to transmit
994
995        // Get the quantization style
996        if(isReversible) {
997            qstyle = SQCX_NO_QUANTIZATION;
998        }
999        else if (isDerived) {
1000            qstyle = SQCX_SCALAR_DERIVED;
1001        }
1002        else {
1003            qstyle = SQCX_SCALAR_EXPOUNDED;
1004        }
1005
1006        // QCC marker
1007        hbuf.writeShort(QCC);
1008
1009        // Compute the number of steps to send
1010        switch (qstyle) {
1011        case SQCX_SCALAR_DERIVED:
1012            nqcc = 1; // Just the LL value
1013            break;
1014        case SQCX_NO_QUANTIZATION:
1015        case SQCX_SCALAR_EXPOUNDED:
1016            // One value per subband
1017            nqcc = 0;
1018
1019            sb = sbRoot;
1020            mrl = sb.resLvl;
1021
1022            // Get the subband at first resolution level
1023            sb = (SubbandAn)sb.getSubbandByIdx(0,0);
1024
1025            // Find root element for LL subband
1026            while (sb.resLvl != 0) {
1027                sb = sb.subb_LL;
1028            }
1029
1030            // Count total number of subbands
1031            for (int j=0; j<=mrl; j++) {
1032                sb2 = sb;
1033                while (sb2 != null) {
1034                    nqcc++;
1035                    sb2 = (SubbandAn) sb2.nextSubband();
1036                }
1037                // Go up one resolution level
1038                sb = (SubbandAn) sb.getNextResLevel();
1039            }
1040            break;
1041        default:
1042            throw new Error("Internal JJ2000 error");
1043        }
1044
1045        // Lqcc (marker segment length (in bytes))
1046        // Lqcc(2 bytes)+Cqcc(1 or 2)+Sqcc(1)+ SPqcc (2*Nqcc)
1047        int markSegLen = 3 + ((nComp < 257) ? 1 : 2) +
1048            ((isReversible) ? nqcc : 2*nqcc);
1049        hbuf.writeShort(markSegLen);
1050
1051        // Cqcc
1052        if (nComp < 257) {
1053            hbuf.write(compIdx);
1054        }
1055        else {
1056            hbuf.writeShort(compIdx);
1057        }
1058
1059        // Sqcc (quantization style)
1060        hbuf.write(qstyle+(gb<<SQCX_GB_SHIFT));
1061
1062        // SPqcc
1063        switch (qstyle) {
1064        case SQCX_NO_QUANTIZATION:
1065            // Get resolution level 0 subband
1066            sb = sbRoot;
1067            sb = (SubbandAn) sb.getSubbandByIdx(0,0);
1068
1069            // Output one exponent per subband
1070            for (int j=0; j<=mrl; j++) {
1071                sb2 = sb;
1072                while (sb2 != null) {
1073                    int tmp = (imgnr+sb2.anGainExp);
1074                    hbuf.write(tmp<<SQCX_EXP_SHIFT);
1075
1076                    sb2 = (SubbandAn)sb2.nextSubband();
1077                }
1078                // Go up one resolution level
1079                sb = (SubbandAn)sb.getNextResLevel();
1080            }
1081            break;
1082        case SQCX_SCALAR_DERIVED:
1083            // Get resolution level 0 subband
1084            sb = sbRoot;
1085            sb = (SubbandAn) sb.getSubbandByIdx(0,0);
1086
1087            // Calculate subband step (normalized to unit
1088            // dynamic range)
1089            step = baseStep/(1<<sb.level);
1090
1091            // Write exponent-mantissa, 16 bits
1092            hbuf.writeShort(StdQuantizer.
1093                            convertToExpMantissa(step));
1094            break;
1095        case SQCX_SCALAR_EXPOUNDED:
1096            // Get resolution level 0 subband
1097            sb = sbRoot;
1098            mrl = sb.resLvl;
1099
1100            sb = (SubbandAn) sb.getSubbandByIdx(0,0);
1101
1102            for (int j=0; j<=mrl; j++) {
1103                sb2 = sb;
1104                while (sb2 != null) {
1105                    // Calculate subband step (normalized to unit
1106                    // dynamic range)
1107                    step = baseStep/(sb2.l2Norm*(1<<sb2.anGainExp));
1108
1109                    // Write exponent-mantissa, 16 bits
1110                    hbuf.writeShort(StdQuantizer.
1111                                    convertToExpMantissa(step));
1112                    sb2 = (SubbandAn)sb2.nextSubband();
1113                }
1114                // Go up one resolution level
1115                sb = (SubbandAn) sb.getNextResLevel();
1116            }
1117            break;
1118        default:
1119            throw new Error("Internal JJ2000 error");
1120        }
1121    }
1122
1123    /**
1124     * Writes QCD marker segment in tile header. QCD is a functional
1125     * marker segment countaining the quantization default used for
1126     * compressing all the components in an image. The values can be
1127     * overriden for an individual component by a QCC marker in either
1128     * the main or the tile header.
1129     *
1130     * @param tIdx Tile index
1131     * */
1132    protected void writeTileQCD(int tIdx) throws IOException{
1133        int mrl;
1134        int qstyle;
1135
1136        float step;
1137        SubbandAn sb,csb,sbRoot;
1138
1139        String qType = (String)wp.getQuantizationType().getTileDef(tIdx);
1140        float baseStep = ((Float)wp.getQuantizationStep().getTileDef(tIdx)).floatValue();
1141        mrl = ((Integer)wp.getDecompositionLevel().getTileDef(tIdx)).intValue();
1142
1143        int nc = dwt.getNumComps();
1144        int tmpI;
1145        String tmpStr;
1146        boolean notFound = true;
1147        int compIdx = 0;
1148        for(int c=0; c<nc && notFound; c++) {
1149            tmpI = ((Integer)wp.getDecompositionLevel().getTileCompVal(tIdx,c)).intValue();
1150            tmpStr = (String)wp.getQuantizationStep().getTileCompVal(tIdx,c);
1151            if(tmpI==mrl && tmpStr.equals(qType)) {
1152                compIdx = c;
1153                notFound = false;
1154            }
1155        }
1156        if(notFound) {
1157            throw new Error("Default representative for quantization type "+
1158                            " and number of decomposition levels not found "+
1159                            " in tile QCD (t="+tIdx+") marker segment. "+
1160                            "You have found a JJ2000 bug.");
1161        }
1162
1163        sbRoot = dwt.getAnSubbandTree(tIdx,compIdx);
1164        deftilenr = dwt.getNomRangeBits(compIdx);
1165        int gb = ((Integer)wp.getGuardBits().getTileDef(tIdx)).intValue();
1166
1167        boolean isDerived   = qType.equals("derived");
1168        boolean isReversible = qType.equals("reversible");
1169
1170        int nqcd; // Number of quantization step-size to transmit
1171
1172        // Get the quantization style
1173        qstyle = (isReversible) ? SQCX_NO_QUANTIZATION :
1174            ((isDerived) ? SQCX_SCALAR_DERIVED : SQCX_SCALAR_EXPOUNDED);
1175
1176        // QCD marker
1177        hbuf.writeShort(QCD);
1178
1179        // Compute the number of steps to send
1180        switch (qstyle) {
1181        case SQCX_SCALAR_DERIVED:
1182            nqcd = 1; // Just the LL value
1183            break;
1184        case SQCX_NO_QUANTIZATION:
1185        case SQCX_SCALAR_EXPOUNDED:
1186            // One value per subband
1187            nqcd=0;
1188
1189            sb=sbRoot;
1190
1191            // Get the subband at first resolution level
1192            sb = (SubbandAn) sb.getSubbandByIdx(0,0);
1193
1194            // Count total number of subbands
1195            for (int j=0; j<=mrl; j++) {
1196                csb = sb;
1197                while (csb != null) {
1198                    nqcd++;
1199                    csb = (SubbandAn) csb.nextSubband();
1200                }
1201                // Go up one resolution level
1202                sb = (SubbandAn) sb.getNextResLevel();
1203            }
1204            break;
1205        default:
1206            throw new Error("Internal JJ2000 error");
1207        }
1208
1209        // Lqcd (marker segment length (in bytes))
1210        // Lqcd(2 bytes)+Sqcd(1)+ SPqcd (2*Nqcd)
1211        int markSegLen = 3 + ((isReversible) ? nqcd : 2*nqcd);
1212
1213        // Rounded to the nearest even value greater or equals
1214        hbuf.writeShort(markSegLen);
1215
1216        // Sqcd
1217        hbuf.write(qstyle+(gb<<SQCX_GB_SHIFT));
1218
1219        // SPqcd
1220        switch (qstyle) {
1221        case SQCX_NO_QUANTIZATION:
1222            sb = sbRoot;
1223            sb = (SubbandAn)sb.getSubbandByIdx(0,0);
1224
1225            // Output one exponent per subband
1226            for (int j=0; j<=mrl; j++) {
1227                csb = sb;
1228                while(csb != null) {
1229                    int tmp = (deftilenr+csb.anGainExp);
1230                    hbuf.write(tmp<<SQCX_EXP_SHIFT);
1231
1232                    csb = (SubbandAn)csb.nextSubband();
1233                    // Go up one resolution level
1234                }
1235                sb = (SubbandAn)sb.getNextResLevel();
1236            }
1237            break;
1238        case SQCX_SCALAR_DERIVED:
1239            sb = sbRoot;
1240            sb = (SubbandAn)sb.getSubbandByIdx(0,0);
1241
1242            // Calculate subband step (normalized to unit
1243            // dynamic range)
1244            step = baseStep/(1<<sb.level);
1245
1246            // Write exponent-mantissa, 16 bits
1247            hbuf.writeShort(StdQuantizer.
1248                            convertToExpMantissa(step));
1249            break;
1250        case SQCX_SCALAR_EXPOUNDED:
1251            sb = sbRoot;
1252            sb = (SubbandAn)sb.getSubbandByIdx(0,0);
1253
1254            // Output one step per subband
1255            for (int j=0; j<=mrl; j++) {
1256                csb = sb;
1257                while(csb != null) {
1258                    // Calculate subband step (normalized to unit
1259                    // dynamic range)
1260                    step = baseStep/(csb.l2Norm*(1<<csb.anGainExp));
1261
1262                    // Write exponent-mantissa, 16 bits
1263                    hbuf.writeShort(StdQuantizer.
1264                                    convertToExpMantissa(step));
1265
1266                    csb = (SubbandAn)csb.nextSubband();
1267                }
1268                // Go up one resolution level
1269                sb = (SubbandAn)sb.getNextResLevel();
1270            }
1271            break;
1272        default:
1273            throw new Error("Internal JJ2000 error");
1274        }
1275    }
1276
1277    /**
1278     * Writes QCC marker segment in tile header. It is a functional
1279     * marker segment countaining the quantization used for
1280     * compressing the specified component in an image. The values
1281     * override for the specified component what was defined by a QCC
1282     * marker in either the main or the tile header.
1283     *
1284     * @param t Tile index
1285     *
1286     * @param compIdx Index of the component which needs QCC marker
1287     * segment.
1288     * */
1289    protected void writeTileQCC(int t,int compIdx)
1290        throws IOException{
1291
1292        int mrl;
1293        int qstyle;
1294        float step;
1295
1296        SubbandAn sb,sb2;
1297        int nqcc; // Number of quantization step-size to transmit
1298
1299        SubbandAn sbRoot = dwt.getAnSubbandTree(t,compIdx);
1300        int imgnr = dwt.getNomRangeBits(compIdx);
1301        String qType = (String)wp.getQuantizationType().getTileCompVal(t,compIdx);
1302        float baseStep = ((Float)wp.getQuantizationStep().getTileCompVal(t,compIdx)).
1303            floatValue();
1304        int gb = ((Integer)wp.getGuardBits().getTileCompVal(t,compIdx)).intValue();
1305
1306        boolean isReversible = qType.equals("reversible");
1307        boolean isDerived   = qType.equals("derived");
1308
1309        mrl = ((Integer)wp.getDecompositionLevel().getTileCompVal(t,compIdx)).intValue();
1310
1311        // Get the quantization style
1312        if(isReversible) {
1313            qstyle = SQCX_NO_QUANTIZATION;
1314        }
1315        else if (isDerived) {
1316            qstyle = SQCX_SCALAR_DERIVED;
1317        }
1318        else {
1319            qstyle = SQCX_SCALAR_EXPOUNDED;
1320        }
1321
1322        // QCC marker
1323        hbuf.writeShort(QCC);
1324
1325        // Compute the number of steps to send
1326        switch (qstyle) {
1327        case SQCX_SCALAR_DERIVED:
1328            nqcc = 1; // Just the LL value
1329            break;
1330        case SQCX_NO_QUANTIZATION:
1331        case SQCX_SCALAR_EXPOUNDED:
1332            // One value per subband
1333            nqcc = 0;
1334
1335            sb = sbRoot;
1336            mrl = sb.resLvl;
1337
1338            // Get the subband at first resolution level
1339            sb = (SubbandAn)sb.getSubbandByIdx(0,0);
1340
1341            // Find root element for LL subband
1342            while (sb.resLvl != 0) {
1343                sb = sb.subb_LL;
1344            }
1345
1346            // Count total number of subbands
1347            for (int j=0; j<=mrl; j++) {
1348                sb2 = sb;
1349                while (sb2 != null) {
1350                    nqcc++;
1351                    sb2 = (SubbandAn) sb2.nextSubband();
1352                }
1353                // Go up one resolution level
1354                sb = (SubbandAn) sb.getNextResLevel();
1355            }
1356            break;
1357        default:
1358            throw new Error("Internal JJ2000 error");
1359        }
1360
1361        // Lqcc (marker segment length (in bytes))
1362        // Lqcc(2 bytes)+Cqcc(1 or 2)+Sqcc(1)+ SPqcc (2*Nqcc)
1363        int markSegLen = 3 + ((nComp < 257) ? 1 : 2) +
1364            ((isReversible) ? nqcc : 2*nqcc);
1365        hbuf.writeShort(markSegLen);
1366
1367        // Cqcc
1368        if (nComp < 257) {
1369            hbuf.write(compIdx);
1370        }
1371        else {
1372            hbuf.writeShort(compIdx);
1373        }
1374
1375        // Sqcc (quantization style)
1376        hbuf.write(qstyle+(gb<<SQCX_GB_SHIFT));
1377
1378        // SPqcc
1379        switch (qstyle) {
1380        case SQCX_NO_QUANTIZATION:
1381            // Get resolution level 0 subband
1382            sb = sbRoot;
1383            sb = (SubbandAn) sb.getSubbandByIdx(0,0);
1384
1385            // Output one exponent per subband
1386            for (int j=0; j<=mrl; j++) {
1387                sb2 = sb;
1388                while (sb2 != null) {
1389                    int tmp = (imgnr+sb2.anGainExp);
1390                    hbuf.write(tmp<<SQCX_EXP_SHIFT);
1391
1392                    sb2 = (SubbandAn)sb2.nextSubband();
1393                }
1394                // Go up one resolution level
1395                sb = (SubbandAn)sb.getNextResLevel();
1396            }
1397            break;
1398        case SQCX_SCALAR_DERIVED:
1399            // Get resolution level 0 subband
1400            sb = sbRoot;
1401            sb = (SubbandAn) sb.getSubbandByIdx(0,0);
1402
1403            // Calculate subband step (normalized to unit
1404            // dynamic range)
1405            step = baseStep/(1<<sb.level);
1406
1407            // Write exponent-mantissa, 16 bits
1408            hbuf.writeShort(StdQuantizer.
1409                            convertToExpMantissa(step));
1410            break;
1411        case SQCX_SCALAR_EXPOUNDED:
1412            // Get resolution level 0 subband
1413            sb = sbRoot;
1414            mrl = sb.resLvl;
1415
1416            sb = (SubbandAn) sb.getSubbandByIdx(0,0);
1417
1418            for (int j=0; j<=mrl; j++) {
1419                sb2 = sb;
1420                while (sb2 != null) {
1421                    // Calculate subband step (normalized to unit
1422                    // dynamic range)
1423                    step = baseStep/(sb2.l2Norm*(1<<sb2.anGainExp));
1424
1425                    // Write exponent-mantissa, 16 bits
1426                    hbuf.writeShort(StdQuantizer.
1427                                    convertToExpMantissa(step));
1428                    sb2 = (SubbandAn)sb2.nextSubband();
1429                }
1430                // Go up one resolution level
1431                sb = (SubbandAn) sb.getNextResLevel();
1432            }
1433            break;
1434        default:
1435            throw new Error("Internal JJ2000 error");
1436        }
1437    }
1438
1439    /**
1440     * Writes POC marker segment. POC is a functional marker segment
1441     * containing the bounds and progression order for any progression order
1442     * other than default in the codestream.
1443     *
1444     * @param mh Flag indicating whether the main header is to be written
1445     *
1446     * @param tileIdx Tile index
1447     * */
1448    protected void writePOC(boolean mh, int tileIdx) throws IOException {
1449        int markSegLen=0;        // Segment marker length
1450        int lenCompField;        // Holds the size of any component field as
1451                                 // this size depends on the number of
1452                                 //components
1453        Progression[] prog = null; // Holds the progression(s)
1454        int npoc;                // Number of progression order changes
1455
1456        // Get the progression order changes, their number and checks
1457        // if it is ok
1458        if(mh){
1459            prog = (Progression[])(wp.getProgressionType().getDefault());
1460        }
1461        else {
1462            prog = (Progression[])(wp.getProgressionType().getTileDef(tileIdx));
1463        }
1464
1465        // Calculate the length of a component field (depends on the number of
1466        // components)
1467        lenCompField = (nComp<257 ? 1 : 2);
1468
1469        // POC marker
1470        hbuf.writeShort(POC);
1471
1472        // Lpoc (marker segment length (in bytes))
1473        // Basic: Lpoc(2 bytes) + npoc * [ RSpoc(1) + CSpoc(1 or 2) + LYEpoc(2)
1474        // + REpoc(1) + CEpoc(1 or 2) + Ppoc(1) ]
1475        npoc = prog.length;
1476        markSegLen = 2 + npoc * (1+lenCompField+2+1+lenCompField+1);
1477        hbuf.writeShort(markSegLen);
1478
1479        // Write each progression order change
1480        for (int i=0 ; i<npoc ; i++){
1481            // RSpoc(i)
1482            hbuf.write(prog[i].rs);
1483            // CSpoc(i)
1484            if ( lenCompField==2 ) {
1485                hbuf.writeShort(prog[i].cs);
1486            }
1487            else {
1488                hbuf.write(prog[i].cs);
1489            }
1490            // LYEpoc(i)
1491            hbuf.writeShort(prog[i].lye);
1492            // REpoc(i)
1493            hbuf.write(prog[i].re);
1494            // CEpoc(i)
1495            if ( lenCompField==2 ) {
1496                hbuf.writeShort(prog[i].ce);
1497            }
1498            else {
1499                hbuf.write(prog[i].ce);
1500            }
1501            // Ppoc(i)
1502            hbuf.write(prog[i].type);
1503        }
1504    }
1505
1506
1507    /**
1508     * Write main header. JJ2000 main header corresponds to the following
1509     * sequence of marker
1510     * segments:<ol><li>SOC</li><li>SIZ</li><li>COD</li><li>COC (if
1511     * needed)</li><li>QCD</li><li>QCC (if needed)</li><li>POC (if
1512     * needed)</li></ol>
1513     * */
1514    public void encodeMainHeader() throws IOException {
1515        int i;
1516
1517
1518        // +---------------------------------+
1519        // |    SOC marker segment           |
1520        // +---------------------------------+
1521        writeSOC();
1522
1523        // +---------------------------------+
1524        // |    Image and tile SIZe (SIZ)    |
1525        // +---------------------------------+
1526        writeSIZ();
1527
1528        // +-------------------------------+
1529        // |   COding style Default (COD)  |
1530        // +-------------------------------+
1531        boolean isEresUsed = ((String)wp.getTerminateOnByte().getDefault()).
1532            equals("predict");
1533        writeCOD(true,0);
1534
1535        // +---------------------------------+
1536        // |   COding style Component (COC)  |
1537        // +---------------------------------+
1538        for (i= 0; i<nComp; i++) {
1539            boolean isEresUsedinComp = ((String)wp.getTerminateOnByte().getCompDef(i)).
1540                equals("predict");
1541            if(wp.getFilters().isCompSpecified(i) ||
1542               wp.getDecompositionLevel().isCompSpecified(i) ||
1543               wp.getBypass().isCompSpecified(i) ||
1544               wp.getResetMQ().isCompSpecified(i) ||
1545               wp.getMethodForMQTermination().isCompSpecified(i) ||
1546               wp.getCodeSegSymbol().isCompSpecified(i) ||
1547               wp.getCausalCXInfo().isCompSpecified(i) ||
1548               wp.getPrecinctPartition().isCompSpecified(i) ||
1549               wp.getCodeBlockSize().isCompSpecified(i) ||
1550               (isEresUsed != isEresUsedinComp ) )
1551                // Some component non-default stuff => need COC
1552                writeCOC(true,0,i);
1553        }
1554
1555        // +-------------------------------+
1556        // |   Quantization Default (QCD)  |
1557        // +-------------------------------+
1558        writeMainQCD();
1559
1560        // +-------------------------------+
1561        // | Quantization Component (QCC)  |
1562        // +-------------------------------+
1563        // Write needed QCC markers
1564        for(i=0; i<nComp; i++){
1565            if(dwt.getNomRangeBits(i)!= defimgn ||
1566               wp.getQuantizationType().isCompSpecified(i) ||
1567               wp.getQuantizationStep().isCompSpecified(i) ||
1568               wp.getDecompositionLevel().isCompSpecified(i) ||
1569               wp.getGuardBits().isCompSpecified(i)){
1570                writeMainQCC(i);
1571            }
1572        }
1573
1574        // +--------------------------+
1575        // |    POC maker segment     |
1576        // +--------------------------+
1577        Progression[] prog = (Progression[])(wp.getProgressionType().getDefault());
1578        if(prog.length>1)
1579            writePOC(true, 0);
1580
1581        // +--------------------------+
1582        // |      Comment (COM)       |
1583        // +--------------------------+
1584        writeCOM();
1585    }
1586
1587    /**
1588     * Write a COM marker segment adding some comments to the codestream.
1589     *
1590     * <p> This marker is currently written in main header and indicates the
1591     * JJ2000 encoder's version that has created the codestream.
1592     * */
1593    private void writeCOM() throws IOException {
1594        // JJ2000 COM marker segment
1595        if(enJJ2KMarkSeg) {
1596            String str = "Created by: JJ2000 version "+JJ2KInfo.version;
1597            int markSegLen; // the marker segment length
1598
1599            // COM marker
1600            hbuf.writeShort(COM);
1601
1602            // Calculate length: Lcom(2) + Rcom (2) + string's length;
1603            markSegLen = 2 + 2 + str.length();
1604            hbuf.writeShort(markSegLen);
1605
1606            // Rcom 
1607            hbuf.writeShort(1); // General use (IS 8859-15:1999(Latin) values)
1608
1609            byte[] chars = str.getBytes();
1610            for(int i=0; i<chars.length; i++) {
1611                hbuf.writeByte(chars[i]);
1612            }
1613        }
1614        // other COM marker segments
1615        if(otherCOMMarkSeg!=null) {
1616            StringTokenizer stk = new StringTokenizer(otherCOMMarkSeg,"#");
1617            while(stk.hasMoreTokens()) {
1618                String str = stk.nextToken();
1619                int markSegLen; // the marker segment length
1620
1621                // COM marker
1622                hbuf.writeShort(COM);
1623
1624                // Calculate length: Lcom(2) + Rcom (2) + string's length;
1625                markSegLen = 2 + 2 + str.length();
1626                hbuf.writeShort(markSegLen);
1627
1628                // Rcom 
1629                hbuf.writeShort(1); // General use (IS 8859-15:1999(Latin)
1630                // values)
1631
1632                byte[] chars = str.getBytes();
1633                for(int i=0; i<chars.length; i++) {
1634                    hbuf.writeByte(chars[i]);
1635                }
1636            }
1637        }
1638    }
1639
1640    /**
1641     * Writes the RGN marker segment in the tile header. It describes the
1642     * scaling value in each tile component
1643     *
1644     * <P>May be used in tile or main header. If used in main header, it
1645     * refers to a ROI of the whole image, regardless of tiling. When used in
1646     * tile header, only the particular tile is affected.
1647     *
1648     * @param tIdx The tile index
1649     *
1650     * @exception IOException If an I/O error occurs while reading from the
1651     * encoder header stream
1652     * */
1653    private void writeRGN(int tIdx) throws IOException {
1654        int i;
1655        int markSegLen;    // the marker length
1656
1657        // Write one RGN marker per component
1658        for(i=0;i<nComp;i++){
1659            // RGN marker
1660            hbuf.writeShort(RGN);
1661
1662            // Calculate length (Lrgn)
1663            // Basic: Lrgn (2) + Srgn (1) + SPrgn + one byte
1664            // or two for component number
1665            markSegLen = 4+((nComp<257)? 1:2);
1666            hbuf.writeShort(markSegLen);
1667
1668            // Write component (Crgn)
1669            if(nComp<257)
1670                hbuf.writeByte(i);
1671            else
1672                hbuf.writeShort(i);
1673
1674            // Write type of ROI (Srgn)
1675            hbuf.writeByte(SRGN_IMPLICIT);
1676
1677            // Write ROI info (SPrgn)
1678            hbuf.writeByte(((Integer)(wp.getROIs().
1679                              getTileCompVal(tIdx,i))).intValue());
1680        }
1681    }
1682    /**
1683     * Writes tile-part header. JJ2000 tile-part header corresponds to the
1684     * following sequence of marker segments:<ol> <li>SOT</li> <li>COD (if
1685     * needed)</li> <li>COC (if needed)</li> <li>QCD (if needed)</li> <li>QCC
1686     * (if needed)</li> <li>RGN (if needed)</li> <li>POC (if needed)</li>
1687     * <li>SOD</li> </ol>
1688     *
1689     * @param length The length of the current tile-part.
1690     *
1691     * @param tileIdx Index of the tile to write
1692     * */
1693    public void encodeTilePartHeader(int tileLength,int tileIdx)
1694        throws IOException {
1695
1696        int tmp;
1697        Point numTiles = ralloc.getNumTiles(null);
1698        ralloc.setTile(tileIdx%numTiles.x,tileIdx/numTiles.x);
1699
1700        // +--------------------------+
1701        // |    SOT maker segment     |
1702        // +--------------------------+
1703        // SOT marker
1704        hbuf.writeByte(SOT>>8);
1705        hbuf.writeByte(SOT);
1706
1707        // Lsot (10 bytes)
1708        hbuf.writeByte(0);
1709        hbuf.writeByte(10);
1710
1711        // Isot
1712        if(tileIdx>65534){
1713            throw new IllegalArgumentException("Trying to write a tile-part "+
1714                                               "header whose tile index is too"+
1715                                               " high");
1716        }
1717        hbuf.writeByte(tileIdx>>8);
1718        hbuf.writeByte(tileIdx);
1719
1720        // Psot
1721        tmp = tileLength;
1722        hbuf.writeByte(tmp>>24);
1723        hbuf.writeByte(tmp>>16);
1724        hbuf.writeByte(tmp>>8);
1725        hbuf.writeByte(tmp);
1726
1727        // TPsot
1728        hbuf.writeByte(0); // Only one tile-part currently supported !
1729
1730        // TNsot
1731        hbuf.writeByte(1); // Only one tile-part currently supported !
1732
1733        // +--------------------------+
1734        // |    COD maker segment     |
1735        // +--------------------------+
1736        boolean isEresUsed = ((String)wp.getMethodForMQTermination().getDefault()).
1737            equals("predict");
1738        boolean isEresUsedInTile = ((String)wp.getMethodForMQTermination().getTileDef(tileIdx)).
1739            equals("predict");
1740        boolean tileCODwritten = false;
1741        if(wp.getFilters().isTileSpecified(tileIdx) ||
1742           wp.getComponentTransformation().isTileSpecified(tileIdx) ||
1743           wp.getDecompositionLevel().isTileSpecified(tileIdx) ||
1744           wp.getBypass().isTileSpecified(tileIdx) ||
1745           wp.getResetMQ().isTileSpecified(tileIdx) ||
1746           wp.getTerminateOnByte().isTileSpecified(tileIdx) ||
1747           wp.getCausalCXInfo().isTileSpecified(tileIdx) ||
1748           wp.getPrecinctPartition().isTileSpecified(tileIdx) ||
1749           wp.getSOP().isTileSpecified(tileIdx) ||
1750           wp.getCodeSegSymbol().isTileSpecified(tileIdx) ||
1751           wp.getProgressionType().isTileSpecified(tileIdx) ||
1752           wp.getEPH().isTileSpecified(tileIdx) ||
1753           wp.getCodeBlockSize().isTileSpecified(tileIdx) ||
1754           ( isEresUsed != isEresUsedInTile ) ) {
1755            writeCOD(false,tileIdx);
1756            tileCODwritten = true;
1757        }
1758
1759        // +--------------------------+
1760        // |    COC maker segment     |
1761        // +--------------------------+
1762        for(int c=0; c<nComp; c++){
1763            boolean isEresUsedInTileComp = ((String)wp.getMethodForMQTermination().
1764                                            getTileCompVal(tileIdx,c)).
1765                equals("predict");
1766
1767            if(wp.getFilters().isTileCompSpecified(tileIdx,c) ||
1768               wp.getDecompositionLevel().isTileCompSpecified(tileIdx,c) ||
1769               wp.getBypass().isTileCompSpecified(tileIdx,c) ||
1770               wp.getResetMQ().isTileCompSpecified(tileIdx,c) ||
1771               wp.getTerminateOnByte().isTileCompSpecified(tileIdx,c) ||
1772               wp.getCausalCXInfo().isTileCompSpecified(tileIdx,c) ||
1773               wp.getPrecinctPartition().isTileCompSpecified(tileIdx,c) ||
1774               wp.getCodeSegSymbol().isTileCompSpecified(tileIdx,c) ||
1775               wp.getCodeBlockSize().isTileCompSpecified(tileIdx,c) ||
1776               ( isEresUsedInTileComp != isEresUsed ) ) {
1777                writeCOC(false,tileIdx,c);
1778            }
1779            else if(tileCODwritten){
1780                if(wp.getFilters().isCompSpecified(c) ||
1781                   wp.getDecompositionLevel().isCompSpecified(c) ||
1782                   wp.getBypass().isCompSpecified(c) ||
1783                   wp.getResetMQ().isCompSpecified(c) ||
1784                   wp.getTerminateOnByte().isCompSpecified(c) ||
1785                   wp.getCodeSegSymbol().isCompSpecified(c) ||
1786                   wp.getCausalCXInfo().isCompSpecified(c) ||
1787                   wp.getPrecinctPartition().isCompSpecified(c) ||
1788                   wp.getCodeBlockSize().isCompSpecified(c) ||
1789                   (wp.getMethodForMQTermination().isCompSpecified(c)&&
1790                    ((String)wp.getMethodForMQTermination().getCompDef(c)).equals("predict"))){
1791                    writeCOC(false,tileIdx,c);
1792                }
1793            }
1794        }
1795
1796        // +--------------------------+
1797        // |    QCD maker segment     |
1798        // +--------------------------+
1799        boolean tileQCDwritten = false;
1800        if(wp.getQuantizationType().isTileSpecified(tileIdx) ||
1801           wp.getQuantizationStep().isTileSpecified(tileIdx) ||
1802           wp.getDecompositionLevel().isTileSpecified(tileIdx) ||
1803           wp.getGuardBits().isTileSpecified(tileIdx)){
1804            writeTileQCD(tileIdx);
1805            tileQCDwritten = true;
1806        } else {
1807            deftilenr = defimgn;
1808        }
1809
1810        // +--------------------------+
1811        // |    QCC maker segment     |
1812        // +--------------------------+
1813        for(int c=0; c<nComp; c++){
1814            if(dwt.getNomRangeBits(c)!= deftilenr ||
1815               wp.getQuantizationType().isTileCompSpecified(tileIdx,c) ||
1816               wp.getQuantizationStep().isTileCompSpecified(tileIdx,c) ||
1817               wp.getDecompositionLevel().isTileCompSpecified(tileIdx,c) ||
1818               wp.getGuardBits().isTileCompSpecified(tileIdx,c)){
1819                writeTileQCC(tileIdx,c);
1820            }
1821            else if(tileQCDwritten){
1822                if(wp.getQuantizationType().isCompSpecified(c) ||
1823                   wp.getQuantizationStep().isCompSpecified(c) ||
1824                   wp.getDecompositionLevel().isCompSpecified(c) ||
1825                   wp.getGuardBits().isCompSpecified(c)){
1826                    writeTileQCC(tileIdx,c);
1827                }
1828            }
1829        }
1830
1831        // +--------------------------+
1832        // |    RGN maker segment     |
1833        // +--------------------------+
1834        if(roiSc.useRoi() &&(!roiSc.getBlockAligned()))
1835            writeRGN(tileIdx);
1836
1837        // +--------------------------+
1838        // |    POC maker segment     |
1839        // +--------------------------+
1840        Progression[] prog;
1841        if( wp.getProgressionType().isTileSpecified(tileIdx) ){
1842            prog = (Progression[])(wp.getProgressionType().getTileDef(tileIdx));
1843            if(prog.length>1)
1844                writePOC(false,tileIdx);
1845        }
1846
1847        // +--------------------------+
1848        // |         SOD maker        |
1849        // +--------------------------+
1850        hbuf.writeByte(SOD>>8);
1851        hbuf.writeByte(SOD);
1852    }
1853}
1854