using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
namespace Wsq2Bmp
{
public class WsqDecoder
{
public Bitmap Decode(byte[] data) {
Token token = new Token(data);
token.initialize();
/* Read the SOI marker. */
getCMarkerWSQ(token, WsqHelper.SOI_WSQ);
/* Read in supporting tables up to the SOF marker. */
int marker = getCMarkerWSQ(token, WsqHelper.TBLS_N_SOF);
while (marker != WsqHelper.SOF_WSQ) {
getCTableWSQ(token, marker);
marker = getCMarkerWSQ(token, WsqHelper.TBLS_N_SOF);
}
/* Read in the Frame Header. */
HeaderFrm frmHeaderWSQ = getCFrameHeaderWSQ(token);
int width = frmHeaderWSQ.width;
int height = frmHeaderWSQ.height;
int ppi = getCPpiWSQ();
/* Build WSQ decomposition trees. */
buildWSQTrees(token, width, height);
/* Decode the Huffman encoded buffer blocks. */
int[] qdata = huffmanDecodeDataMem(token, width * height);
/* Decode the quantize wavelet subband buffer. */
float[] fdata = unquantize(token, qdata, width, height);
/* Done with quantized wavelet subband buffer. */
//noinspection UnusedAssignment
qdata = null;
wsqReconstruct(token, fdata, width, height);
/* Convert floating point pixels to unsigned char pixels. */
byte[] cdata = convertImage2Byte(fdata, width, height, frmHeaderWSQ.mShift, frmHeaderWSQ.rScale);
//noinspection UnusedAssignment
fdata = null;
//noinspection UnusedAssignment
token = null;
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
int pix = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
bmp.SetPixel(j, i, Color.FromArgb(cdata[pix], cdata[pix], cdata[pix]));
pix++;
}
}
return bmp; //new Bitmap(cdata, width, height, ppi, 8, 1);
}
private int intSign(int power) { /* "sign" power */
int cnt; /* counter */
int num = -1; /* sign return value */
if (power == 0)
return 1;
for (cnt = 1; cnt < power; cnt++)
num *= -1;
return num;
}
private int getCMarkerWSQ(Token token, int type) {
if (token.pointer >= token.buffer.Length) {
throw new SystemException("Error, Invalid pointer : " + token.pointer);
}
int marker = token.readShort();
switch (type) {
case WsqHelper.SOI_WSQ:
if (marker != WsqHelper.SOI_WSQ) {
throw new SystemException("ERROR : getCMarkerWSQ : No SOI marker : " + marker);
}
return marker;
case WsqHelper.TBLS_N_SOF:
if (marker != WsqHelper.DTT_WSQ
&& marker != WsqHelper.DQT_WSQ
&& marker != WsqHelper.DHT_WSQ
&& marker != WsqHelper.SOF_WSQ
&& marker != WsqHelper.COM_WSQ) {
throw new SystemException("ERROR : getc_marker_wsq : No SOF, Table, or comment markers : " + marker);
}
return marker;
case WsqHelper.TBLS_N_SOB:
if (marker != WsqHelper.DTT_WSQ
&& marker != WsqHelper.DQT_WSQ
&& marker != WsqHelper.DHT_WSQ
&& marker != WsqHelper.SOB_WSQ
&& marker != WsqHelper.COM_WSQ) {
throw new SystemException("ERROR : getc_marker_wsq : No SOB, Table, or comment markers : " +
marker);
}
return marker;
case WsqHelper.ANY_WSQ:
if ((marker & 0xff00) != 0xff00) {
throw new SystemException("ERROR : getc_marker_wsq : no marker found : " + marker);
}
/* Added by MDG on 03-07-05 */
if ((marker < WsqHelper.SOI_WSQ) || (marker > WsqHelper.COM_WSQ)) {
throw new SystemException("ERROR : getc_marker_wsq : not a valid marker : " + marker);
}
return marker;
default:
throw new SystemException("ERROR : getc_marker_wsq : Invalid marker : " + marker);
}
}
private void getCTableWSQ(Token token, int marker) {
switch (marker) {
case WsqHelper.DTT_WSQ:
getCTransformTable(token);
return;
case WsqHelper.DQT_WSQ:
getCQuantizationTable(token);
return;
case WsqHelper.DHT_WSQ:
getCHuffmanTableWSQ(token);
return;
case WsqHelper.COM_WSQ:
//shams: i don't use return value
getCComment(token);
return;
default:
throw new SystemException("ERROR: getCTableWSQ : Invalid table defined : " + marker);
}
}
private string getCComment(Token token) {
int size = token.readShort() - 2;
byte[] t = token.readBytes(size);
return ASCIIEncoding.ASCII.GetString(t, 0, t.Length);
}
private void getCTransformTable(Token token) {
// read header Size;
token.readShort();
token.tableDTT.hisz = token.readByte();
token.tableDTT.losz = token.readByte();
token.tableDTT.hifilt = new float[token.tableDTT.hisz];
token.tableDTT.lofilt = new float[token.tableDTT.losz];
int aSize;
if (token.tableDTT.hisz % 2 != 0) {
aSize = (token.tableDTT.hisz + 1) / 2;
} else {
aSize = token.tableDTT.hisz / 2;
}
float[] aLofilt = new float[aSize];
aSize--;
for (int cnt = 0; cnt <= aSize; cnt++) {
int sign = token.readByte();
int scale = token.readByte();
long shrtDat = token.readInt();
aLofilt[cnt] = (float) shrtDat;
while (scale > 0) {
aLofilt[cnt] /= 10.0F;
scale--;
}
if (sign != 0) {
aLofilt[cnt] *= -1.0F;
}
if (token.tableDTT.hisz % 2 != 0) {
token.tableDTT.hifilt[cnt + aSize] = intSign(cnt) * aLofilt[cnt];
if (cnt > 0) {
token.tableDTT.hifilt[aSize - cnt] = token.tableDTT.hifilt[cnt + aSize];
}
} else {
token.tableDTT.hifilt[cnt + aSize + 1] = intSign(cnt) * aLofilt[cnt];
token.tableDTT.hifilt[aSize - cnt] = -1 * token.tableDTT.hifilt[cnt + aSize + 1];
}
}
if (token.tableDTT.losz % 2 != 0) {
aSize = (token.tableDTT.losz + 1) / 2;
} else {
aSize = token.tableDTT.losz / 2;
}
float[] aHifilt = new float[aSize];
aSize--;
for (int cnt = 0; cnt <= aSize; cnt++) {
int sign = token.readByte();
int scale = token.readByte();
long shrtDat = token.readInt();
aHifilt[cnt] = (float) shrtDat;
while (scale > 0) {
aHifilt[cnt] /= 10.0F;
scale--;
}
if (sign != 0) {
aHifilt[cnt] *= -1.0F;
}
if (token.tableDTT.losz % 2 != 0) {
token.tableDTT.lofilt[cnt + aSize] = intSign(cnt) * aHifilt[cnt];
if (cnt > 0) {
token.tableDTT.lofilt[aSize - cnt] = token.tableDTT.lofilt[cnt + aSize];
}
} else {
token.tableDTT.lofilt[cnt + aSize + 1] = intSign(cnt + 1) * aHifilt[cnt];
token.tableDTT.lofilt[aSize - cnt] = token.tableDTT.lofilt[cnt + aSize + 1];
}
}
token.tableDTT.lodef = 1;
token.tableDTT.hidef = 1;
}
public void getCQuantizationTable(Token token) {
token.readShort(); /* header size */
int scale = token.readByte(); /* scaling parameter */
int shrtDat = token.readShort(); /* counter and temp short buffer */
token.tableDQT.binCenter = (float) shrtDat;
while (scale > 0) {
token.tableDQT.binCenter /= 10.0F;
scale--;
}
for (int cnt = 0; cnt < Table_DQT.MAX_SUBBANDS; cnt++) {
scale = token.readByte();
shrtDat = token.readShort();
token.tableDQT.qBin[cnt] = (float) shrtDat;
while (scale > 0) {
token.tableDQT.qBin[cnt] /= 10.0F;
scale--;
}
scale = token.readByte();
shrtDat = token.readShort();
token.tableDQT.zBin[cnt] = (float) shrtDat;
while (scale > 0) {
token.tableDQT.zBin[cnt] /= 10.0F;
scale--;
}
}
token.tableDQT.dqtDef = 1;
}
public void getCHuffmanTableWSQ(Token token) {
/* First time, read table len. */
HuffmanTable firstHuffmanTable = getCHuffmanTable(token, WsqHelper.MAX_HUFFCOUNTS_WSQ, 0, true);
/* Store table into global structure list. */
int tableId = firstHuffmanTable.tableId;
token.tableDHT[tableId].huffbits = (int[]) firstHuffmanTable.huffbits.Clone();
token.tableDHT[tableId].huffvalues = (int[]) firstHuffmanTable.huffvalues.Clone();
token.tableDHT[tableId].tabdef = 1;
int bytesLeft = firstHuffmanTable.bytesLeft;
while (bytesLeft != 0) {
/* Read next table without rading table len. */
HuffmanTable huffmantable = getCHuffmanTable(token, WsqHelper.MAX_HUFFCOUNTS_WSQ, bytesLeft, false);
/* If table is already defined ... */
tableId = huffmantable.tableId;
if (token.tableDHT[tableId].tabdef != 0) {
throw new SystemException("ERROR : getCHuffmanTableWSQ : huffman table already defined.");
}
/* Store table into global structure list. */
token.tableDHT[tableId].huffbits = (int[]) huffmantable.huffbits.Clone();
token.tableDHT[tableId].huffvalues = (int[]) huffmantable.huffvalues.Clone();
token.tableDHT[tableId].tabdef = 1;
bytesLeft = huffmantable.bytesLeft;
}
}
private HuffmanTable getCHuffmanTable(Token token, int maxHuffcounts, int bytesLeft, bool readTableLen) {
HuffmanTable huffmanTable = new HuffmanTable();
/* table_len */
if (readTableLen) {
huffmanTable.tableLen = token.readShort();
huffmanTable.bytesLeft = huffmanTable.tableLen - 2;
bytesLeft = huffmanTable.bytesLeft;
} else {
huffmanTable.bytesLeft = bytesLeft;
}
/* If no bytes left ... */
if (bytesLeft <= 0) {
throw new SystemException("ERROR : getCHuffmanTable : no huffman table bytes remaining");
}
/* Table ID */
huffmanTable.tableId = token.readByte();
huffmanTable.bytesLeft--;
huffmanTable.huffbits = new int[WsqHelper.MAX_HUFFBITS];
int numHufvals = 0;
/* L1 ... L16 */
for (int i = 0; i < WsqHelper.MAX_HUFFBITS; i++) {
huffmanTable.huffbits[i] = token.readByte();
numHufvals += huffmanTable.huffbits[i];
}
huffmanTable.bytesLeft -= WsqHelper.MAX_HUFFBITS;
if (numHufvals > maxHuffcounts + 1) {
throw new SystemException("ERROR : getCHuffmanTable : numHufvals is larger than MAX_HUFFCOUNTS");
}
/* Could allocate only the amount needed ... then we wouldn't */
/* need to pass MAX_HUFFCOUNTS. */
huffmanTable.huffvalues = new int[maxHuffcounts + 1];
/* V1,1 ... V16,16 */
for (int i = 0; i < numHufvals; i++) {
huffmanTable.huffvalues[i] = token.readByte();
}
huffmanTable.bytesLeft -= numHufvals;
return huffmanTable;
}
private HeaderFrm getCFrameHeaderWSQ(Token token) {
HeaderFrm headerFrm = new HeaderFrm();
//noinspection UnusedDeclaration
int hdrSize = token.readShort(); /* header size */
headerFrm.black = token.readByte();
headerFrm.white = token.readByte();
headerFrm.height = token.readShort();
headerFrm.width = token.readShort();
int scale = token.readByte(); /* exponent scaling parameter */
int shrtDat = token.readShort(); /* buffer pointer */
headerFrm.mShift = (float) shrtDat;
while (scale > 0) {
headerFrm.mShift /= 10.0F;
scale--;
}
scale = token.readByte();
shrtDat = token.readShort();
headerFrm.rScale = (float) shrtDat;
while (scale > 0) {
headerFrm.rScale /= 10.0F;
scale--;
}
headerFrm.wsqEncoder = token.readByte();
headerFrm.software = token.readShort();
return headerFrm;
}
private int getCPpiWSQ() {
return -1;
}
private void buildWSQTrees(Token token, int width, int height) {
/* Build a W-TREE structure for the image. */
buildWTree(token, WsqHelper.W_TREELEN, width, height);
/* Build a Q-TREE structure for the image. */
buildQTree(token, WsqHelper.Q_TREELEN);
}
private void buildWTree(Token token, int wtreelen, int width, int height) {
int lenx, lenx2, leny, leny2; /* starting lengths of sections of
the image being split into subbands */
token.wtree = new WavletTree[wtreelen];
for (int i = 0; i < wtreelen; i++) {
token.wtree[i] = new WavletTree();
token.wtree[i].invrw = 0;
token.wtree[i].invcl = 0;
}
token.wtree[2].invrw = 1;
token.wtree[4].invrw = 1;
token.wtree[7].invrw = 1;
token.wtree[9].invrw = 1;
token.wtree[11].invrw = 1;
token.wtree[13].invrw = 1;
token.wtree[16].invrw = 1;
token.wtree[18].invrw = 1;
token.wtree[3].invcl = 1;
token.wtree[5].invcl = 1;
token.wtree[8].invcl = 1;
token.wtree[9].invcl = 1;
token.wtree[12].invcl = 1;
token.wtree[13].invcl = 1;
token.wtree[17].invcl = 1;
token.wtree[18].invcl = 1;
wtree4(token, 0, 1, width, height, 0, 0, 1);
if ((token.wtree[1].lenx % 2) == 0) {
lenx = token.wtree[1].lenx / 2;
lenx2 = lenx;
} else {
lenx = (token.wtree[1].lenx + 1) / 2;
lenx2 = lenx - 1;
}
if ((token.wtree[1].leny % 2) == 0) {
leny = token.wtree[1].leny / 2;
leny2 = leny;
} else {
leny = (token.wtree[1].leny + 1) / 2;
leny2 = leny - 1;
}
wtree4(token, 4, 6, lenx2, leny, lenx, 0, 0);
wtree4(token, 5, 10, lenx, leny2, 0, leny, 0);
wtree4(token, 14, 15, lenx, leny, 0, 0, 0);
token.wtree[19].x = 0;
token.wtree[19].y = 0;
if ((token.wtree[15].lenx % 2) == 0)
token.wtree[19].lenx = token.wtree[15].lenx / 2;
else
token.wtree[19].lenx = (token.wtree[15].lenx + 1) / 2;
if ((token.wtree[15].leny % 2) == 0)
token.wtree[19].leny = token.wtree[15].leny / 2;
else
token.wtree[19].leny = (token.wtree[15].leny + 1) / 2;
}
private void wtree4(Token token, int start1, int start2, int lenx, int leny, int x, int y, int stop1) {
int evenx, eveny; /* Check length of subband for even or odd */
int p1, p2; /* w_tree locations for storing subband sizes and locations */
p1 = start1;
p2 = start2;
evenx = lenx % 2;
eveny = leny % 2;
token.wtree[p1].x = x;
token.wtree[p1].y = y;
token.wtree[p1].lenx = lenx;
token.wtree[p1].leny = leny;
token.wtree[p2].x = x;
token.wtree[p2 + 2].x = x;
token.wtree[p2].y = y;
token.wtree[p2 + 1].y = y;
if (evenx == 0) {
token.wtree[p2].lenx = lenx / 2;
token.wtree[p2 + 1].lenx = token.wtree[p2].lenx;
} else {
if (p1 == 4) {
token.wtree[p2].lenx = (lenx - 1) / 2;
token.wtree[p2 + 1].lenx = token.wtree[p2].lenx + 1;
} else {
token.wtree[p2].lenx = (lenx + 1) / 2;
token.wtree[p2 + 1].lenx = token.wtree[p2].lenx - 1;
}
}
token.wtree[p2 + 1].x = token.wtree[p2].lenx + x;
if (stop1 == 0) {
token.wtree[p2 + 3].lenx = token.wtree[p2 + 1].lenx;
token.wtree[p2 + 3].x = token.wtree[p2 + 1].x;
}
token.wtree[p2 + 2].lenx = token.wtree[p2].lenx;
if (eveny == 0) {
token.wtree[p2].leny = leny / 2;
token.wtree[p2 + 2].leny = token.wtree[p2].leny;
} else {
if (p1 == 5) {
token.wtree[p2].leny = (leny - 1) / 2;
token.wtree[p2 + 2].leny = token.wtree[p2].leny + 1;
} else {
token.wtree[p2].leny = (leny + 1) / 2;
token.wtree[p2 + 2].leny = token.wtree[p2].leny - 1;
}
}
token.wtree[p2 + 2].y = token.wtree[p2].leny + y;
if (stop1 == 0) {
token.wtree[p2 + 3].leny = token.wtree[p2 + 2].leny;
token.wtree[p2 + 3].y = token.wtree[p2 + 2].y;
}
token.wtree[p2 + 1].leny = token.wtree[p2].leny;
}
private void buildQTree(Token token, int qtreelen) {
token.qtree = new QuantTree[qtreelen];
for (int i = 0; i < token.qtree.Length; i++) {
token.qtree[i] = new QuantTree();
}
qtree16(token, 3, token.wtree[14].lenx, token.wtree[14].leny, token.wtree[14].x, token.wtree[14].y, 0, 0);
qtree16(token, 19, token.wtree[4].lenx, token.wtree[4].leny, token.wtree[4].x, token.wtree[4].y, 0, 1);
qtree16(token, 48, token.wtree[0].lenx, token.wtree[0].leny, token.wtree[0].x, token.wtree[0].y, 0, 0);
qtree16(token, 35, token.wtree[5].lenx, token.wtree[5].leny, token.wtree[5].x, token.wtree[5].y, 1, 0);
qtree4(token, 0, token.wtree[19].lenx, token.wtree[19].leny, token.wtree[19].x, token.wtree[19].y);
}
private void qtree16(Token token, int start, int lenx, int leny, int x, int y, int rw, int cl) {
int tempx, temp2x; /* temporary x values */
int tempy, temp2y; /* temporary y values */
int evenx, eveny; /* Check length of subband for even or odd */
int p; /* indicates subband information being stored */
p = start;
evenx = lenx % 2;
eveny = leny % 2;
if (evenx == 0) {
tempx = lenx / 2;
temp2x = tempx;
} else {
if (cl != 0) {
temp2x = (lenx + 1) / 2;
tempx = temp2x - 1;
} else {
tempx = (lenx + 1) / 2;
temp2x = tempx - 1;
}
}
if (eveny == 0) {
tempy = leny / 2;
temp2y = tempy;
} else {
if (rw != 0) {
temp2y = (leny + 1) / 2;
tempy = temp2y - 1;
} else {
tempy = (leny + 1) / 2;
temp2y = tempy - 1;
}
}
evenx = tempx % 2;
eveny = tempy % 2;
token.qtree[p].x = x;
token.qtree[p + 2].x = x;
token.qtree[p].y = y;
token.qtree[p + 1].y = y;
if (evenx == 0) {
token.qtree[p].lenx = tempx / 2;
token.qtree[p + 1].lenx = token.qtree[p].lenx;
token.qtree[p + 2].lenx = token.qtree[p].lenx;
token.qtree[p + 3].lenx = token.qtree[p].lenx;
} else {
token.qtree[p].lenx = (tempx + 1) / 2;
token.qtree[p + 1].lenx = token.qtree[p].lenx - 1;
token.qtree[p + 2].lenx = token.qtree[p].lenx;
token.qtree[p + 3].lenx = token.qtree[p + 1].lenx;
}
token.qtree[p + 1].x = x + token.qtree[p].lenx;
token.qtree[p + 3].x = token.qtree[p + 1].x;
if (eveny == 0) {
token.qtree[p].leny = tempy / 2;
token.qtree[p + 1].leny = token.qtree[p].leny;
token.qtree[p + 2].leny = token.qtree[p].leny;
token.qtree[p + 3].leny = token.qtree[p].leny;
} else {
token.qtree[p].leny = (tempy + 1) / 2;
token.qtree[p + 1].leny = token.qtree[p].leny;
token.qtree[p + 2].leny = token.qtree[p].leny - 1;
token.qtree[p + 3].leny = token.qtree[p + 2].leny;
}
token.qtree[p + 2].y = y + token.qtree[p].leny;
token.qtree[p + 3].y = token.qtree[p + 2].y;
evenx = temp2x % 2;
token.qtree[p + 4].x = x + tempx;
token.qtree[p + 6].x = token.qtree[p + 4].x;
token.qtree[p + 4].y = y;
token.qtree[p + 5].y = y;
token.qtree[p + 6].y = token.qtree[p + 2].y;
token.qtree[p + 7].y = token.qtree[p + 2].y;
token.qtree[p + 4].leny = token.qtree[p].leny;
token.qtree[p + 5].leny = token.qtree[p].leny;
token.qtree[p + 6].leny = token.qtree[p + 2].leny;
token.qtree[p + 7].leny = token.qtree[p + 2].leny;
if (evenx == 0) {
token.qtree[p + 4].lenx = temp2x / 2;
token.qtree[p + 5].lenx = token.qtree[p + 4].lenx;
token.qtree[p + 6].lenx = token.qtree[p + 4].lenx;
token.qtree[p + 7].lenx = token.qtree[p + 4].lenx;
} else {
token.qtree[p + 5].lenx = (temp2x + 1) / 2;
token.qtree[p + 4].lenx = token.qtree[p + 5].lenx - 1;
token.qtree[p + 6].lenx = token.qtree[p + 4].lenx;
token.qtree[p + 7].lenx = token.qtree[p + 5].lenx;
}
token.qtree[p + 5].x = token.qtree[p + 4].x + token.qtree[p + 4].lenx;
token.qtree[p + 7].x = token.qtree[p + 5].x;
eveny = temp2y % 2;
token.qtree[p + 8].x = x;
token.qtree[p + 9].x = token.qtree[p + 1].x;
token.qtree[p + 10].x = x;
token.qtree[p + 11].x = token.qtree[p + 1].x;
token.qtree[p + 8].y = y + tempy;
token.qtree[p + 9].y = token.qtree[p + 8].y;
token.qtree[p + 8].lenx = token.qtree[p].lenx;
token.qtree[p + 9].lenx = token.qtree[p + 1].lenx;
token.qtree[p + 10].lenx = token.qtree[p].lenx;
token.qtree[p + 11].lenx = token.qtree[p + 1].lenx;
if (eveny == 0) {
token.qtree[p + 8].leny = temp2y / 2;
token.qtree[p + 9].leny = token.qtree[p + 8].leny;
token.qtree[p + 10].leny = token.qtree[p + 8].leny;
token.qtree[p + 11].leny = token.qtree[p + 8].leny;
} else {
token.qtree[p + 10].leny = (temp2y + 1) / 2;
token.qtree[p + 11].leny = token.qtree[p + 10].leny;
token.qtree[p + 8].leny = token.qtree[p + 10].leny - 1;
token.qtree[p + 9].leny = token.qtree[p + 8].leny;
}
token.qtree[p + 10].y = token.qtree[p + 8].y + token.qtree[p + 8].leny;
token.qtree[p + 11].y = token.qtree[p + 10].y;
token.qtree[p + 12].x = token.qtree[p + 4].x;
token.qtree[p + 13].x = token.qtree[p + 5].x;
token.qtree[p + 14].x = token.qtree[p + 4].x;
token.qtree[p + 15].x = token.qtree[p + 5].x;
token.qtree[p + 12].y = token.qtree[p + 8].y;
token.qtree[p + 13].y = token.qtree[p + 8].y;
token.qtree[p + 14].y = token.qtree[p + 10].y;
token.qtree[p + 15].y = token.qtree[p + 10].y;
token.qtree[p + 12].lenx = token.qtree[p + 4].lenx;
token.qtree[p + 13].lenx = token.qtree[p + 5].lenx;
token.qtree[p + 14].lenx = token.qtree[p + 4].lenx;
token.qtree[p + 15].lenx = token.qtree[p + 5].lenx;
token.qtree[p + 12].leny = token.qtree[p + 8].leny;
token.qtree[p + 13].leny = token.qtree[p + 8].leny;
token.qtree[p + 14].leny = token.qtree[p + 10].leny;
token.qtree[p + 15].leny = token.qtree[p + 10].leny;
}
private void qtree4(Token token, int start, int lenx, int leny, int x, int y) {
int evenx, eveny; /* Check length of subband for even or odd */
int p; /* indicates subband information being stored */
p = start;
evenx = lenx % 2;
eveny = leny % 2;
token.qtree[p].x = x;
token.qtree[p + 2].x = x;
token.qtree[p].y = y;
token.qtree[p + 1].y = y;
if (evenx == 0) {
token.qtree[p].lenx = lenx / 2;
token.qtree[p + 1].lenx = token.qtree[p].lenx;
token.qtree[p + 2].lenx = token.qtree[p].lenx;
token.qtree[p + 3].lenx = token.qtree[p].lenx;
} else {
token.qtree[p].lenx = (lenx + 1) / 2;
token.qtree[p + 1].lenx = token.qtree[p].lenx - 1;
token.qtree[p + 2].lenx = token.qtree[p].lenx;
token.qtree[p + 3].lenx = token.qtree[p + 1].lenx;
}
token.qtree[p + 1].x = x + token.qtree[p].lenx;
token.qtree[p + 3].x = token.qtree[p + 1].x;
if (eveny == 0) {
token.qtree[p].leny = leny / 2;
token.qtree[p + 1].leny = token.qtree[p].leny;
token.qtree[p + 2].leny = token.qtree[p].leny;
token.qtree[p + 3].leny = token.qtree[p].leny;
} else {
token.qtree[p].leny = (leny + 1) / 2;
token.qtree[p + 1].leny = token.qtree[p].leny;
token.qtree[p + 2].leny = token.qtree[p].leny - 1;
token.qtree[p + 3].leny = token.qtree[p + 2].leny;
}
token.qtree[p + 2].y = y + token.qtree[p].leny;
token.qtree[p + 3].y = token.qtree[p + 2].y;
}
private int[] huffmanDecodeDataMem(Token token, int size) {
int[] qdata = new int[size];
int[] maxcode = new int[WsqHelper.MAX_HUFFBITS + 1];
int[] mincode = new int[WsqHelper.MAX_HUFFBITS + 1];
int[] valptr = new int[WsqHelper.MAX_HUFFBITS + 1];
IntRef marker = new IntRef(getCMarkerWSQ(token, WsqHelper.TBLS_N_SOB));
IntRef bitCount = new IntRef(0); /* bit count for getc_nextbits_wsq routine */
IntRef nextByte = new IntRef(0); /*next byte of buffer*/
int hufftableId = 0; /* huffman table number */
int ip = 0;
while (marker.value != WsqHelper.EOI_WSQ) {
if (marker.value != 0) {
while (marker.value != WsqHelper.SOB_WSQ) {
getCTableWSQ(token, marker.value);
marker.value = getCMarkerWSQ(token, WsqHelper.TBLS_N_SOB);
}
hufftableId = getCBlockHeader(token); /* huffman table number */
if (token.tableDHT[hufftableId].tabdef != 1) {
throw new SystemException("ERROR : huffmanDecodeDataMem : huffman table undefined.");
}
/* the next two routines reconstruct the huffman tables */
HuffCode[] hufftable = buildHuffsizes(token.tableDHT[hufftableId].huffbits, WsqHelper.MAX_HUFFCOUNTS_WSQ);
buildHuffcodes(hufftable);
/* this routine builds a set of three tables used in decoding */
/* the compressed buffer*/
genDecodeTable(hufftable, maxcode, mincode, valptr, token.tableDHT[hufftableId].huffbits);
bitCount.value = 0;
marker.value = 0;
}
/* get next huffman category code from compressed input buffer stream */
int nodeptr = decodeDataMem(token, mincode, maxcode, valptr, token.tableDHT[hufftableId].huffvalues, bitCount, marker, nextByte);
/* nodeptr pointers for decoding */
if (nodeptr == -1) {
continue;
}
if (nodeptr > 0 && nodeptr <= 100) {
for (int n = 0; n < nodeptr; n++) {
qdata[ip++] = 0; /* z run */
}
} else if (nodeptr > 106 && nodeptr < 0xff) {
qdata[ip++] = nodeptr - 180;
} else if (nodeptr == 101) {
qdata[ip++] = getCNextbitsWSQ(token, marker, bitCount, 8, nextByte);
} else if (nodeptr == 102) {
qdata[ip++] = -getCNextbitsWSQ(token, marker, bitCount, 8, nextByte);
} else if (nodeptr == 103) {
qdata[ip++] = getCNextbitsWSQ(token, marker, bitCount, 16, nextByte);
} else if (nodeptr == 104) {
qdata[ip++] = -getCNextbitsWSQ(token, marker, bitCount, 16, nextByte);
} else if (nodeptr == 105) {
int n = getCNextbitsWSQ(token, marker, bitCount, 8, nextByte);
while (n-- > 0) {
qdata[ip++] = 0;
}
} else if (nodeptr == 106) {
int n = getCNextbitsWSQ(token, marker, bitCount, 16, nextByte);
while (n-- > 0) {
qdata[ip++] = 0;
}
} else {
throw new SystemException("ERROR: huffman_decode_data_mem : Invalid code (" + nodeptr + ")");
}
}
return qdata;
}
private int getCBlockHeader(Token token) {
token.readShort(); /* block header size */
return token.readByte();
}
private HuffCode[] buildHuffsizes(int[] huffbits, int maxHuffcounts) {
HuffCode[] huffcodeTable; /*table of huffman codes and sizes*/
int numberOfCodes = 1; /*the number codes for a given code size*/
huffcodeTable = new HuffCode[maxHuffcounts + 1];
int tempSize = 0;
for (int codeSize = 1; codeSize <= WsqHelper.MAX_HUFFBITS; codeSize++) {
while (numberOfCodes <= huffbits[codeSize - 1]) {
huffcodeTable[tempSize] = new HuffCode();
huffcodeTable[tempSize].size = codeSize;
tempSize++;
numberOfCodes++;
}
numberOfCodes = 1;
}
huffcodeTable[tempSize] = new HuffCode();
huffcodeTable[tempSize].size = 0;
return huffcodeTable;
}
private void buildHuffcodes(HuffCode[] huffcodeTable) {
short tempCode = 0; /*used to construct code word*/
int pointer = 0; /*pointer to code word information*/
int tempSize = huffcodeTable[0].size;
if (huffcodeTable[pointer].size == 0) {
return;
}
do {
do {
huffcodeTable[pointer].code = tempCode;
tempCode++;
pointer++;
} while (huffcodeTable[pointer].size == tempSize);
if (huffcodeTable[pointer].size == 0)
return;
do {
tempCode <<= 1;
tempSize++;
} while (huffcodeTable[pointer].size != tempSize);
} while (huffcodeTable[pointer].size == tempSize);
}
private void genDecodeTable(HuffCode[] huffcodeTable, int[] maxcode, int[] mincode, int[] valptr, int[] huffbits) {
for (int i = 0; i <= WsqHelper.MAX_HUFFBITS; i++) {
maxcode[i] = 0;
mincode[i] = 0;
valptr[i] = 0;
}
int i2 = 0;
for (int i = 1; i <= WsqHelper.MAX_HUFFBITS; i++) {
if (huffbits[i - 1] == 0) {
maxcode[i] = -1;
continue;
}
valptr[i] = i2;
mincode[i] = huffcodeTable[i2].code;
i2 = i2 + huffbits[i - 1] - 1;
maxcode[i] = huffcodeTable[i2].code;
i2++;
}
}
private int decodeDataMem(Token token, int[] mincode, int[] maxcode, int[] valptr, int[] huffvalues, IntRef bitCount, IntRef marker, IntRef nextByte) {
short code = (short) getCNextbitsWSQ(token, marker, bitCount, 1, nextByte); /* becomes a huffman code word (one bit at a time)*/
if (marker.value != 0) {
return -1;
}
int inx;
for (inx = 1; code > maxcode[inx]; inx++) {
int tbits = getCNextbitsWSQ(token, marker, bitCount, 1, nextByte); /* becomes a huffman code word (one bit at a time)*/
code = (short) ((code << 1) + tbits);
if (marker.value != 0) {
return -1;
}
}
int inx2 = valptr[inx] + code - mincode[inx]; /*increment variables*/
return huffvalues[inx2];
}
private int getCNextbitsWSQ(Token token, IntRef marker, IntRef bitCount, int bitsReq, IntRef nextByte) {
if (bitCount.value == 0) {
nextByte.value = token.readByte();
bitCount.value = 8;
if (nextByte.value == 0xFF) {
int code2 = token.readByte(); /*stuffed byte of buffer*/
if (code2 != 0x00 && bitsReq == 1) {
marker.value = (nextByte.value << 8) | code2;
return 1;
}
if (code2 != 0x00) {
throw new SystemException("ERROR: getCNextbitsWSQ : No stuffed zeros.");
}
}
}
int bits, tbits; /*bits of current buffer byte requested*/
int bitsNeeded; /*additional bits required to finish request*/
if (bitsReq <= bitCount.value) {
bits = (nextByte.value >> (bitCount.value - bitsReq)) & (WsqHelper.BITMASK[bitsReq]);
bitCount.value -= bitsReq;
nextByte.value &= WsqHelper.BITMASK[bitCount.value];
} else {
bitsNeeded = bitsReq - bitCount.value; /*additional bits required to finish request*/
bits = nextByte.value << bitsNeeded;
bitCount.value = 0;
tbits = getCNextbitsWSQ(token, marker, bitCount, bitsNeeded, nextByte);
bits |= tbits;
}
return bits;
}
private float[] unquantize(Token token, int[] sip, int width, int height) {
float[] fip = new float[width * height]; /* floating point image */
if (token.tableDQT.dqtDef != 1) {
throw new SystemException("ERROR: unquantize : quantization table parameters not defined!");
}
float binCenter = token.tableDQT.binCenter; /* quantizer bin center */
int sptr = 0;
for (int cnt = 0; cnt < WsqHelper.NUM_SUBBANDS; cnt++) {
if (token.tableDQT.qBin[cnt] == 0.0) {
continue;
}
int fptr = (token.qtree[cnt].y * width) + token.qtree[cnt].x;
for (int row = 0; row < token.qtree[cnt].leny; row++, fptr += width - token.qtree[cnt].lenx) {
for (int col = 0; col < token.qtree[cnt].lenx; col++) {
if (sip[sptr] == 0) {
fip[fptr] = 0.0f;
} else if (sip[sptr] > 0) {
fip[fptr] = (token.tableDQT.qBin[cnt] * (sip[sptr] - binCenter)) + (token.tableDQT.zBin[cnt] / 2.0f);
} else if (sip[sptr] < 0) {
fip[fptr] = (token.tableDQT.qBin[cnt] * (sip[sptr] + binCenter)) - (token.tableDQT.zBin[cnt] / 2.0f);
} else {
throw new SystemException("ERROR : unquantize : invalid quantization pixel value");
}
fptr++;
sptr++;
}
}
}
return fip;
}
private void wsqReconstruct(Token token, float[] fdata, int width, int height) {
if (token.tableDTT.lodef != 1) {
throw new SystemException("ERROR: wsq_reconstruct : Lopass filter coefficients not defined");
}
if (token.tableDTT.hidef != 1) {
throw new SystemException("ERROR: wsq_reconstruct : Hipass filter coefficients not defined");
}
int numPix = width * height;
/* Allocate temporary floating point pixmap. */
float[] fdataTemp = new float[numPix];
/* Reconstruct floating point pixmap from wavelet subband buffer. */
for (int node = WsqHelper.W_TREELEN - 1; node >= 0; node--) {
int fdataBse = (token.wtree[node].y * width) + token.wtree[node].x;
joinLets(fdataTemp, fdata, 0, fdataBse, token.wtree[node].lenx, token.wtree[node].leny,
1, width,
token.tableDTT.hifilt, token.tableDTT.hisz,
token.tableDTT.lofilt, token.tableDTT.losz,
token.wtree[node].invcl);
joinLets(fdata, fdataTemp, fdataBse, 0, token.wtree[node].leny, token.wtree[node].lenx,
width, 1,
token.tableDTT.hifilt, token.tableDTT.hisz,
token.tableDTT.lofilt, token.tableDTT.losz,
token.wtree[node].invrw);
}
}
private void joinLets(
float[] newdata,
float[] olddata,
int newIndex,
int oldIndex,
int len1, /* temporary length parameters */
int len2,
int pitch, /* pitch gives next row_col to filter */
int stride, /* stride gives next pixel to filter */
float[] hi,
int hsz, /* NEW */
float[] lo, /* filter coefficients */
int lsz, /* NEW */
int inv) /* spectral inversion? */ {
int lp0, lp1;
int hp0, hp1;
int lopass, hipass; /* lo/hi pass image pointers */
int limg, himg;
int pix, cl_rw; /* pixel counter and column/row counter */
int i, da_ev; /* if "scanline" is even or odd and */
int loc, hoc;
int hlen, llen;
int nstr, pstr;
int tap;
int fi_ev;
int olle, ohle, olre, ohre;
int lle, lle2, lre, lre2;
int hle, hle2, hre, hre2;
int lpx, lspx;
int lpxstr, lspxstr;
int lstap, lotap;
int hpx, hspx;
int hpxstr, hspxstr;
int hstap, hotap;
int asym, fhre = 0, ofhre;
float ssfac, osfac, sfac;
da_ev = len2 % 2;
fi_ev = lsz % 2;
pstr = stride;
nstr = -pstr;
if (da_ev != 0) {
llen = (len2 + 1) / 2;
hlen = llen - 1;
} else {
llen = len2 / 2;
hlen = llen;
}
if (fi_ev != 0) {
asym = 0;
ssfac = 1.0f;
ofhre = 0;
loc = (lsz - 1) / 4;
hoc = (hsz + 1) / 4 - 1;
lotap = ((lsz - 1) / 2) % 2;
hotap = ((hsz + 1) / 2) % 2;
if (da_ev != 0) {
olle = 0;
olre = 0;
ohle = 1;
ohre = 1;
} else {
olle = 0;
olre = 1;
ohle = 1;
ohre = 0;
}
} else {
asym = 1;
ssfac = -1.0f;
ofhre = 2;
loc = lsz / 4 - 1;
hoc = hsz / 4 - 1;
lotap = (lsz / 2) % 2;
hotap = (hsz / 2) % 2;
if (da_ev != 0) {
olle = 1;
olre = 0;
ohle = 1;
ohre = 1;
} else {
olle = 1;
olre = 1;
ohle = 1;
ohre = 1;
}
if (loc == -1) {
loc = 0;
olle = 0;
}
if (hoc == -1) {
hoc = 0;
ohle = 0;
}
for (i = 0; i < hsz; i++)
hi[i] *= -1.0F;
}
for (cl_rw = 0; cl_rw < len1; cl_rw++) {
limg = newIndex + cl_rw * pitch;
himg = limg;
newdata[himg] = 0.0f;
newdata[himg + stride] = 0.0f;
if (inv != 0) {
hipass = oldIndex + cl_rw * pitch;
lopass = hipass + stride * hlen;
} else {
lopass = oldIndex + cl_rw * pitch;
hipass = lopass + stride * llen;
}
lp0 = lopass;
lp1 = lp0 + (llen - 1) * stride;
lspx = lp0 + (loc * stride);
lspxstr = nstr;
lstap = lotap;
lle2 = olle;
lre2 = olre;
hp0 = hipass;
hp1 = hp0 + (hlen - 1) * stride;
hspx = hp0 + (hoc * stride);
hspxstr = nstr;
hstap = hotap;
hle2 = ohle;
hre2 = ohre;
osfac = ssfac;
for (pix = 0; pix < hlen; pix++) {
for (tap = lstap; tap >= 0; tap--) {
lle = lle2;
lre = lre2;
lpx = lspx;
lpxstr = lspxstr;
newdata[limg] = olddata[lpx] * lo[tap];
for (i = tap + 2; i < lsz; i += 2) {
if (lpx == lp0) {
if (lle != 0) {
lpxstr = 0;
lle = 0;
} else
lpxstr = pstr;
}
if (lpx == lp1) {
if (lre != 0) {
lpxstr = 0;
lre = 0;
} else
lpxstr = nstr;
}
lpx += lpxstr;
newdata[limg] += olddata[lpx] * lo[i];
}
limg += stride;
}
if (lspx == lp0) {
if (lle2 != 0) {
lspxstr = 0;
lle2 = 0;
} else
lspxstr = pstr;
}
lspx += lspxstr;
lstap = 1;
for (tap = hstap; tap >= 0; tap--) {
hle = hle2;
hre = hre2;
hpx = hspx;
hpxstr = hspxstr;
fhre = ofhre;
sfac = osfac;
for (i = tap; i < hsz; i += 2) {
if (hpx == hp0) {
if (hle != 0) {
hpxstr = 0;
hle = 0;
} else {
hpxstr = pstr;
sfac = 1.0f;
}
}
if (hpx == hp1) {
if (hre != 0) {
hpxstr = 0;
hre = 0;
if (asym != 0 && da_ev != 0) {
hre = 1;
fhre--;
sfac = (float) fhre;
if (sfac == 0.0)
hre = 0;
}
} else {
hpxstr = nstr;
if (asym != 0)
sfac = -1.0f;
}
}
newdata[himg] += olddata[hpx] * hi[i] * sfac;
hpx += hpxstr;
}
himg += stride;
}
if (hspx == hp0) {
if (hle2 != 0) {
hspxstr = 0;
hle2 = 0;
} else {
hspxstr = pstr;
osfac = 1.0f;
}
}
hspx += hspxstr;
hstap = 1;
}
if (da_ev != 0)
if (lotap != 0)
lstap = 1;
else
lstap = 0;
else if (lotap != 0)
lstap = 2;
else
lstap = 1;
for (tap = 1; tap >= lstap; tap--) {
lle = lle2;
lre = lre2;
lpx = lspx;
lpxstr = lspxstr;
newdata[limg] = olddata[lpx] * lo[tap];
for (i = tap + 2; i < lsz; i += 2) {
if (lpx == lp0) {
if (lle != 0) {
lpxstr = 0;
lle = 0;
} else
lpxstr = pstr;
}
if (lpx == lp1) {
if (lre != 0) {
lpxstr = 0;
lre = 0;
} else
lpxstr = nstr;
}
lpx += lpxstr;
newdata[limg] += olddata[lpx] * lo[i];
}
limg += stride;
}
if (da_ev != 0) {
if (hotap != 0)
hstap = 1;
else
hstap = 0;
if (hsz == 2) {
hspx -= hspxstr;
fhre = 1;
}
} else if (hotap != 0)
hstap = 2;
else
hstap = 1;
for (tap = 1; tap >= hstap; tap--) {
hle = hle2;
hre = hre2;
hpx = hspx;
hpxstr = hspxstr;
sfac = osfac;
if (hsz != 2)
fhre = ofhre;
for (i = tap; i < hsz; i += 2) {
if (hpx == hp0) {
if (hle != 0) {
hpxstr = 0;
hle = 0;
} else {
hpxstr = pstr;
sfac = 1.0f;
}
}
if (hpx == hp1) {
if (hre != 0) {
hpxstr = 0;
hre = 0;
if (asym != 0 && da_ev != 0) {
hre = 1;
fhre--;
sfac = (float) fhre;
if (sfac == 0.0)
hre = 0;
}
} else {
hpxstr = nstr;
if (asym != 0)
sfac = -1.0f;
}
}
newdata[himg] += olddata[hpx] * hi[i] * sfac;
hpx += hpxstr;
}
himg += stride;
}
}
if (fi_ev == 0)
for (i = 0; i < hsz; i++)
hi[i] *= -1.0F;
}
private byte[] convertImage2Byte(float[] img, int width, int height, float mShift, float rScale) {
byte[] data = new byte[width * height];
int idx = 0;
for (int r = 0; r < height; r++) {
for (int c = 0; c < width; c++) {
float pixel = (img[idx] * rScale) + mShift;
pixel += 0.5F;
if (pixel < 0.0) {
data[idx] = 0; /* neg pix poss after quantization */
} else if (pixel > 255.0) {
data[idx] = (byte) 255;
} else {
data[idx] = (byte) pixel;
}
idx++;
}
}
return data;
}
}
}