/*
* CVS identifier:
*
* $Id: HeaderEncoder.java,v 1.43 2001/10/12 09:02:14 grosbois 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.
* */
using System;
using CSJ2K.j2k.quantization.quantizer;
using CSJ2K.j2k.wavelet.analysis;
using CSJ2K.j2k.entropy.encoder;
using CSJ2K.j2k.quantization;
using CSJ2K.j2k.image.input;
using CSJ2K.j2k.roi.encoder;
using CSJ2K.j2k.codestream;
using CSJ2K.j2k.wavelet;
using CSJ2K.j2k.encoder;
using CSJ2K.j2k.entropy;
using CSJ2K.j2k.image;
using CSJ2K.j2k.util;
using CSJ2K.j2k.io;
using CSJ2K.j2k;
namespace CSJ2K.j2k.codestream.writer
{
/// 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.
///
///
///
///
///
///
///
///
///
public class HeaderEncoder
{
/// Returns the parameters that are used in this class and implementing
/// classes. It returns a 2D String array. Each of the 1D arrays is for a
/// different option, and they have 3 elements. The first element is the
/// option name, the second one is the synopsis, the third one is a long
/// description of what the parameter is and the fourth is its default
/// value. The synopsis or description may be 'null', in which case it is
/// assumed that there is no synopsis or description of the option,
/// respectively. Null may be returned if no options are supported.
///
///
/// the options name, their synopsis and their explanation, or null
/// if no options are supported.
///
///
public static System.String[][] ParameterInfo
{
get
{
return pinfo;
}
}
/// Returns the byte-buffer used to store the codestream header.
///
///
/// A byte array countaining codestream header
///
///
virtual protected internal byte[] Buffer
{
get
{
return baos.ToArray();
}
}
/// Returns the length of the header.
///
///
/// The length of the header in bytes
///
///
virtual public int Length
{
get
{
return (int)hbuf.BaseStream.Length;
}
}
/// Returns the number of bytes used in the codestream header's buffer.
///
///
/// Header length in buffer (without any header overhead)
///
///
virtual protected internal int BufferLength
{
get
{
return (int)baos.Length;
}
}
/// The prefix for the header encoder options: 'H'
public const char OPT_PREFIX = 'H';
/// The list of parameters that are accepted for the header encoder
/// module. Options for this modules start with 'H'.
///
//UPGRADE_NOTE: Final was removed from the declaration of 'pinfo'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private static readonly System.String[][] pinfo = new System.String[][]{new System.String[]{"Hjj2000_COM", null, "Writes or not the JJ2000 COM marker in the " + "codestream", "off"}, new System.String[]{"HCOM", "[#[#]]", "Adds COM marker segments in the codestream. Comments must be " + "separated with '#' and are written into distinct maker segments.", null}};
/// 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
private int nComp;
/// Whether or not to write the JJ2000 COM marker segment
private bool enJJ2KMarkSeg = true;
/// Other COM marker segments specified in the command line
private System.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.
///
///
///
///
protected internal System.IO.MemoryStream baos;
/// The DataOutputStream to store header data. This kind of object is
/// useful to write short, int, .... It's constructor takes baos as
/// parameter.
///
///
///
///
///
//UPGRADE_TODO: Class 'java.io.DataOutputStream' was converted to 'System.IO.BinaryWriter' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataOutputStream'"
protected internal System.IO.BinaryWriter hbuf;
/// The image data reader. Source of original data info
protected internal ImgData origSrc;
/// An array specifying, for each component,if the data was signed or not
///
///
protected internal bool[] isOrigSig;
/// Reference to the rate allocator
protected internal PostCompRateAllocator ralloc;
/// Reference to the DWT module
protected internal ForwardWT dwt;
/// Reference to the tiler module
protected internal Tiler tiler;
/// Reference to the ROI module
protected internal ROIScaler roiSc;
/// The encoder specifications
protected internal EncoderSpecs encSpec;
/// Initializes the header writer with the references to the coding chain.
///
///
/// The original image data (before any component mixing,
/// tiling, etc.)
///
///
/// An array specifying for each component if it was
/// originally signed or not.
///
///
/// The discrete wavelet transform module.
///
///
/// The tiler module.
///
///
/// The encoder specifications
///
///
/// The ROI scaler module.
///
///
/// The post compression rate allocator.
///
///
/// ParameterList instance.
///
///
public HeaderEncoder(ImgData origsrc, bool[] isorigsig, ForwardWT dwt, Tiler tiler, EncoderSpecs encSpec, ROIScaler roiSc, PostCompRateAllocator ralloc, ParameterList pl)
{
pl.checkList(OPT_PREFIX, CSJ2K.j2k.util.ParameterList.toNameArray(pinfo));
if (origsrc.NumComps != isorigsig.Length)
{
throw new System.ArgumentException();
}
this.origSrc = origsrc;
this.isOrigSig = isorigsig;
this.dwt = dwt;
this.tiler = tiler;
this.encSpec = encSpec;
this.roiSc = roiSc;
this.ralloc = ralloc;
baos = new System.IO.MemoryStream();
//UPGRADE_TODO: Class 'java.io.DataOutputStream' was converted to 'System.IO.BinaryWriter' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataOutputStream'"
hbuf = new CSJ2K.Util.EndianBinaryWriter(baos, true);
nComp = origsrc.NumComps;
enJJ2KMarkSeg = pl.getBooleanParameter("Hjj2000_COM");
otherCOMMarkSeg = pl.getParameter("HCOM");
}
/// 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 virtual void reset()
{
//UPGRADE_ISSUE: Method 'java.io.ByteArrayOutputStream.reset' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javaioByteArrayOutputStreamreset'"
// CONVERSION PROBLEM?
//baos.reset();
baos.SetLength(0);
//UPGRADE_TODO: Class 'java.io.DataOutputStream' was converted to 'System.IO.BinaryWriter' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioDataOutputStream'"
hbuf = new CSJ2K.Util.EndianBinaryWriter(baos, true); //new System.IO.BinaryWriter(baos);
}
/// Writes the header to the specified BinaryDataOutput.
///
///
/// Where to write the header.
///
///
public virtual void writeTo(BinaryDataOutput out_Renamed)
{
int i, len;
byte[] buf;
buf = Buffer;
len = Length;
for (i = 0; i < len; i++)
{
out_Renamed.writeByte(buf[i]);
}
}
/// Writes the header to the specified OutputStream.
///
///
/// Where to write the header.
///
///
public virtual void writeTo(System.IO.Stream out_Renamed)
{
out_Renamed.Write(Buffer, 0, BufferLength);
}
/// Start Of Codestream marker (SOC) signalling the beginning of a
/// codestream.
///
///
private void writeSOC()
{
hbuf.Write((System.Int16) CSJ2K.j2k.codestream.Markers.SOC);
}
/// Writes SIZ marker segment of the codestream header. It is a fixed
/// information marker segment containing informations about image and tile
/// sizes. It is required in the main header immediately after SOC marker
/// segment.
///
///
private void writeSIZ()
{
int tmp;
// SIZ marker
hbuf.Write((System.Int16) CSJ2K.j2k.codestream.Markers.SIZ);
// Lsiz (Marker length) corresponding to
// Lsiz(2 bytes)+Rsiz(2)+Xsiz(4)+Ysiz(4)+XOsiz(4)+YOsiz(4)+
// XTsiz(4)+YTsiz(4)+XTOsiz(4)+YTOsiz(4)+Csiz(2)+
// (Ssiz(1)+XRsiz(1)+YRsiz(1))*nComp
// markSegLen = 38 + 3*nComp;
int markSegLen = 38 + 3 * nComp;
hbuf.Write((System.Int16) markSegLen);
// Rsiz (codestream capabilities)
hbuf.Write((System.Int16) 0); // JPEG 2000 - Part I
// Xsiz (original image width)
hbuf.Write(tiler.ImgWidth + tiler.ImgULX);
// Ysiz (original image height)
hbuf.Write(tiler.ImgHeight + tiler.ImgULY);
// XOsiz (horizontal offset from the origin of the reference
// grid to the left side of the image area)
hbuf.Write(tiler.ImgULX);
// YOsiz (vertical offset from the origin of the reference
// grid to the top side of the image area)
hbuf.Write(tiler.ImgULY);
// XTsiz (nominal tile width)
hbuf.Write(tiler.NomTileWidth);
// YTsiz (nominal tile height)
hbuf.Write(tiler.NomTileHeight);
Coord torig = tiler.getTilingOrigin(null);
// XTOsiz (Horizontal offset from the origin of the reference
// grid to the left side of the first tile)
hbuf.Write(torig.x);
// YTOsiz (Vertical offset from the origin of the reference
// grid to the top side of the first tile)
hbuf.Write(torig.y);
// Csiz (number of components)
hbuf.Write((System.Int16) nComp);
// Bit-depth and downsampling factors.
for (int c = 0; c < nComp; c++)
{
// Loop on each component
// Ssiz bit-depth before mixing
tmp = origSrc.getNomRangeBits(c) - 1;
tmp |= ((isOrigSig[c]?1:0) << CSJ2K.j2k.codestream.Markers.SSIZ_DEPTH_BITS);
hbuf.Write((System.Byte) tmp);
// XRsiz (component sub-sampling value x-wise)
hbuf.Write((System.Byte) tiler.getCompSubsX(c));
// YRsiz (component sub-sampling value y-wise)
hbuf.Write((System.Byte) tiler.getCompSubsY(c));
} // End loop on each component
}
/// Writes COD marker segment. COD is a functional marker segment
/// containing the code style default (coding style, decomposition,
/// layering) used for compressing all the components in an image.
///
/// The values can be overriden for an individual component by a COC
/// marker in either the main or the tile header.
///
///
/// Flag indicating whether this marker belongs to the main
/// header
///
///
/// Tile index if the marker belongs to a tile-part header
///
///
///
///
///
protected internal virtual void writeCOD(bool mh, int tileIdx)
{
AnWTFilter[][] filt;
bool precinctPartitionUsed;
int tmp;
int mrl = 0, a = 0;
int ppx = 0, ppy = 0;
Progression[] prog;
if (mh)
{
mrl = ((System.Int32) encSpec.dls.getDefault());
// get default precinct size
ppx = encSpec.pss.getPPX(- 1, - 1, mrl);
ppy = encSpec.pss.getPPY(- 1, - 1, mrl);
prog = (Progression[]) (encSpec.pocs.getDefault());
}
else
{
mrl = ((System.Int32) encSpec.dls.getTileDef(tileIdx));
// get precinct size for specified tile
ppx = encSpec.pss.getPPX(tileIdx, - 1, mrl);
ppy = encSpec.pss.getPPY(tileIdx, - 1, mrl);
prog = (Progression[]) (encSpec.pocs.getTileDef(tileIdx));
}
if (ppx != CSJ2K.j2k.codestream.Markers.PRECINCT_PARTITION_DEF_SIZE || ppy != CSJ2K.j2k.codestream.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;
}
// Write COD marker
hbuf.Write((System.Int16) CSJ2K.j2k.codestream.Markers.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.Write((System.Int16) markSegLen);
// Scod (coding style parameter)
tmp = 0;
if (precinctPartitionUsed)
{
tmp = CSJ2K.j2k.codestream.Markers.SCOX_PRECINCT_PARTITION;
}
// Are SOP markers used ?
if (mh)
{
//UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Object.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
if (((System.String) encSpec.sops.getDefault().ToString()).ToUpper().Equals("on".ToUpper()))
{
tmp |= CSJ2K.j2k.codestream.Markers.SCOX_USE_SOP;
}
}
else
{
//UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Object.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
if (((System.String) encSpec.sops.getTileDef(tileIdx).ToString()).ToUpper().Equals("on".ToUpper()))
{
tmp |= CSJ2K.j2k.codestream.Markers.SCOX_USE_SOP;
}
}
// Are EPH markers used ?
if (mh)
{
//UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Object.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
if (((System.String) encSpec.ephs.getDefault().ToString()).ToUpper().Equals("on".ToUpper()))
{
tmp |= CSJ2K.j2k.codestream.Markers.SCOX_USE_EPH;
}
}
else
{
//UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Object.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
if (((System.String) encSpec.ephs.getTileDef(tileIdx).ToString()).ToUpper().Equals("on".ToUpper()))
{
tmp |= CSJ2K.j2k.codestream.Markers.SCOX_USE_EPH;
}
}
if (dwt.CbULX != 0)
tmp |= CSJ2K.j2k.codestream.Markers.SCOX_HOR_CB_PART;
if (dwt.CbULY != 0)
tmp |= CSJ2K.j2k.codestream.Markers.SCOX_VER_CB_PART;
hbuf.Write((System.Byte) tmp);
// SGcod
// Progression order
hbuf.Write((System.Byte) prog[0].type);
// Number of layers
hbuf.Write((System.Int16) ralloc.NumLayers);
// Multiple component transform
// CSsiz (Color transform)
System.String str = null;
if (mh)
{
str = ((System.String) encSpec.cts.getDefault());
}
else
{
str = ((System.String) encSpec.cts.getTileDef(tileIdx));
}
if (str.Equals("none"))
{
hbuf.Write((System.Byte) 0);
}
else
{
hbuf.Write((System.Byte) 1);
}
// SPcod
// Number of decomposition levels
hbuf.Write((System.Byte) mrl);
// Code-block width and height
if (mh)
{
// main header, get default values
tmp = encSpec.cblks.getCBlkWidth(ModuleSpec.SPEC_DEF, - 1, - 1);
hbuf.Write((System.Byte) (MathUtil.log2(tmp) - 2));
tmp = encSpec.cblks.getCBlkHeight(ModuleSpec.SPEC_DEF, - 1, - 1);
hbuf.Write((System.Byte) (MathUtil.log2(tmp) - 2));
}
else
{
// tile header, get tile default values
tmp = encSpec.cblks.getCBlkWidth(ModuleSpec.SPEC_TILE_DEF, tileIdx, - 1);
hbuf.Write((System.Byte) (MathUtil.log2(tmp) - 2));
tmp = encSpec.cblks.getCBlkHeight(ModuleSpec.SPEC_TILE_DEF, tileIdx, - 1);
hbuf.Write((System.Byte) (MathUtil.log2(tmp) - 2));
}
// Style of the code-block coding passes
tmp = 0;
if (mh)
{
// Main header
// Selective arithmetic coding bypass ?
if (((System.String) encSpec.bms.getDefault()).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS;
}
// MQ reset after each coding pass ?
if (((System.String) encSpec.mqrs.getDefault()).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_RESET_MQ;
}
// MQ termination after each arithmetically coded coding pass ?
if (((System.String) encSpec.rts.getDefault()).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS;
}
// Vertically stripe-causal context mode ?
if (((System.String) encSpec.css.getDefault()).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_VERT_STR_CAUSAL;
}
// Predictable termination ?
if (((System.String) encSpec.tts.getDefault()).Equals("predict"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM;
}
// Error resilience segmentation symbol insertion ?
if (((System.String) encSpec.sss.getDefault()).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_SEG_SYMBOLS;
}
}
else
{
// Tile header
// Selective arithmetic coding bypass ?
if (((System.String) encSpec.bms.getTileDef(tileIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS;
}
// MQ reset after each coding pass ?
if (((System.String) encSpec.mqrs.getTileDef(tileIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_RESET_MQ;
}
// MQ termination after each arithmetically coded coding pass ?
if (((System.String) encSpec.rts.getTileDef(tileIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS;
}
// Vertically stripe-causal context mode ?
if (((System.String) encSpec.css.getTileDef(tileIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_VERT_STR_CAUSAL;
}
// Predictable termination ?
if (((System.String) encSpec.tts.getTileDef(tileIdx)).Equals("predict"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM;
}
// Error resilience segmentation symbol insertion ?
if (((System.String) encSpec.sss.getTileDef(tileIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_SEG_SYMBOLS;
}
}
hbuf.Write((System.Byte) tmp);
// Wavelet transform
// Wavelet Filter
if (mh)
{
filt = ((AnWTFilter[][]) encSpec.wfs.getDefault());
hbuf.Write((System.Byte) filt[0][0].FilterType);
}
else
{
filt = ((AnWTFilter[][]) encSpec.wfs.getTileDef(tileIdx));
hbuf.Write((System.Byte) filt[0][0].FilterType);
}
// Precinct partition
if (precinctPartitionUsed)
{
// Write the precinct size for each resolution level + 1
// (resolution 0) if precinct partition is used.
System.Collections.ArrayList[] v = null;
if (mh)
{
v = (System.Collections.ArrayList[]) encSpec.pss.getDefault();
}
else
{
v = (System.Collections.ArrayList[]) encSpec.pss.getTileDef(tileIdx);
}
for (int r = mrl; r >= 0; r--)
{
if (r >= v[1].Count)
{
tmp = ((System.Int32) v[1][v[1].Count - 1]);
}
else
{
tmp = ((System.Int32) v[1][r]);
}
int yExp = (MathUtil.log2(tmp) << 4) & 0x00F0;
if (r >= v[0].Count)
{
tmp = ((System.Int32) v[0][v[0].Count - 1]);
}
else
{
tmp = ((System.Int32) v[0][r]);
}
int xExp = MathUtil.log2(tmp) & 0x000F;
hbuf.Write((System.Byte) (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.
///
///
/// Flag indicating whether the main header is to be written.
///
///
/// Tile index.
///
///
/// index of the component which need use of the COC marker
/// segment.
///
///
///
///
///
protected internal virtual void writeCOC(bool mh, int tileIdx, int compIdx)
{
AnWTFilter[][] filt;
bool precinctPartitionUsed;
int tmp;
int mrl = 0, a = 0;
int ppx = 0, ppy = 0;
Progression[] prog;
if (mh)
{
mrl = ((System.Int32) encSpec.dls.getCompDef(compIdx));
// Get precinct size for specified component
ppx = encSpec.pss.getPPX(- 1, compIdx, mrl);
ppy = encSpec.pss.getPPY(- 1, compIdx, mrl);
prog = (Progression[]) (encSpec.pocs.getCompDef(compIdx));
}
else
{
mrl = ((System.Int32) encSpec.dls.getTileCompVal(tileIdx, compIdx));
// Get precinct size for specified component/tile
ppx = encSpec.pss.getPPX(tileIdx, compIdx, mrl);
ppy = encSpec.pss.getPPY(tileIdx, compIdx, mrl);
prog = (Progression[]) (encSpec.pocs.getTileCompVal(tileIdx, compIdx));
}
if (ppx != CSJ2K.j2k.codestream.Markers.PRECINCT_PARTITION_DEF_SIZE || ppy != CSJ2K.j2k.codestream.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.Write((System.Int16) CSJ2K.j2k.codestream.Markers.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.Write((System.Int16) markSegLen);
// Ccoc
if (nComp < 257)
{
hbuf.Write((System.Byte) compIdx);
}
else
{
hbuf.Write((System.Int16) compIdx);
}
// Scod (coding style parameter)
tmp = 0;
if (precinctPartitionUsed)
{
tmp = CSJ2K.j2k.codestream.Markers.SCOX_PRECINCT_PARTITION;
}
hbuf.Write((System.Byte) tmp);
// SPcoc
// Number of decomposition levels
hbuf.Write((System.Byte) mrl);
// Code-block width and height
if (mh)
{
// main header, get component default values
tmp = encSpec.cblks.getCBlkWidth(ModuleSpec.SPEC_COMP_DEF, - 1, compIdx);
hbuf.Write((System.Byte) (MathUtil.log2(tmp) - 2));
tmp = encSpec.cblks.getCBlkHeight(ModuleSpec.SPEC_COMP_DEF, - 1, compIdx);
hbuf.Write((System.Byte) (MathUtil.log2(tmp) - 2));
}
else
{
// tile header, get tile component values
tmp = encSpec.cblks.getCBlkWidth(ModuleSpec.SPEC_TILE_COMP, tileIdx, compIdx);
hbuf.Write((System.Byte) (MathUtil.log2(tmp) - 2));
tmp = encSpec.cblks.getCBlkHeight(ModuleSpec.SPEC_TILE_COMP, tileIdx, compIdx);
hbuf.Write((System.Byte) (MathUtil.log2(tmp) - 2));
}
// Entropy coding mode options
tmp = 0;
if (mh)
{
// Main header
// Lazy coding mode ?
if (((System.String) encSpec.bms.getCompDef(compIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS;
}
// MQ reset after each coding pass ?
if (((System.String) encSpec.mqrs.getCompDef(compIdx)).ToUpper().Equals("on".ToUpper()))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_RESET_MQ;
}
// MQ termination after each arithmetically coded coding pass ?
if (((System.String) encSpec.rts.getCompDef(compIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS;
}
// Vertically stripe-causal context mode ?
if (((System.String) encSpec.css.getCompDef(compIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_VERT_STR_CAUSAL;
}
// Predictable termination ?
if (((System.String) encSpec.tts.getCompDef(compIdx)).Equals("predict"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM;
}
// Error resilience segmentation symbol insertion ?
if (((System.String) encSpec.sss.getCompDef(compIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_SEG_SYMBOLS;
}
}
else
{
// Tile Header
if (((System.String) encSpec.bms.getTileCompVal(tileIdx, compIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_BYPASS;
}
// MQ reset after each coding pass ?
if (((System.String) encSpec.mqrs.getTileCompVal(tileIdx, compIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_RESET_MQ;
}
// MQ termination after each arithmetically coded coding pass ?
if (((System.String) encSpec.rts.getTileCompVal(tileIdx, compIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_TERM_PASS;
}
// Vertically stripe-causal context mode ?
if (((System.String) encSpec.css.getTileCompVal(tileIdx, compIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_VERT_STR_CAUSAL;
}
// Predictable termination ?
if (((System.String) encSpec.tts.getTileCompVal(tileIdx, compIdx)).Equals("predict"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_PRED_TERM;
}
// Error resilience segmentation symbol insertion ?
if (((System.String) encSpec.sss.getTileCompVal(tileIdx, compIdx)).Equals("on"))
{
tmp |= CSJ2K.j2k.entropy.StdEntropyCoderOptions.OPT_SEG_SYMBOLS;
}
}
hbuf.Write((System.Byte) tmp);
// Wavelet transform
// Wavelet Filter
if (mh)
{
filt = ((AnWTFilter[][]) encSpec.wfs.getCompDef(compIdx));
hbuf.Write((System.Byte) filt[0][0].FilterType);
}
else
{
filt = ((AnWTFilter[][]) encSpec.wfs.getTileCompVal(tileIdx, compIdx));
hbuf.Write((System.Byte) filt[0][0].FilterType);
}
// Precinct partition
if (precinctPartitionUsed)
{
// Write the precinct size for each resolution level + 1
// (resolution 0) if precinct partition is used.
System.Collections.ArrayList[] v = null;
if (mh)
{
v = (System.Collections.ArrayList[]) encSpec.pss.getCompDef(compIdx);
}
else
{
v = (System.Collections.ArrayList[]) encSpec.pss.getTileCompVal(tileIdx, compIdx);
}
for (int r = mrl; r >= 0; r--)
{
if (r >= v[1].Count)
{
tmp = ((System.Int32) v[1][v[1].Count - 1]);
}
else
{
tmp = ((System.Int32) v[1][r]);
}
int yExp = (MathUtil.log2(tmp) << 4) & 0x00F0;
if (r >= v[0].Count)
{
tmp = ((System.Int32) v[0][v[0].Count - 1]);
}
else
{
tmp = ((System.Int32) v[0][r]);
}
int xExp = MathUtil.log2(tmp) & 0x000F;
hbuf.Write((System.Byte) (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 internal virtual void writeMainQCD()
{
int mrl;
int qstyle;
float step;
System.String qType = (System.String) encSpec.qts.getDefault();
//UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Float.floatValue' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
float baseStep = (float) ((System.Single) encSpec.qsss.getDefault());
int gb = ((System.Int32) encSpec.gbs.getDefault());
bool isDerived = qType.Equals("derived");
bool isReversible = qType.Equals("reversible");
mrl = ((System.Int32) encSpec.dls.getDefault());
int nt = dwt.getNumTiles();
int nc = dwt.NumComps;
int tmpI;
int[] tcIdx = new int[2];
System.String tmpStr;
bool notFound = true;
for (int t = 0; t < nt && notFound; t++)
{
for (int c = 0; c < nc && notFound; c++)
{
tmpI = ((System.Int32) encSpec.dls.getTileCompVal(t, c));
tmpStr = ((System.String) encSpec.qts.getTileCompVal(t, c));
if (tmpI == mrl && tmpStr.Equals(qType))
{
tcIdx[0] = t; tcIdx[1] = c;
notFound = false;
}
}
}
if (notFound)
{
throw new System.ApplicationException("Default representative for quantization type " + " and number of decomposition levels not found " + " in main QCD marker segment. " + "You have found a JJ2000 bug.");
}
SubbandAn sb, csb, sbRoot = dwt.getAnSubbandTree(tcIdx[0], tcIdx[1]);
defimgn = dwt.getNomRangeBits(tcIdx[1]);
int nqcd; // Number of quantization step-size to transmit
// Get the quantization style
qstyle = (isReversible)?CSJ2K.j2k.codestream.Markers.SQCX_NO_QUANTIZATION:((isDerived)?CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_DERIVED:CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_EXPOUNDED);
// QCD marker
hbuf.Write((System.Int16) CSJ2K.j2k.codestream.Markers.QCD);
// Compute the number of steps to send
switch (qstyle)
{
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_DERIVED:
nqcd = 1; // Just the LL value
break;
case CSJ2K.j2k.codestream.Markers.SQCX_NO_QUANTIZATION:
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_EXPOUNDED:
// One value per subband
nqcd = 0;
sb = sbRoot;
// Get the subband at first resolution level
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Count total number of subbands
for (int j = 0; j <= mrl; j++)
{
csb = sb;
while (csb != null)
{
nqcd++;
csb = (SubbandAn) csb.nextSubband();
}
// Go up one resolution level
sb = (SubbandAn) sb.NextResLevel;
}
break;
default:
throw new System.ApplicationException("Internal JJ2000 error");
}
// Lqcd (marker segment length (in bytes))
// Lqcd(2 bytes)+Sqcd(1)+ SPqcd (2*Nqcd)
int markSegLen = 3 + ((isReversible)?nqcd:2 * nqcd);
// Rounded to the nearest even value greater or equals
hbuf.Write((System.Int16) markSegLen);
// Sqcd
hbuf.Write((System.Byte) (qstyle + (gb << CSJ2K.j2k.codestream.Markers.SQCX_GB_SHIFT)));
// SPqcd
switch (qstyle)
{
case CSJ2K.j2k.codestream.Markers.SQCX_NO_QUANTIZATION:
sb = sbRoot;
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Output one exponent per subband
for (int j = 0; j <= mrl; j++)
{
csb = sb;
while (csb != null)
{
int tmp = (defimgn + csb.anGainExp);
hbuf.Write((System.Byte) (tmp << CSJ2K.j2k.codestream.Markers.SQCX_EXP_SHIFT));
csb = (SubbandAn) csb.nextSubband();
// Go up one resolution level
}
sb = (SubbandAn) sb.NextResLevel;
}
break;
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_DERIVED:
sb = sbRoot;
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Calculate subband step (normalized to unit
// dynamic range)
step = baseStep / (1 << sb.level);
// Write exponent-mantissa, 16 bits
hbuf.Write((System.Int16) StdQuantizer.convertToExpMantissa(step));
break;
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_EXPOUNDED:
sb = sbRoot;
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Output one step per subband
for (int j = 0; j <= mrl; j++)
{
csb = sb;
while (csb != null)
{
// Calculate subband step (normalized to unit
// dynamic range)
step = baseStep / (csb.l2Norm * (1 << csb.anGainExp));
// Write exponent-mantissa, 16 bits
hbuf.Write((System.Int16) StdQuantizer.convertToExpMantissa(step));
csb = (SubbandAn) csb.nextSubband();
}
// Go up one resolution level
sb = (SubbandAn) sb.NextResLevel;
}
break;
default:
throw new System.ApplicationException("Internal JJ2000 error");
}
}
/// Writes QCC marker segment in main header. It is a functional marker
/// segment countaining the quantization used for compressing the specified
/// component in an image. The values override for the specified component
/// what was defined by a QCC marker in either the main or the tile header.
///
///
/// Index of the component which needs QCC marker segment.
///
///
protected internal virtual void writeMainQCC(int compIdx)
{
int mrl;
int qstyle;
int tIdx = 0;
float step;
SubbandAn sb, sb2;
SubbandAn sbRoot;
int imgnr = dwt.getNomRangeBits(compIdx);
System.String qType = (System.String) encSpec.qts.getCompDef(compIdx);
//UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Float.floatValue' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
float baseStep = (float) ((System.Single) encSpec.qsss.getCompDef(compIdx));
int gb = ((System.Int32) encSpec.gbs.getCompDef(compIdx));
bool isReversible = qType.Equals("reversible");
bool isDerived = qType.Equals("derived");
mrl = ((System.Int32) encSpec.dls.getCompDef(compIdx));
int nt = dwt.getNumTiles();
int nc = dwt.NumComps;
int tmpI;
System.String tmpStr;
bool notFound = true;
for (int t = 0; t < nt && notFound; t++)
{
for (int c = 0; c < nc && notFound; c++)
{
tmpI = ((System.Int32) encSpec.dls.getTileCompVal(t, c));
tmpStr = ((System.String) encSpec.qts.getTileCompVal(t, c));
if (tmpI == mrl && tmpStr.Equals(qType))
{
tIdx = t;
notFound = false;
}
}
}
if (notFound)
{
throw new System.ApplicationException("Default representative for quantization type " + " and number of decomposition levels not found " + " in main QCC (c=" + compIdx + ") marker segment. " + "You have found a JJ2000 bug.");
}
sbRoot = dwt.getAnSubbandTree(tIdx, compIdx);
int nqcc; // Number of quantization step-size to transmit
// Get the quantization style
if (isReversible)
{
qstyle = CSJ2K.j2k.codestream.Markers.SQCX_NO_QUANTIZATION;
}
else if (isDerived)
{
qstyle = CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_DERIVED;
}
else
{
qstyle = CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_EXPOUNDED;
}
// QCC marker
hbuf.Write((System.Int16) CSJ2K.j2k.codestream.Markers.QCC);
// Compute the number of steps to send
switch (qstyle)
{
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_DERIVED:
nqcc = 1; // Just the LL value
break;
case CSJ2K.j2k.codestream.Markers.SQCX_NO_QUANTIZATION:
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_EXPOUNDED:
// One value per subband
nqcc = 0;
sb = sbRoot;
mrl = sb.resLvl;
// Get the subband at first resolution level
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Find root element for LL subband
while (sb.resLvl != 0)
{
sb = sb.subb_LL;
}
// Count total number of subbands
for (int j = 0; j <= mrl; j++)
{
sb2 = sb;
while (sb2 != null)
{
nqcc++;
sb2 = (SubbandAn) sb2.nextSubband();
}
// Go up one resolution level
sb = (SubbandAn) sb.NextResLevel;
}
break;
default:
throw new System.ApplicationException("Internal JJ2000 error");
}
// Lqcc (marker segment length (in bytes))
// Lqcc(2 bytes)+Cqcc(1 or 2)+Sqcc(1)+ SPqcc (2*Nqcc)
int markSegLen = 3 + ((nComp < 257)?1:2) + ((isReversible)?nqcc:2 * nqcc);
hbuf.Write((System.Int16) markSegLen);
// Cqcc
if (nComp < 257)
{
hbuf.Write((System.Byte) compIdx);
}
else
{
hbuf.Write((System.Int16) compIdx);
}
// Sqcc (quantization style)
hbuf.Write((System.Byte) (qstyle + (gb << CSJ2K.j2k.codestream.Markers.SQCX_GB_SHIFT)));
// SPqcc
switch (qstyle)
{
case CSJ2K.j2k.codestream.Markers.SQCX_NO_QUANTIZATION:
// Get resolution level 0 subband
sb = sbRoot;
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Output one exponent per subband
for (int j = 0; j <= mrl; j++)
{
sb2 = sb;
while (sb2 != null)
{
int tmp = (imgnr + sb2.anGainExp);
hbuf.Write((System.Byte) (tmp << CSJ2K.j2k.codestream.Markers.SQCX_EXP_SHIFT));
sb2 = (SubbandAn) sb2.nextSubband();
}
// Go up one resolution level
sb = (SubbandAn) sb.NextResLevel;
}
break;
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_DERIVED:
// Get resolution level 0 subband
sb = sbRoot;
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Calculate subband step (normalized to unit
// dynamic range)
step = baseStep / (1 << sb.level);
// Write exponent-mantissa, 16 bits
hbuf.Write((System.Int16) StdQuantizer.convertToExpMantissa(step));
break;
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_EXPOUNDED:
// Get resolution level 0 subband
sb = sbRoot;
mrl = sb.resLvl;
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
for (int j = 0; j <= mrl; j++)
{
sb2 = sb;
while (sb2 != null)
{
// Calculate subband step (normalized to unit
// dynamic range)
step = baseStep / (sb2.l2Norm * (1 << sb2.anGainExp));
// Write exponent-mantissa, 16 bits
hbuf.Write((System.Int16) StdQuantizer.convertToExpMantissa(step));
sb2 = (SubbandAn) sb2.nextSubband();
}
// Go up one resolution level
sb = (SubbandAn) sb.NextResLevel;
}
break;
default:
throw new System.ApplicationException("Internal JJ2000 error");
}
}
/// Writes QCD marker segment in tile 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.
///
///
/// Tile index
///
///
protected internal virtual void writeTileQCD(int tIdx)
{
int mrl;
int qstyle;
float step;
SubbandAn sb, csb, sbRoot;
System.String qType = (System.String) encSpec.qts.getTileDef(tIdx);
//UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Float.floatValue' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
float baseStep = (float) ((System.Single) encSpec.qsss.getTileDef(tIdx));
mrl = ((System.Int32) encSpec.dls.getTileDef(tIdx));
int nc = dwt.NumComps;
int tmpI;
System.String tmpStr;
bool notFound = true;
int compIdx = 0;
for (int c = 0; c < nc && notFound; c++)
{
tmpI = ((System.Int32) encSpec.dls.getTileCompVal(tIdx, c));
tmpStr = ((System.String) encSpec.qts.getTileCompVal(tIdx, c));
if (tmpI == mrl && tmpStr.Equals(qType))
{
compIdx = c;
notFound = false;
}
}
if (notFound)
{
throw new System.ApplicationException("Default representative for quantization type " + " and number of decomposition levels not found " + " in tile QCD (t=" + tIdx + ") marker segment. " + "You have found a JJ2000 bug.");
}
sbRoot = dwt.getAnSubbandTree(tIdx, compIdx);
deftilenr = dwt.getNomRangeBits(compIdx);
int gb = ((System.Int32) encSpec.gbs.getTileDef(tIdx));
bool isDerived = qType.Equals("derived");
bool isReversible = qType.Equals("reversible");
int nqcd; // Number of quantization step-size to transmit
// Get the quantization style
qstyle = (isReversible)?CSJ2K.j2k.codestream.Markers.SQCX_NO_QUANTIZATION:((isDerived)?CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_DERIVED:CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_EXPOUNDED);
// QCD marker
hbuf.Write((System.Int16) CSJ2K.j2k.codestream.Markers.QCD);
// Compute the number of steps to send
switch (qstyle)
{
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_DERIVED:
nqcd = 1; // Just the LL value
break;
case CSJ2K.j2k.codestream.Markers.SQCX_NO_QUANTIZATION:
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_EXPOUNDED:
// One value per subband
nqcd = 0;
sb = sbRoot;
// Get the subband at first resolution level
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Count total number of subbands
for (int j = 0; j <= mrl; j++)
{
csb = sb;
while (csb != null)
{
nqcd++;
csb = (SubbandAn) csb.nextSubband();
}
// Go up one resolution level
sb = (SubbandAn) sb.NextResLevel;
}
break;
default:
throw new System.ApplicationException("Internal JJ2000 error");
}
// Lqcd (marker segment length (in bytes))
// Lqcd(2 bytes)+Sqcd(1)+ SPqcd (2*Nqcd)
int markSegLen = 3 + ((isReversible)?nqcd:2 * nqcd);
// Rounded to the nearest even value greater or equals
hbuf.Write((System.Int16) markSegLen);
// Sqcd
hbuf.Write((System.Byte) (qstyle + (gb << CSJ2K.j2k.codestream.Markers.SQCX_GB_SHIFT)));
// SPqcd
switch (qstyle)
{
case CSJ2K.j2k.codestream.Markers.SQCX_NO_QUANTIZATION:
sb = sbRoot;
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Output one exponent per subband
for (int j = 0; j <= mrl; j++)
{
csb = sb;
while (csb != null)
{
int tmp = (deftilenr + csb.anGainExp);
hbuf.Write((System.Byte) (tmp << CSJ2K.j2k.codestream.Markers.SQCX_EXP_SHIFT));
csb = (SubbandAn) csb.nextSubband();
// Go up one resolution level
}
sb = (SubbandAn) sb.NextResLevel;
}
break;
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_DERIVED:
sb = sbRoot;
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Calculate subband step (normalized to unit
// dynamic range)
step = baseStep / (1 << sb.level);
// Write exponent-mantissa, 16 bits
hbuf.Write((System.Int16) StdQuantizer.convertToExpMantissa(step));
break;
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_EXPOUNDED:
sb = sbRoot;
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Output one step per subband
for (int j = 0; j <= mrl; j++)
{
csb = sb;
while (csb != null)
{
// Calculate subband step (normalized to unit
// dynamic range)
step = baseStep / (csb.l2Norm * (1 << csb.anGainExp));
// Write exponent-mantissa, 16 bits
hbuf.Write((System.Int16) StdQuantizer.convertToExpMantissa(step));
csb = (SubbandAn) csb.nextSubband();
}
// Go up one resolution level
sb = (SubbandAn) sb.NextResLevel;
}
break;
default:
throw new System.ApplicationException("Internal JJ2000 error");
}
}
/// Writes QCC marker segment in tile header. It is a functional marker
/// segment countaining the quantization used for compressing the specified
/// component in an image. The values override for the specified component
/// what was defined by a QCC marker in either the main or the tile header.
///
///
/// Tile index
///
///
/// Index of the component which needs QCC marker segment.
///
///
protected internal virtual void writeTileQCC(int t, int compIdx)
{
int mrl;
int qstyle;
float step;
SubbandAn sb, sb2;
int nqcc; // Number of quantization step-size to transmit
SubbandAn sbRoot = dwt.getAnSubbandTree(t, compIdx);
int imgnr = dwt.getNomRangeBits(compIdx);
System.String qType = (System.String) encSpec.qts.getTileCompVal(t, compIdx);
//UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Float.floatValue' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
float baseStep = (float) ((System.Single) encSpec.qsss.getTileCompVal(t, compIdx));
int gb = ((System.Int32) encSpec.gbs.getTileCompVal(t, compIdx));
bool isReversible = qType.Equals("reversible");
bool isDerived = qType.Equals("derived");
mrl = ((System.Int32) encSpec.dls.getTileCompVal(t, compIdx));
// Get the quantization style
if (isReversible)
{
qstyle = CSJ2K.j2k.codestream.Markers.SQCX_NO_QUANTIZATION;
}
else if (isDerived)
{
qstyle = CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_DERIVED;
}
else
{
qstyle = CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_EXPOUNDED;
}
// QCC marker
hbuf.Write((System.Int16) CSJ2K.j2k.codestream.Markers.QCC);
// Compute the number of steps to send
switch (qstyle)
{
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_DERIVED:
nqcc = 1; // Just the LL value
break;
case CSJ2K.j2k.codestream.Markers.SQCX_NO_QUANTIZATION:
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_EXPOUNDED:
// One value per subband
nqcc = 0;
sb = sbRoot;
mrl = sb.resLvl;
// Get the subband at first resolution level
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Find root element for LL subband
while (sb.resLvl != 0)
{
sb = sb.subb_LL;
}
// Count total number of subbands
for (int j = 0; j <= mrl; j++)
{
sb2 = sb;
while (sb2 != null)
{
nqcc++;
sb2 = (SubbandAn) sb2.nextSubband();
}
// Go up one resolution level
sb = (SubbandAn) sb.NextResLevel;
}
break;
default:
throw new System.ApplicationException("Internal JJ2000 error");
}
// Lqcc (marker segment length (in bytes))
// Lqcc(2 bytes)+Cqcc(1 or 2)+Sqcc(1)+ SPqcc (2*Nqcc)
int markSegLen = 3 + ((nComp < 257)?1:2) + ((isReversible)?nqcc:2 * nqcc);
hbuf.Write((System.Int16) markSegLen);
// Cqcc
if (nComp < 257)
{
hbuf.Write((System.Byte) compIdx);
}
else
{
hbuf.Write((System.Int16) compIdx);
}
// Sqcc (quantization style)
hbuf.Write((System.Byte) (qstyle + (gb << CSJ2K.j2k.codestream.Markers.SQCX_GB_SHIFT)));
// SPqcc
switch (qstyle)
{
case CSJ2K.j2k.codestream.Markers.SQCX_NO_QUANTIZATION:
// Get resolution level 0 subband
sb = sbRoot;
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Output one exponent per subband
for (int j = 0; j <= mrl; j++)
{
sb2 = sb;
while (sb2 != null)
{
int tmp = (imgnr + sb2.anGainExp);
hbuf.Write((System.Byte) (tmp << CSJ2K.j2k.codestream.Markers.SQCX_EXP_SHIFT));
sb2 = (SubbandAn) sb2.nextSubband();
}
// Go up one resolution level
sb = (SubbandAn) sb.NextResLevel;
}
break;
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_DERIVED:
// Get resolution level 0 subband
sb = sbRoot;
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
// Calculate subband step (normalized to unit
// dynamic range)
step = baseStep / (1 << sb.level);
// Write exponent-mantissa, 16 bits
hbuf.Write((System.Int16) StdQuantizer.convertToExpMantissa(step));
break;
case CSJ2K.j2k.codestream.Markers.SQCX_SCALAR_EXPOUNDED:
// Get resolution level 0 subband
sb = sbRoot;
mrl = sb.resLvl;
sb = (SubbandAn) sb.getSubbandByIdx(0, 0);
for (int j = 0; j <= mrl; j++)
{
sb2 = sb;
while (sb2 != null)
{
// Calculate subband step (normalized to unit
// dynamic range)
step = baseStep / (sb2.l2Norm * (1 << sb2.anGainExp));
// Write exponent-mantissa, 16 bits
hbuf.Write((System.Int16) StdQuantizer.convertToExpMantissa(step));
sb2 = (SubbandAn) sb2.nextSubband();
}
// Go up one resolution level
sb = (SubbandAn) sb.NextResLevel;
}
break;
default:
throw new System.ApplicationException("Internal JJ2000 error");
}
}
/// Writes POC marker segment. POC is a functional marker segment
/// containing the bounds and progression order for any progression order
/// other than default in the codestream.
///
///
/// Flag indicating whether the main header is to be written
///
///
/// Tile index
///
///
protected internal virtual void writePOC(bool mh, int tileIdx)
{
int markSegLen = 0; // Segment marker length
int lenCompField; // Holds the size of any component field as
// this size depends on the number of
//components
Progression[] prog = null; // Holds the progression(s)
int npoc; // Number of progression order changes
// Get the progression order changes, their number and checks
// if it is ok
if (mh)
{
prog = (Progression[]) (encSpec.pocs.getDefault());
}
else
{
prog = (Progression[]) (encSpec.pocs.getTileDef(tileIdx));
}
// Calculate the length of a component field (depends on the number of
// components)
lenCompField = (nComp < 257?1:2);
// POC marker
hbuf.Write((System.Int16) CSJ2K.j2k.codestream.Markers.POC);
// Lpoc (marker segment length (in bytes))
// Basic: Lpoc(2 bytes) + npoc * [ RSpoc(1) + CSpoc(1 or 2) +
// LYEpoc(2) + REpoc(1) + CEpoc(1 or 2) + Ppoc(1) ]
npoc = prog.Length;
markSegLen = 2 + npoc * (1 + lenCompField + 2 + 1 + lenCompField + 1);
hbuf.Write((System.Int16) markSegLen);
// Write each progression order change
for (int i = 0; i < npoc; i++)
{
// RSpoc(i)
hbuf.Write((System.Byte) prog[i].rs);
// CSpoc(i)
if (lenCompField == 2)
{
hbuf.Write((System.Int16) prog[i].cs);
}
else
{
hbuf.Write((System.Byte) prog[i].cs);
}
// LYEpoc(i)
hbuf.Write((System.Int16) prog[i].lye);
// REpoc(i)
hbuf.Write((System.Byte) prog[i].re);
// CEpoc(i)
if (lenCompField == 2)
{
hbuf.Write((System.Int16) prog[i].ce);
}
else
{
hbuf.Write((System.Byte) prog[i].ce);
}
// Ppoc(i)
hbuf.Write((System.Byte) prog[i].type);
}
}
/// Write main header. JJ2000 main header corresponds to the following
/// sequence of marker segments:
///
///
/// - SOC
/// - SIZ
/// - COD
/// - COC (if needed)
/// - QCD
/// - QCC (if needed)
/// - POC (if needed)
///
///
///
public virtual void encodeMainHeader()
{
int i;
// +---------------------------------+
// | SOC marker segment |
// +---------------------------------+
writeSOC();
// +---------------------------------+
// | Image and tile SIZe (SIZ) |
// +---------------------------------+
writeSIZ();
// +-------------------------------+
// | COding style Default (COD) |
// +-------------------------------+
bool isEresUsed = ((System.String) encSpec.tts.getDefault()).Equals("predict");
writeCOD(true, 0);
// +---------------------------------+
// | COding style Component (COC) |
// +---------------------------------+
for (i = 0; i < nComp; i++)
{
bool isEresUsedinComp = ((System.String) encSpec.tts.getCompDef(i)).Equals("predict");
if (encSpec.wfs.isCompSpecified(i) || encSpec.dls.isCompSpecified(i) || encSpec.bms.isCompSpecified(i) || encSpec.mqrs.isCompSpecified(i) || encSpec.rts.isCompSpecified(i) || encSpec.sss.isCompSpecified(i) || encSpec.css.isCompSpecified(i) || encSpec.pss.isCompSpecified(i) || encSpec.cblks.isCompSpecified(i) || (isEresUsed != isEresUsedinComp))
// Some component non-default stuff => need COC
writeCOC(true, 0, i);
}
// +-------------------------------+
// | Quantization Default (QCD) |
// +-------------------------------+
writeMainQCD();
// +-------------------------------+
// | Quantization Component (QCC) |
// +-------------------------------+
// Write needed QCC markers
for (i = 0; i < nComp; i++)
{
if (dwt.getNomRangeBits(i) != defimgn || encSpec.qts.isCompSpecified(i) || encSpec.qsss.isCompSpecified(i) || encSpec.dls.isCompSpecified(i) || encSpec.gbs.isCompSpecified(i))
{
writeMainQCC(i);
}
}
// +--------------------------+
// | POC maker segment |
// +--------------------------+
Progression[] prog = (Progression[]) (encSpec.pocs.getDefault());
if (prog.Length > 1)
writePOC(true, 0);
// +---------------------------+
// | Comments (COM) |
// +---------------------------+
writeCOM();
}
/// Write COM marker segment(s) 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()
{
// JJ2000 COM marker segment
if (enJJ2KMarkSeg)
{
System.String str = "Created by: CSJ2K version " + JJ2KInfo.version;
int markSegLen; // the marker segment length
// COM marker
hbuf.Write((System.Int16) CSJ2K.j2k.codestream.Markers.COM);
// Calculate length: Lcom(2) + Rcom (2) + string's length;
markSegLen = 2 + 2 + str.Length;
hbuf.Write((System.Int16) markSegLen);
// Rcom
hbuf.Write((System.Int16) 1); // General use (IS 8859-15:1999(Latin) values)
byte[] chars = System.Text.ASCIIEncoding.ASCII.GetBytes(str);
for (int i = 0; i < chars.Length; i++)
{
hbuf.Write((byte) chars[i]);
}
}
// other COM marker segments
if (otherCOMMarkSeg != null)
{
SupportClass.Tokenizer stk = new SupportClass.Tokenizer(otherCOMMarkSeg, "#");
while (stk.HasMoreTokens())
{
System.String str = stk.NextToken();
int markSegLen; // the marker segment length
// COM marker
hbuf.Write((System.Int16) CSJ2K.j2k.codestream.Markers.COM);
// Calculate length: Lcom(2) + Rcom (2) + string's length;
markSegLen = 2 + 2 + str.Length;
hbuf.Write((System.Int16) markSegLen);
// Rcom
hbuf.Write((System.Int16) 1); // General use (IS 8859-15:1999(Latin)
// values)
byte[] chars = System.Text.ASCIIEncoding.ASCII.GetBytes(str);
for (int i = 0; i < chars.Length; i++)
{
hbuf.Write((byte) chars[i]);
}
}
}
}
/// Writes the RGN marker segment in the tile header. It describes the
/// scaling value in each tile component
///
/// May 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.
///
///
/// The tile index
///
///
/// If an I/O error occurs while reading from the
/// encoder header stream
///
///
private void writeRGN(int tIdx)
{
int i;
int markSegLen; // the marker length
// Write one RGN marker per component
for (i = 0; i < nComp; i++)
{
// RGN marker
hbuf.Write((System.Int16) CSJ2K.j2k.codestream.Markers.RGN);
// Calculate length (Lrgn)
// Basic: Lrgn (2) + Srgn (1) + SPrgn + one byte
// or two for component number
markSegLen = 4 + ((nComp < 257)?1:2);
hbuf.Write((System.Int16) markSegLen);
// Write component (Crgn)
if (nComp < 257)
{
hbuf.Write((System.Byte) i);
}
else
{
hbuf.Write((System.Int16) i);
}
// Write type of ROI (Srgn)
hbuf.Write((System.Byte) CSJ2K.j2k.codestream.Markers.SRGN_IMPLICIT);
// Write ROI info (SPrgn)
hbuf.Write((System.Byte) ((System.Int32) (encSpec.rois.getTileCompVal(tIdx, i))));
}
}
/// Writes tile-part header. JJ2000 tile-part header corresponds to the
/// following sequence of marker segments:
///
///
/// - SOT
/// - COD (if needed)
/// - COC (if needed)
/// - QCD (if needed)
/// - QCC (if needed)
/// - RGN (if needed)
/// - POC (if needed)
/// - SOD
///
///
///
/// The length of the current tile-part.
///
///
/// Index of the tile to write
///
///
public virtual void encodeTilePartHeader(int tileLength, int tileIdx)
{
int tmp;
Coord numTiles = ralloc.getNumTiles(null);
ralloc.setTile(tileIdx % numTiles.x, tileIdx / numTiles.x);
// +--------------------------+
// | SOT maker segment |
// +--------------------------+
// SOT marker
hbuf.Write((System.Byte) SupportClass.URShift(CSJ2K.j2k.codestream.Markers.SOT, 8));
hbuf.Write((System.Byte) (CSJ2K.j2k.codestream.Markers.SOT & 0x00FF));
// Lsot (10 bytes)
hbuf.Write((System.Byte) 0);
hbuf.Write((System.Byte) 10);
// Isot
if (tileIdx > 65534)
{
throw new System.ArgumentException("Trying to write a tile-part " + "header whose tile index is " + "too high");
}
hbuf.Write((System.Byte) (tileIdx >> 8));
hbuf.Write((System.Byte) tileIdx);
// Psot
tmp = tileLength;
hbuf.Write((System.Byte) (tmp >> 24));
hbuf.Write((System.Byte) (tmp >> 16));
hbuf.Write((System.Byte) (tmp >> 8));
hbuf.Write((System.Byte) tmp);
// TPsot
hbuf.Write((System.Byte) 0); // Only one tile-part currently supported !
// TNsot
hbuf.Write((System.Byte) 1); // Only one tile-part currently supported !
// +--------------------------+
// | COD maker segment |
// +--------------------------+
bool isEresUsed = ((System.String) encSpec.tts.getDefault()).Equals("predict");
bool isEresUsedInTile = ((System.String) encSpec.tts.getTileDef(tileIdx)).Equals("predict");
bool tileCODwritten = false;
if (encSpec.wfs.isTileSpecified(tileIdx) || encSpec.cts.isTileSpecified(tileIdx) || encSpec.dls.isTileSpecified(tileIdx) || encSpec.bms.isTileSpecified(tileIdx) || encSpec.mqrs.isTileSpecified(tileIdx) || encSpec.rts.isTileSpecified(tileIdx) || encSpec.css.isTileSpecified(tileIdx) || encSpec.pss.isTileSpecified(tileIdx) || encSpec.sops.isTileSpecified(tileIdx) || encSpec.sss.isTileSpecified(tileIdx) || encSpec.pocs.isTileSpecified(tileIdx) || encSpec.ephs.isTileSpecified(tileIdx) || encSpec.cblks.isTileSpecified(tileIdx) || (isEresUsed != isEresUsedInTile))
{
writeCOD(false, tileIdx);
tileCODwritten = true;
}
// +--------------------------+
// | COC maker segment |
// +--------------------------+
for (int c = 0; c < nComp; c++)
{
bool isEresUsedInTileComp = ((System.String) encSpec.tts.getTileCompVal(tileIdx, c)).Equals("predict");
if (encSpec.wfs.isTileCompSpecified(tileIdx, c) || encSpec.dls.isTileCompSpecified(tileIdx, c) || encSpec.bms.isTileCompSpecified(tileIdx, c) || encSpec.mqrs.isTileCompSpecified(tileIdx, c) || encSpec.rts.isTileCompSpecified(tileIdx, c) || encSpec.css.isTileCompSpecified(tileIdx, c) || encSpec.pss.isTileCompSpecified(tileIdx, c) || encSpec.sss.isTileCompSpecified(tileIdx, c) || encSpec.cblks.isTileCompSpecified(tileIdx, c) || (isEresUsedInTileComp != isEresUsed))
{
writeCOC(false, tileIdx, c);
}
else if (tileCODwritten)
{
if (encSpec.wfs.isCompSpecified(c) || encSpec.dls.isCompSpecified(c) || encSpec.bms.isCompSpecified(c) || encSpec.mqrs.isCompSpecified(c) || encSpec.rts.isCompSpecified(c) || encSpec.sss.isCompSpecified(c) || encSpec.css.isCompSpecified(c) || encSpec.pss.isCompSpecified(c) || encSpec.cblks.isCompSpecified(c) || (encSpec.tts.isCompSpecified(c) && ((System.String) encSpec.tts.getCompDef(c)).Equals("predict")))
{
writeCOC(false, tileIdx, c);
}
}
}
// +--------------------------+
// | QCD maker segment |
// +--------------------------+
bool tileQCDwritten = false;
if (encSpec.qts.isTileSpecified(tileIdx) || encSpec.qsss.isTileSpecified(tileIdx) || encSpec.dls.isTileSpecified(tileIdx) || encSpec.gbs.isTileSpecified(tileIdx))
{
writeTileQCD(tileIdx);
tileQCDwritten = true;
}
else
{
deftilenr = defimgn;
}
// +--------------------------+
// | QCC maker segment |
// +--------------------------+
for (int c = 0; c < nComp; c++)
{
if (dwt.getNomRangeBits(c) != deftilenr || encSpec.qts.isTileCompSpecified(tileIdx, c) || encSpec.qsss.isTileCompSpecified(tileIdx, c) || encSpec.dls.isTileCompSpecified(tileIdx, c) || encSpec.gbs.isTileCompSpecified(tileIdx, c))
{
writeTileQCC(tileIdx, c);
}
else if (tileQCDwritten)
{
if (encSpec.qts.isCompSpecified(c) || encSpec.qsss.isCompSpecified(c) || encSpec.dls.isCompSpecified(c) || encSpec.gbs.isCompSpecified(c))
{
writeTileQCC(tileIdx, c);
}
}
}
// +--------------------------+
// | RGN maker segment |
// +--------------------------+
if (roiSc.useRoi() && (!roiSc.BlockAligned))
writeRGN(tileIdx);
// +--------------------------+
// | POC maker segment |
// +--------------------------+
Progression[] prog;
if (encSpec.pocs.isTileSpecified(tileIdx))
{
prog = (Progression[]) (encSpec.pocs.getTileDef(tileIdx));
if (prog.Length > 1)
writePOC(false, tileIdx);
}
// +--------------------------+
// | SOD maker |
// +--------------------------+
hbuf.Write((System.Byte) SupportClass.URShift(CSJ2K.j2k.codestream.Markers.SOD, 8));
hbuf.Write((System.Byte) (CSJ2K.j2k.codestream.Markers.SOD & 0x00FF));
}
}
}