jj2000.j2k.codestream.writer.HeaderEncoder Maven / Gradle / Ivy
Show all versions of jai-imageio-jpeg2000 Show documentation
/*
* $RCSfile: HeaderEncoder.java,v $
* $Revision: 1.1 $
* $Date: 2005/02/11 05:02:02 $
* $State: Exp $
*
* Class: HeaderEncoder
*
* Description: Write codestream headers.
*
*
*
* COPYRIGHT:
*
* This software module was originally developed by Raphaël Grosbois and
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
* Centre France S.A) in the course of development of the JPEG2000
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
* software module is an implementation of a part of the JPEG 2000
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
* Partners) agree not to assert against ISO/IEC and users of the JPEG
* 2000 Standard (Users) any of their rights under the copyright, not
* including other intellectual property rights, for this software module
* with respect to the usage by ISO/IEC and Users of this software module
* or modifications thereof for use in hardware or software products
* claiming conformance to the JPEG 2000 Standard. Those intending to use
* this software module in hardware or software products are advised that
* their use may infringe existing patents. The original developers of
* this software module, JJ2000 Partners and ISO/IEC assume no liability
* for use of this software module or modifications thereof. No license
* or right to this software module is granted for non JPEG 2000 Standard
* conforming products. JJ2000 Partners have full right to use this
* software module for his/her own purpose, assign or donate this
* software module to any third party and to inhibit third parties from
* using this software module for non JPEG 2000 Standard conforming
* products. This copyright notice must be included in all copies or
* derivative works of this software module.
*
* Copyright (c) 1999/2000 JJ2000 Partners.
* */
package jj2000.j2k.codestream.writer;
import java.awt.Point;
import java.beans.Encoder;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.StringTokenizer;
import java.util.Vector;
import jj2000.j2k.JJ2KInfo;
import jj2000.j2k.ModuleSpec;
import jj2000.j2k.codestream.Markers;
import jj2000.j2k.entropy.Progression;
import jj2000.j2k.entropy.StdEntropyCoderOptions;
import jj2000.j2k.entropy.encoder.EBCOTRateAllocator;
import jj2000.j2k.entropy.encoder.PostCompRateAllocator;
import jj2000.j2k.image.ImgData;
import jj2000.j2k.image.Tiler;
import jj2000.j2k.io.BinaryDataOutput;
import jj2000.j2k.quantization.quantizer.StdQuantizer;
import jj2000.j2k.roi.encoder.ROIScaler;
import jj2000.j2k.util.MathUtil;
import jj2000.j2k.wavelet.analysis.AnWTFilter;
import jj2000.j2k.wavelet.analysis.ForwardWT;
import jj2000.j2k.wavelet.analysis.SubbandAn;
import com.github.jaiimageio.jpeg2000.impl.J2KImageWriteParamJava;
/**
* This class writes almost of the markers and marker segments in main header
* and in tile-part headers. It is created by the run() method of the Encoder
* instance.
*
* A marker segment includes a marker and eventually marker segment
* parameters. It is designed by the three letter code of the marker
* associated with the marker segment. JPEG 2000 part I defines 6 types of
* markers:
- Delimiting : SOC,SOT,SOD,EOC (written in
* FileCodestreamWriter).
- Fixed information: SIZ.
-
* Functional: COD,COC,RGN,QCD,QCC,POC.
- In bit-stream: SOP,EPH.
* - Pointer: TLM,PLM,PLT,PPM,PPT.
- Informational:
* CRG,COM.
*
* Main Header is written when Encoder instance calls encodeMainHeader
* whereas tile-part headers are written when the EBCOTRateAllocator instance
* calls encodeTilePartHeader.
*
* @see Encoder
* @see Markers
* @see EBCOTRateAllocator
* */
public class HeaderEncoder implements Markers, StdEntropyCoderOptions {
/** Nominal range bit of the component defining default values in QCD for
* main header */
private int defimgn;
/** Nominal range bit of the component defining default values in QCD for
* tile headers */
private int deftilenr;
/** The number of components in the image */
protected int nComp;
/** Whether or not to write the JJ2000 COM marker segment */
private boolean enJJ2KMarkSeg = true;
/** Other COM marker segments specified in the command line */
private String otherCOMMarkSeg = null;
/** The ByteArrayOutputStream to store header data. This handler
* is kept in order to use methods not accessible from a general
* DataOutputStream. For the other methods, it's better to use
* variable hbuf.
*
* @see #hbuf */
protected ByteArrayOutputStream baos;
/** The DataOutputStream to store header data. This kind of object
* is useful to write short, int, .... It's constructor takes
* baos as parameter.
*
* @see #baos
**/
protected DataOutputStream hbuf;
/** The image data reader. Source of original data info */
protected ImgData origSrc;
/** An array specifying, for each component,if the data was signed
or not */
protected boolean isOrigSig[];
/** Reference to the rate allocator */
protected PostCompRateAllocator ralloc;
/** Reference to the DWT module */
protected ForwardWT dwt;
/** Reference to the tiler module */
protected Tiler tiler;
/** Reference to the ROI module */
protected ROIScaler roiSc;
/** The encoder specifications */
protected J2KImageWriteParamJava wp;
/**
* Initializes the header writer with the references to the coding chain.
*
* @param origsrc The original image data (before any component mixing,
* tiling, etc.)
*
* @param isorigsig An array specifying for each component if it was
* originally signed or not.
*
* @param dwt The discrete wavelet transform module.
*
* @param tiler The tiler module.
*
* @param encSpec The encoder specifications
*
* @param roiSc The ROI scaler module.
*
* @param ralloc The post compression rate allocator.
* */
public HeaderEncoder(ImgData origsrc, boolean isorigsig[],
ForwardWT dwt, Tiler tiler,J2KImageWriteParamJava wp,
ROIScaler roiSc, PostCompRateAllocator ralloc) {
if (origsrc.getNumComps() != isorigsig.length) {
throw new IllegalArgumentException();
}
this.origSrc = origsrc;
this.isOrigSig = isorigsig;
this.dwt = dwt;
this.tiler = tiler;
this.wp = wp;
this.roiSc = roiSc;
this.ralloc = ralloc;
baos = new ByteArrayOutputStream();
hbuf = new DataOutputStream(baos);
nComp = origsrc.getNumComps();
// enJJ2KMarkSeg = wp.getHjj2000_COM();
// otherCOMMarkSeg = wp.getHCOM();
}
/**
* Resets the contents of this HeaderEncoder to its initial state. It
* erases all the data in the header buffer and reactualizes the
* headerLength field of the bit stream writer.
* */
public void reset() {
baos.reset();
hbuf = new DataOutputStream(baos);
}
/**
* Returns the byte-buffer used to store the codestream header.
*
* @return A byte array countaining codestream header
* */
protected byte[] getBuffer(){
return baos.toByteArray();
}
/**
* Returns the length of the header.
*
* @return The length of the header in bytes
* */
public int getLength() {
return hbuf.size();
}
/**
* Writes the header to the specified BinaryDataOutput.
*
* @param out Where to write the header.
* */
public void writeTo(BinaryDataOutput out) throws IOException {
int i,len;
byte buf[];
buf = getBuffer();
len = getLength();
for (i=0; iThe values can be overriden for an individual component by a COC
* marker in either the main or the tile header.
*
* @param mh Flag indicating whether this marker belongs to the main
* header
*
* @param tileIdx Tile index if the marker belongs to a tile-part header
*
* @see #writeCOC
* */
protected void writeCOD(boolean mh, int tileIdx)
throws IOException {
AnWTFilter[][] filt;
boolean precinctPartitionUsed;
int tmp;
int mrl=0,a=0;
int ppx=0, ppy=0;
Progression[] prog;
if (mh) {
mrl = ((Integer)wp.getDecompositionLevel().getDefault()).intValue();
// get default precinct size
ppx = wp.getPrecinctPartition().getPPX(-1,-1,mrl);
ppy = wp.getPrecinctPartition().getPPY(-1,-1,mrl);
prog = (Progression[])(wp.getProgressionType().getDefault());
}
else {
mrl = ((Integer)wp.getDecompositionLevel().getTileDef(tileIdx)).intValue();
// get precinct size for specified tile
ppx = wp.getPrecinctPartition().getPPX(tileIdx,-1,mrl);
ppy = wp.getPrecinctPartition().getPPY(tileIdx,-1,mrl);
prog = (Progression[])(wp.getProgressionType().getTileDef(tileIdx));
}
if ( ppx != PRECINCT_PARTITION_DEF_SIZE ||
ppy != PRECINCT_PARTITION_DEF_SIZE ) {
precinctPartitionUsed = true;
}
else {
precinctPartitionUsed = false;
}
if ( precinctPartitionUsed ) {
// If precinct partition is used we add one byte per resolution
// level i.e. mrl+1 (+1 for resolution 0).
a = mrl+1;
}
// Write COD marker
hbuf.writeShort(COD);
// Lcod (marker segment length (in bytes)) Basic : Lcod(2
// bytes)+Scod(1)+SGcod(4)+SPcod(5+a) where:
// a=0 if no precinct partition is used
// a=mrl+1 if precinct partition used
int markSegLen = 12+a;
hbuf.writeShort(markSegLen);
// Scod (coding style parameter)
tmp=0;
if ( precinctPartitionUsed )
tmp=SCOX_PRECINCT_PARTITION;
// Are SOP markers used ?
if (mh) {
if( ((String)wp.getSOP().getDefault().toString())
.equalsIgnoreCase("true") ) {
tmp |= SCOX_USE_SOP;
}
}
else {
if ( ((String)wp.getSOP().getTileDef(tileIdx).toString())
.equalsIgnoreCase("true") ) {
tmp |= SCOX_USE_SOP;
}
}
// Are EPH markers used ?
if(mh){
if ( ((String)wp.getEPH().getDefault().toString())
.equalsIgnoreCase("true") ) {
tmp |= SCOX_USE_EPH;
}
}
else{
if ( ((String)wp.getEPH().getTileDef(tileIdx).toString())
.equalsIgnoreCase("true") ) {
tmp |= SCOX_USE_EPH;
}
}
if (dwt.getCbULX()!=0) tmp |= SCOX_HOR_CB_PART;
if (dwt.getCbULY()!=0) tmp |= SCOX_VER_CB_PART;
hbuf.write(tmp);
// SGcod
// Progression order
hbuf.write(prog[0].type);
// Number of layers
hbuf.writeShort(ralloc.getNumLayers());
// Multiple component transform
// CSsiz (Color transform)
String str = null;
if(mh)
str = (String)wp.getComponentTransformation().getDefault();
else
str = (String)wp.getComponentTransformation().getTileDef(tileIdx);
if(str.equals("none"))
hbuf.write(0);
else
hbuf.write(1);
// SPcod
// Number of decomposition levels
hbuf.write(mrl);
// Code-block width and height
if ( mh ) {
// main header, get default values
tmp = wp.getCodeBlockSize().
getCBlkWidth(ModuleSpec.SPEC_DEF,-1,-1);
hbuf.write(MathUtil.log2(tmp)-2);
tmp = wp.getCodeBlockSize().
getCBlkHeight(ModuleSpec.SPEC_DEF,-1,-1);
hbuf.write(MathUtil.log2(tmp)-2);
}
else {
// tile header, get tile default values
tmp = wp.getCodeBlockSize().
getCBlkWidth(ModuleSpec.SPEC_TILE_DEF,tileIdx,-1);
hbuf.write(MathUtil.log2(tmp)-2);
tmp = wp.getCodeBlockSize().
getCBlkHeight(ModuleSpec.SPEC_TILE_DEF,tileIdx,-1);
hbuf.write(MathUtil.log2(tmp)-2);
}
// Style of the code-block coding passes
tmp = 0;
if(mh){ // Main header
// Selective arithmetic coding bypass ?
if( ((String)wp.getBypass().getDefault()).equals("true")) {
tmp |= OPT_BYPASS;
}
// MQ reset after each coding pass ?
if( ((String)wp.getResetMQ().getDefault()).equals("true")) {
tmp |= OPT_RESET_MQ;
}
// MQ termination after each arithmetically coded coding pass ?
if( ((String)wp.getTerminateOnByte().getDefault()).equals("true") ) {
tmp |= OPT_TERM_PASS;
}
// Vertically stripe-causal context mode ?
if( ((String)wp.getCausalCXInfo().getDefault()).equals("true") ) {
tmp |= OPT_VERT_STR_CAUSAL;
}
// Predictable termination ?
if( ((String)wp.getMethodForMQTermination().getDefault()).equals("predict")){
tmp |= OPT_PRED_TERM;
}
// Error resilience segmentation symbol insertion ?
if( ((String)wp.getCodeSegSymbol().getDefault()).equals("true")) {
tmp |= OPT_SEG_SYMBOLS;
}
}
else{ // Tile header
// Selective arithmetic coding bypass ?
if( ((String)wp.getBypass().getTileDef(tileIdx)).equals("true")) {
tmp |= OPT_BYPASS;
}
// MQ reset after each coding pass ?
if( ((String)wp.getResetMQ().getTileDef(tileIdx)).equals("true")) {
tmp |= OPT_RESET_MQ;
}
// MQ termination after each arithmetically coded coding pass ?
if( ((String)wp.getTerminateOnByte().getTileDef(tileIdx)).equals("true") ) {
tmp |= OPT_TERM_PASS;
}
// Vertically stripe-causal context mode ?
if( ((String)wp.getCausalCXInfo().getTileDef(tileIdx)).equals("true") ) {
tmp |= OPT_VERT_STR_CAUSAL;
}
// Predictable termination ?
if( ((String)wp.getMethodForMQTermination().getTileDef(tileIdx)).equals("predict")){
tmp |= OPT_PRED_TERM;
}
// Error resilience segmentation symbol insertion ?
if( ((String)wp.getCodeSegSymbol().getTileDef(tileIdx)).equals("true")) {
tmp |= OPT_SEG_SYMBOLS;
}
}
hbuf.write(tmp);
// Wavelet transform
// Wavelet Filter
if(mh){
filt=((AnWTFilter[][])wp.getFilters().getDefault());
hbuf.write(filt[0][0].getFilterType());
}else{
filt=((AnWTFilter[][])wp.getFilters().getTileDef(tileIdx));
hbuf.write(filt[0][0].getFilterType());
}
// Precinct partition
if ( precinctPartitionUsed ) {
// Write the precinct size for each resolution level + 1
// (resolution 0) if precinct partition is used.
Vector v[] = null;
if ( mh ) {
v = (Vector[])wp.getPrecinctPartition().getDefault();
}
else {
v = (Vector[])wp.getPrecinctPartition().getTileDef(tileIdx);
}
for (int r=mrl ; r>=0 ; r--) {
if ( r>=v[1].size() ) {
tmp = ((Integer)v[1].elementAt(v[1].size()-1)).
intValue();
}
else {
tmp = ((Integer)v[1].elementAt(r)).intValue();
}
int yExp = (MathUtil.log2(tmp)<< 4) & 0x00F0;
if ( r>=v[0].size() ) {
tmp = ((Integer)v[0].elementAt(v[0].size()-1)).
intValue();
}
else {
tmp = ((Integer)v[0].elementAt(r)).intValue();
}
int xExp = MathUtil.log2(tmp) & 0x000F;
hbuf.write(yExp|xExp);
}
}
}
/**
* Writes COC marker segment . It is a functional marker containing the
* coding style for one component (coding style, decomposition, layering).
*
* Its values overrides any value previously set in COD in the main
* header or in the tile header.
*
* @param mh Flag indicating whether the main header is to be written
*
* @param tileIdx Tile index
*
* @param compIdx index of the component which need use of the COC marker
* segment.
*
* @see #writeCOD
* */
protected void writeCOC(boolean mh, int tileIdx, int compIdx)
throws IOException {
AnWTFilter[][] filt;
boolean precinctPartitionUsed;
int tmp;
int mrl=0,a=0;
int ppx=0, ppy=0;
Progression[] prog;
if (mh) {
mrl = ((Integer)wp.getDecompositionLevel().getCompDef(compIdx)).intValue();
// Get precinct size for specified component
ppx = wp.getPrecinctPartition().getPPX(-1, compIdx, mrl);
ppy = wp.getPrecinctPartition().getPPY(-1, compIdx, mrl);
prog = (Progression[])(wp.getProgressionType().getCompDef(compIdx));
}
else {
mrl = ((Integer)wp.getDecompositionLevel().getTileCompVal(tileIdx,compIdx)).
intValue();
// Get precinct size for specified component/tile
ppx = wp.getPrecinctPartition().getPPX(tileIdx, compIdx, mrl);
ppy = wp.getPrecinctPartition().getPPY(tileIdx, compIdx, mrl);
prog = (Progression[])(wp.getProgressionType().getTileCompVal(tileIdx,compIdx));
}
if ( ppx != Markers.PRECINCT_PARTITION_DEF_SIZE ||
ppy != Markers.PRECINCT_PARTITION_DEF_SIZE ) {
precinctPartitionUsed = true;
}
else {
precinctPartitionUsed = false;
}
if ( precinctPartitionUsed ) {
// If precinct partition is used we add one byte per resolution
// level i.e. mrl+1 (+1 for resolution 0).
a = mrl+1;
}
// COC marker
hbuf.writeShort(COC);
// Lcoc (marker segment length (in bytes))
// Basic: Lcoc(2 bytes)+Scoc(1)+ Ccoc(1 or 2)+SPcod(5+a)
int markSegLen = 8 + ((nComp < 257) ? 1 : 2)+a;
// Rounded to the nearest even value greater or equals
hbuf.writeShort(markSegLen);
// Ccoc
if(nComp < 257) {
hbuf.write(compIdx);
}
else {
hbuf.writeShort(compIdx);
}
// Scod (coding style parameter)
tmp=0;
if ( precinctPartitionUsed ) {
tmp=SCOX_PRECINCT_PARTITION;
}
hbuf.write(tmp);
// SPcoc
// Number of decomposition levels
hbuf.write(mrl);
// Code-block width and height
if ( mh ) {
// main header, get component default values
tmp = wp.getCodeBlockSize().
getCBlkWidth(ModuleSpec.SPEC_COMP_DEF, -1, compIdx);
hbuf.write(MathUtil.log2(tmp)-2);
tmp = wp.getCodeBlockSize().
getCBlkHeight(ModuleSpec.SPEC_COMP_DEF, -1, compIdx);
hbuf.write(MathUtil.log2(tmp)-2);
}
else {
// tile header, get tile component values
tmp = wp.getCodeBlockSize().
getCBlkWidth(ModuleSpec.SPEC_TILE_COMP, tileIdx, compIdx);
hbuf.write(MathUtil.log2(tmp)-2);
tmp = wp.getCodeBlockSize().
getCBlkHeight(ModuleSpec.SPEC_TILE_COMP, tileIdx, compIdx);
hbuf.write(MathUtil.log2(tmp)-2);
}
// Entropy coding mode options
tmp = 0;
if(mh){ // Main header
// Lazy coding mode ?
if( ((String)wp.getBypass().getCompDef(compIdx)).equals("true")) {
tmp |= OPT_BYPASS;
}
// MQ reset after each coding pass ?
if( ((String)wp.getResetMQ().getCompDef(compIdx)).
equalsIgnoreCase("true")) {
tmp |= OPT_RESET_MQ;
}
// MQ termination after each arithmetically coded coding pass ?
if( ((String)wp.getTerminateOnByte().getCompDef(compIdx)).equals("true") ) {
tmp |= OPT_TERM_PASS;
}
// Vertically stripe-causal context mode ?
if( ((String)wp.getCausalCXInfo().getCompDef(compIdx)).equals("true") ) {
tmp |= OPT_VERT_STR_CAUSAL;
}
// Predictable termination ?
if( ((String)wp.getMethodForMQTermination().getCompDef(compIdx)).equals("predict")){
tmp |= OPT_PRED_TERM;
}
// Error resilience segmentation symbol insertion ?
if( ((String)wp.getCodeSegSymbol().getCompDef(compIdx)).equals("true")) {
tmp |= OPT_SEG_SYMBOLS;
}
}
else{ // Tile Header
if( ((String)wp.getBypass().getTileCompVal(tileIdx,compIdx)).
equals("true")) {
tmp |= OPT_BYPASS;
}
// MQ reset after each coding pass ?
if( ((String)wp.getResetMQ().getTileCompVal(tileIdx,compIdx)).
equals("true")) {
tmp |= OPT_RESET_MQ;
}
// MQ termination after each arithmetically coded coding pass ?
if( ((String)wp.getTerminateOnByte().getTileCompVal(tileIdx,compIdx)).
equals("true") ) {
tmp |= OPT_TERM_PASS;
}
// Vertically stripe-causal context mode ?
if( ((String)wp.getCausalCXInfo().getTileCompVal(tileIdx,compIdx)).
equals("true") ) {
tmp |= OPT_VERT_STR_CAUSAL;
}
// Predictable termination ?
if( ((String)wp.getMethodForMQTermination().getTileCompVal(tileIdx,compIdx)).
equals("predict")){
tmp |= OPT_PRED_TERM;
}
// Error resilience segmentation symbol insertion ?
if( ((String)wp.getCodeSegSymbol().getTileCompVal(tileIdx,compIdx)).
equals("true")) {
tmp |= OPT_SEG_SYMBOLS;
}
}
hbuf.write(tmp);
// Wavelet transform
// Wavelet Filter
if(mh){
filt=((AnWTFilter[][])wp.getFilters().getCompDef(compIdx));
hbuf.write(filt[0][0].getFilterType());
}else{
filt=((AnWTFilter[][])wp.getFilters().getTileCompVal(tileIdx,compIdx));
hbuf.write(filt[0][0].getFilterType());
}
// Precinct partition
if ( precinctPartitionUsed ) {
// Write the precinct size for each resolution level + 1
// (resolution 0) if precinct partition is used.
Vector v[] = null;
if ( mh ) {
v = (Vector[])wp.getPrecinctPartition().getCompDef(compIdx);
}
else {
v = (Vector[])wp.getPrecinctPartition().getTileCompVal(tileIdx, compIdx);
}
for (int r=mrl ; r>=0 ; r--) {
if ( r>=v[1].size() ) {
tmp = ((Integer)v[1].elementAt(v[1].size()-1)).
intValue();
}
else {
tmp = ((Integer)v[1].elementAt(r)).intValue();
}
int yExp = (MathUtil.log2(tmp)<< 4) & 0x00F0;
if ( r>=v[0].size() ) {
tmp = ((Integer)v[0].elementAt(v[0].size()-1)).
intValue();
}
else {
tmp = ((Integer)v[0].elementAt(r)).intValue();
}
int xExp = MathUtil.log2(tmp) & 0x000F;
hbuf.write(yExp|xExp);
}
}
}
/**
* Writes QCD marker segment in main header. QCD is a functional marker
* segment countaining the quantization default used for compressing all
* the components in an image. The values can be overriden for an
* individual component by a QCC marker in either the main or the tile
* header.
* */
protected void writeMainQCD() throws IOException{
float step;
String qType = (String)wp.getQuantizationType().getDefault();
float baseStep = ((Float)wp.getQuantizationStep().getDefault()).floatValue();
int gb = ((Integer)wp.getGuardBits().getDefault()).intValue();
boolean isDerived = qType.equals("derived");
boolean isReversible = qType.equals("reversible");
int mrl = ((Integer)wp.getDecompositionLevel().getDefault()).intValue();
int nt = dwt.getNumTiles();
int nc = dwt.getNumComps();
int tmpI;
int[] tcIdx = new int[2];
String tmpStr;
boolean notFound = true;
for(int t=0; tSOC SIZ COD COC (if
* needed) QCD QCC (if needed) POC (if
* needed)
* */
public void encodeMainHeader() throws IOException {
int i;
// +---------------------------------+
// | SOC marker segment |
// +---------------------------------+
writeSOC();
// +---------------------------------+
// | Image and tile SIZe (SIZ) |
// +---------------------------------+
writeSIZ();
// +-------------------------------+
// | COding style Default (COD) |
// +-------------------------------+
boolean isEresUsed = ((String)wp.getTerminateOnByte().getDefault()).
equals("predict");
writeCOD(true,0);
// +---------------------------------+
// | COding style Component (COC) |
// +---------------------------------+
for (i= 0; i need COC
writeCOC(true,0,i);
}
// +-------------------------------+
// | Quantization Default (QCD) |
// +-------------------------------+
writeMainQCD();
// +-------------------------------+
// | Quantization Component (QCC) |
// +-------------------------------+
// Write needed QCC markers
for(i=0; i1)
writePOC(true, 0);
// +--------------------------+
// | Comment (COM) |
// +--------------------------+
writeCOM();
}
/**
* Write a COM marker segment adding some comments to the codestream.
*
* This marker is currently written in main header and indicates the
* JJ2000 encoder's version that has created the codestream.
* */
private void writeCOM() throws IOException {
// JJ2000 COM marker segment
if(enJJ2KMarkSeg) {
String str = "Created by: JJ2000 version "+JJ2KInfo.version;
int markSegLen; // the marker segment length
// COM marker
hbuf.writeShort(COM);
// Calculate length: Lcom(2) + Rcom (2) + string's length;
markSegLen = 2 + 2 + str.length();
hbuf.writeShort(markSegLen);
// Rcom
hbuf.writeShort(1); // General use (IS 8859-15:1999(Latin) values)
byte[] chars = str.getBytes();
for(int i=0; iMay be used in tile or main header. If used in main header, it
* refers to a ROI of the whole image, regardless of tiling. When used in
* tile header, only the particular tile is affected.
*
* @param tIdx The tile index
*
* @exception IOException If an I/O error occurs while reading from the
* encoder header stream
* */
private void writeRGN(int tIdx) throws IOException {
int i;
int markSegLen; // the marker length
// Write one RGN marker per component
for(i=0;i SOT COD (if
* needed) COC (if needed) QCD (if needed) QCC
* (if needed) RGN (if needed) POC (if needed)
* SOD
*
* @param length The length of the current tile-part.
*
* @param tileIdx Index of the tile to write
* */
public void encodeTilePartHeader(int tileLength,int tileIdx)
throws IOException {
int tmp;
Point numTiles = ralloc.getNumTiles(null);
ralloc.setTile(tileIdx%numTiles.x,tileIdx/numTiles.x);
// +--------------------------+
// | SOT maker segment |
// +--------------------------+
// SOT marker
hbuf.writeByte(SOT>>8);
hbuf.writeByte(SOT);
// Lsot (10 bytes)
hbuf.writeByte(0);
hbuf.writeByte(10);
// Isot
if(tileIdx>65534){
throw new IllegalArgumentException("Trying to write a tile-part "+
"header whose tile index is too"+
" high");
}
hbuf.writeByte(tileIdx>>8);
hbuf.writeByte(tileIdx);
// Psot
tmp = tileLength;
hbuf.writeByte(tmp>>24);
hbuf.writeByte(tmp>>16);
hbuf.writeByte(tmp>>8);
hbuf.writeByte(tmp);
// TPsot
hbuf.writeByte(0); // Only one tile-part currently supported !
// TNsot
hbuf.writeByte(1); // Only one tile-part currently supported !
// +--------------------------+
// | COD maker segment |
// +--------------------------+
boolean isEresUsed = ((String)wp.getMethodForMQTermination().getDefault()).
equals("predict");
boolean isEresUsedInTile = ((String)wp.getMethodForMQTermination().getTileDef(tileIdx)).
equals("predict");
boolean tileCODwritten = false;
if(wp.getFilters().isTileSpecified(tileIdx) ||
wp.getComponentTransformation().isTileSpecified(tileIdx) ||
wp.getDecompositionLevel().isTileSpecified(tileIdx) ||
wp.getBypass().isTileSpecified(tileIdx) ||
wp.getResetMQ().isTileSpecified(tileIdx) ||
wp.getTerminateOnByte().isTileSpecified(tileIdx) ||
wp.getCausalCXInfo().isTileSpecified(tileIdx) ||
wp.getPrecinctPartition().isTileSpecified(tileIdx) ||
wp.getSOP().isTileSpecified(tileIdx) ||
wp.getCodeSegSymbol().isTileSpecified(tileIdx) ||
wp.getProgressionType().isTileSpecified(tileIdx) ||
wp.getEPH().isTileSpecified(tileIdx) ||
wp.getCodeBlockSize().isTileSpecified(tileIdx) ||
( isEresUsed != isEresUsedInTile ) ) {
writeCOD(false,tileIdx);
tileCODwritten = true;
}
// +--------------------------+
// | COC maker segment |
// +--------------------------+
for(int c=0; c1)
writePOC(false,tileIdx);
}
// +--------------------------+
// | SOD maker |
// +--------------------------+
hbuf.writeByte(SOD>>8);
hbuf.writeByte(SOD);
}
}