2080 lines
67 KiB
C#
2080 lines
67 KiB
C#
/*
|
|
* 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
|
|
{
|
|
|
|
/// <summary> 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.
|
|
///
|
|
/// <p>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:
|
|
/// <ul>
|
|
/// <li>Delimiting : SOC,SOT,SOD,EOC (written in FileCodestreamWriter).</li>
|
|
/// <li>Fixed information: SIZ.</li>
|
|
/// <li>Functional: COD,COC,RGN,QCD,QCC,POC.</li>
|
|
/// <li> In bit-stream: SOP,EPH.</li>
|
|
/// <li> Pointer: TLM,PLM,PLT,PPM,PPT.</li>
|
|
/// <li> Informational: CRG,COM.</li>
|
|
/// </ul></p>
|
|
///
|
|
/// <p>Main Header is written when Encoder instance calls encodeMainHeader
|
|
/// whereas tile-part headers are written when the EBCOTRateAllocator instance
|
|
/// calls encodeTilePartHeader.</p>
|
|
///
|
|
/// </summary>
|
|
/// <seealso cref="Encoder">
|
|
/// </seealso>
|
|
/// <seealso cref="Markers">
|
|
/// </seealso>
|
|
/// <seealso cref="EBCOTRateAllocator">
|
|
///
|
|
/// </seealso>
|
|
public class HeaderEncoder
|
|
{
|
|
/// <summary> 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.
|
|
///
|
|
/// </summary>
|
|
/// <returns> the options name, their synopsis and their explanation, or null
|
|
/// if no options are supported.
|
|
///
|
|
/// </returns>
|
|
public static System.String[][] ParameterInfo
|
|
{
|
|
get
|
|
{
|
|
return pinfo;
|
|
}
|
|
|
|
}
|
|
/// <summary> Returns the byte-buffer used to store the codestream header.
|
|
///
|
|
/// </summary>
|
|
/// <returns> A byte array countaining codestream header
|
|
///
|
|
/// </returns>
|
|
virtual protected internal byte[] Buffer
|
|
{
|
|
get
|
|
{
|
|
return baos.ToArray();
|
|
}
|
|
|
|
}
|
|
/// <summary> Returns the length of the header.
|
|
///
|
|
/// </summary>
|
|
/// <returns> The length of the header in bytes
|
|
///
|
|
/// </returns>
|
|
virtual public int Length
|
|
{
|
|
get
|
|
{
|
|
return (int)hbuf.BaseStream.Length;
|
|
}
|
|
|
|
}
|
|
/// <summary> Returns the number of bytes used in the codestream header's buffer.
|
|
///
|
|
/// </summary>
|
|
/// <returns> Header length in buffer (without any header overhead)
|
|
///
|
|
/// </returns>
|
|
virtual protected internal int BufferLength
|
|
{
|
|
get
|
|
{
|
|
return (int)baos.Length;
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>The prefix for the header encoder options: 'H' </summary>
|
|
public const char OPT_PREFIX = 'H';
|
|
|
|
/// <summary>The list of parameters that are accepted for the header encoder
|
|
/// module. Options for this modules start with 'H'.
|
|
/// </summary>
|
|
//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", "<Comment 1>[#<Comment 2>[#<Comment3...>]]", "Adds COM marker segments in the codestream. Comments must be " + "separated with '#' and are written into distinct maker segments.", null}};
|
|
|
|
/// <summary>Nominal range bit of the component defining default values in QCD for
|
|
/// main header
|
|
/// </summary>
|
|
private int defimgn;
|
|
|
|
/// <summary>Nominal range bit of the component defining default values in QCD for
|
|
/// tile headers
|
|
/// </summary>
|
|
private int deftilenr;
|
|
|
|
/// <summary>The number of components in the image </summary>
|
|
private int nComp;
|
|
|
|
/// <summary>Whether or not to write the JJ2000 COM marker segment </summary>
|
|
private bool enJJ2KMarkSeg = true;
|
|
|
|
/// <summary>Other COM marker segments specified in the command line </summary>
|
|
private System.String otherCOMMarkSeg = null;
|
|
|
|
/// <summary>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.
|
|
///
|
|
/// </summary>
|
|
/// <seealso cref="hbuf">
|
|
/// </seealso>
|
|
protected internal System.IO.MemoryStream baos;
|
|
|
|
/// <summary>The DataOutputStream to store header data. This kind of object is
|
|
/// useful to write short, int, .... It's constructor takes baos as
|
|
/// parameter.
|
|
///
|
|
/// </summary>
|
|
/// <seealso cref="baos">
|
|
///
|
|
/// </seealso>
|
|
//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;
|
|
|
|
/// <summary>The image data reader. Source of original data info </summary>
|
|
protected internal ImgData origSrc;
|
|
|
|
/// <summary>An array specifying, for each component,if the data was signed or not
|
|
///
|
|
/// </summary>
|
|
protected internal bool[] isOrigSig;
|
|
|
|
/// <summary>Reference to the rate allocator </summary>
|
|
protected internal PostCompRateAllocator ralloc;
|
|
|
|
/// <summary>Reference to the DWT module </summary>
|
|
protected internal ForwardWT dwt;
|
|
|
|
/// <summary>Reference to the tiler module </summary>
|
|
protected internal Tiler tiler;
|
|
|
|
/// <summary>Reference to the ROI module </summary>
|
|
protected internal ROIScaler roiSc;
|
|
|
|
/// <summary>The encoder specifications </summary>
|
|
protected internal EncoderSpecs encSpec;
|
|
|
|
/// <summary> Initializes the header writer with the references to the coding chain.
|
|
///
|
|
/// </summary>
|
|
/// <param name="origsrc">The original image data (before any component mixing,
|
|
/// tiling, etc.)
|
|
///
|
|
/// </param>
|
|
/// <param name="isorigsig">An array specifying for each component if it was
|
|
/// originally signed or not.
|
|
///
|
|
/// </param>
|
|
/// <param name="dwt">The discrete wavelet transform module.
|
|
///
|
|
/// </param>
|
|
/// <param name="tiler">The tiler module.
|
|
///
|
|
/// </param>
|
|
/// <param name="encSpec">The encoder specifications
|
|
///
|
|
/// </param>
|
|
/// <param name="roiSc">The ROI scaler module.
|
|
///
|
|
/// </param>
|
|
/// <param name="ralloc">The post compression rate allocator.
|
|
///
|
|
/// </param>
|
|
/// <param name="pl">ParameterList instance.
|
|
///
|
|
/// </param>
|
|
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");
|
|
}
|
|
|
|
/// <summary> 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.
|
|
///
|
|
/// </summary>
|
|
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);
|
|
}
|
|
|
|
/// <summary> Writes the header to the specified BinaryDataOutput.
|
|
///
|
|
/// </summary>
|
|
/// <param name="out">Where to write the header.
|
|
///
|
|
/// </param>
|
|
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]);
|
|
}
|
|
}
|
|
|
|
/// <summary> Writes the header to the specified OutputStream.
|
|
///
|
|
/// </summary>
|
|
/// <param name="out">Where to write the header.
|
|
///
|
|
/// </param>
|
|
public virtual void writeTo(System.IO.Stream out_Renamed)
|
|
{
|
|
out_Renamed.Write(Buffer, 0, BufferLength);
|
|
}
|
|
|
|
/// <summary> Start Of Codestream marker (SOC) signalling the beginning of a
|
|
/// codestream.
|
|
///
|
|
/// </summary>
|
|
private void writeSOC()
|
|
{
|
|
hbuf.Write((System.Int16) CSJ2K.j2k.codestream.Markers.SOC);
|
|
}
|
|
|
|
/// <summary> 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.
|
|
///
|
|
/// </summary>
|
|
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
|
|
}
|
|
|
|
/// <summary> 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.
|
|
///
|
|
/// <p>The values can be overriden for an individual component by a COC
|
|
/// marker in either the main or the tile header.</p>
|
|
///
|
|
/// </summary>
|
|
/// <param name="mh">Flag indicating whether this marker belongs to the main
|
|
/// header
|
|
///
|
|
/// </param>
|
|
/// <param name="tileIdx">Tile index if the marker belongs to a tile-part header
|
|
///
|
|
/// </param>
|
|
/// <seealso cref="writeCOC">
|
|
///
|
|
/// </seealso>
|
|
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.Generic.List<System.Int32>[] v = null;
|
|
if (mh)
|
|
{
|
|
v = (System.Collections.Generic.List<System.Int32>[])encSpec.pss.getDefault();
|
|
}
|
|
else
|
|
{
|
|
v = (System.Collections.Generic.List<System.Int32>[])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));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary> Writes COC marker segment . It is a functional marker containing the
|
|
/// coding style for one component (coding style, decomposition, layering).
|
|
///
|
|
/// <p>Its values overrides any value previously set in COD in the main
|
|
/// header or in the tile header.</p>
|
|
///
|
|
/// </summary>
|
|
/// <param name="mh">Flag indicating whether the main header is to be written.
|
|
///
|
|
/// </param>
|
|
/// <param name="tileIdx">Tile index.
|
|
///
|
|
/// </param>
|
|
/// <param name="compIdx">index of the component which need use of the COC marker
|
|
/// segment.
|
|
///
|
|
/// </param>
|
|
/// <seealso cref="writeCOD">
|
|
///
|
|
/// </seealso>
|
|
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.Generic.List<System.Int32>[] v = null;
|
|
if (mh)
|
|
{
|
|
v = (System.Collections.Generic.List<System.Int32>[])encSpec.pss.getCompDef(compIdx);
|
|
}
|
|
else
|
|
{
|
|
v = (System.Collections.Generic.List<System.Int32>[])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));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary> 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.
|
|
///
|
|
/// </summary>
|
|
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.InvalidOperationException("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.InvalidOperationException("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.InvalidOperationException("Internal JJ2000 error");
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary> 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.
|
|
///
|
|
/// </summary>
|
|
/// <param name="compIdx">Index of the component which needs QCC marker segment.
|
|
///
|
|
/// </param>
|
|
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.InvalidOperationException("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.InvalidOperationException("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.InvalidOperationException("Internal JJ2000 error");
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary> 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.
|
|
///
|
|
/// </summary>
|
|
/// <param name="tIdx">Tile index
|
|
///
|
|
/// </param>
|
|
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.InvalidOperationException("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.InvalidOperationException("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.InvalidOperationException("Internal JJ2000 error");
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary> 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.
|
|
///
|
|
/// </summary>
|
|
/// <param name="t">Tile index
|
|
///
|
|
/// </param>
|
|
/// <param name="compIdx">Index of the component which needs QCC marker segment.
|
|
///
|
|
/// </param>
|
|
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.InvalidOperationException("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.InvalidOperationException("Internal JJ2000 error");
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary> 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.
|
|
///
|
|
/// </summary>
|
|
/// <param name="mh">Flag indicating whether the main header is to be written
|
|
///
|
|
/// </param>
|
|
/// <param name="tileIdx">Tile index
|
|
///
|
|
/// </param>
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary> Write main header. JJ2000 main header corresponds to the following
|
|
/// sequence of marker segments:
|
|
///
|
|
/// <ol>
|
|
/// <li>SOC</li>
|
|
/// <li>SIZ</li>
|
|
/// <li>COD</li>
|
|
/// <li>COC (if needed)</li>
|
|
/// <li>QCD</li>
|
|
/// <li>QCC (if needed)</li>
|
|
/// <li>POC (if needed)</li>
|
|
/// </ol>
|
|
///
|
|
/// </summary>
|
|
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();
|
|
}
|
|
|
|
/// <summary> Write COM marker segment(s) to the codestream.
|
|
///
|
|
/// <p>This marker is currently written in main header and indicates the
|
|
/// JJ2000 encoder's version that has created the codestream.</p>
|
|
///
|
|
/// </summary>
|
|
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.Encoding.UTF8.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.Encoding.UTF8.GetBytes(str);
|
|
for (int i = 0; i < chars.Length; i++)
|
|
{
|
|
hbuf.Write((byte) chars[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary> Writes the RGN marker segment in the tile header. It describes the
|
|
/// scaling value in each tile component
|
|
///
|
|
/// <p>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.</p>
|
|
///
|
|
/// </summary>
|
|
/// <param name="tIdx">The tile index
|
|
///
|
|
/// </param>
|
|
/// <exception cref="IOException">If an I/O error occurs while reading from the
|
|
/// encoder header stream
|
|
///
|
|
/// </exception>
|
|
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))));
|
|
}
|
|
}
|
|
/// <summary> Writes tile-part header. JJ2000 tile-part header corresponds to the
|
|
/// following sequence of marker segments:
|
|
///
|
|
/// <ol>
|
|
/// <li>SOT</li>
|
|
/// <li>COD (if needed)</li>
|
|
/// <li>COC (if needed)</li>
|
|
/// <li>QCD (if needed)</li>
|
|
/// <li>QCC (if needed)</li>
|
|
/// <li>RGN (if needed)</li>
|
|
/// <li>POC (if needed)</li>
|
|
/// <li>SOD</li>
|
|
/// </ol>
|
|
///
|
|
/// </summary>
|
|
/// <param name="length">The length of the current tile-part.
|
|
///
|
|
/// </param>
|
|
/// <param name="tileIdx">Index of the tile to write
|
|
///
|
|
/// </param>
|
|
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));
|
|
}
|
|
}
|
|
} |