/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.imageio.jpeg; import java.io.IOException; import java.io.InputStream; /* * Copyright (C) Helmut Dersch * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * * Original source: http://webuser.fh-furtwangen.de/~dersch/ * Changed License to LGPL with the friendly permission of Helmut Dersch. */ public class JPEGDecoder { private int height; // Private variables and constants private static final int MSB = 0x80000000; private static final int MAX_HUFFMAN_SUBTREE = 50; // max size = MAX_HUFFMAN_SUBTREE * 256 private int nComp; //number of Components in a scan private int[] qTab[] = new int[10][]; //quantization table for the i-th Comp in a scan private int[] dcTab[] = new int[10][]; //dc HuffTab for the i-th Comp in a scan private int[] acTab[] = new int[10][]; //ac HuffTab for the i-th Comp in a scan private int nBlock[] = new int[10]; //number of blocks in the i-th Comp in a scan // i=0, ... ,Ns-1 private int YH, YV, Xsize, Ysize; private int marker; private int marker_index = 0; private int Ri = 0; // RestartInterval private int DU[][][] = new int[10][4][64]; //at most 10 data units in a MCU //at most 4 data units in one component private int x = 0, y = 0, num = 0, yp = 0; // the begin point of MCU private int IDCT_Source[] = new int[64]; private static final int IDCT_P[] = { 0, 5, 40, 16, 45, 2, 7, 42, 21, 56, 8, 61, 18, 47, 1, 4, 41, 23, 58, 13, 32, 24, 37, 10, 63, 17, 44, 3, 6, 43, 20, 57, 15, 34, 29, 48, 53, 26, 39, 9, 60, 19, 46, 22, 59, 12, 33, 31, 50, 55, 25, 36, 11, 62, 14, 35, 28, 49, 52, 27, 38, 30, 51, 54 }; private static final int table[] = { 0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63 }; private FrameHeader FH = new FrameHeader(); private ScanHeader SH = new ScanHeader(); private QuantizationTable QT = new QuantizationTable(); private HuffmanTable HT = new HuffmanTable(); private void error(String message) throws Exception { throw new Exception(message); } // Report progress in the range 0...100 public int progress() { if (height == 0) return 0; if (yp > height) return 100; return yp * 100 / height; } interface PixelArray { public void setSize(int width, int height) throws Exception; public void setPixel(int x, int y, int argb); } class ComponentSpec { int C; //Component id int H; //Horizontal sampling factor int V; //Vertical .... int Tq; //Quantization table destination selector } class FrameHeader { int SOF; //Start of frame in different type int Lf; //Length int P; //Sample Precision (from the orignal image) int Y; //Number of lines int X; //Number of samples per line int Nf; //Number of component in the frame ComponentSpec Comp[]; //Components C H V Tq public int get(InputStream in, int sof) throws Exception { //get data from file stream in //return 0 : correct otherwise : error int i, temp, count = 0, c; SOF = sof; Lf = get16(in); count += 2; P = get8(in); count++; Y = get16(in); count += 2; height = Y; X = get16(in); count += 2; //width=X; Nf = get8(in); count++; Comp = new ComponentSpec[Nf + 1]; for (i = 0; i <= Nf; i++) { Comp[i] = new ComponentSpec(); } for (i = 1; i <= Nf; i++) { if (count > Lf) { error("ERROR: frame format error"); } c = get8(in); count++; if (c >= Lf) { error("ERROR: fram format error [c>=Lf]"); } Comp[c].C = c; temp = get8(in); count++; Comp[c].H = temp >> 4; Comp[c].V = temp & 0x0F; Comp[c].Tq = get8(in); count++; } if (count != Lf) { error("ERROR: frame format error [Lf!=count]"); } return 1; } } class ScanComponent { int Cs; //Scan component selector int Td; //DC table selector int Ta; //AC table selector } class ScanHeader { int Ls; //length int Ns; //Number of components in the scan int Ss; //Start of spectral or predictor selection int Se; //End of spectral selection int Ah; int Al; ScanComponent Comp[]; //Components Cs Td Ta // from [0] to [Ns-1] int get(InputStream in) throws Exception { //get data from file stream in //return 0 : correct otherwise : error int i, temp, count = 0; Ls = get16(in); count += 2; Ns = get8(in); count++; Comp = new ScanComponent[Ns]; for (i = 0; i < Ns; i++) { Comp[i] = new ScanComponent(); if (count > Ls) { error("ERROR: scan header format error"); } Comp[i].Cs = get8(in); count++; temp = get8(in); count++; Comp[i].Td = temp >> 4; Comp[i].Ta = temp & 0x0F; } Ss = get8(in); count++; Se = get8(in); count++; temp = get8(in); count++; Ah = temp >> 4; Al = temp & 0x0F; if (count != Ls) { error("ERROR: scan header format error [count!=Ns]"); } return 1; } } class QuantizationTable { int Lq; //length int Pq[] = new int[4]; //Quantization precision 8 or 16 int[] Tq = new int[4]; //1: this table is presented int Q[][] = new int[4][64]; //Tables public QuantizationTable() { Tq[0] = 0; Tq[1] = 0; Tq[2] = 0; Tq[3] = 0; } int get(InputStream in) throws Exception { //get dataStream in) throws Exception{ //get da from file stream in //return 0 : correct otherwise : error int i, count = 0, temp, t; Lq = get16(in); count += 2; while (count < Lq) { temp = get8(in); count++; t = temp & 0x0F; if (t > 3) { error("ERROR: Quantization table ID > 3"); } Pq[t] = temp >> 4; if (Pq[t] == 0) Pq[t] = 8; else if (Pq[t] == 1) Pq[t] = 16; else { error("ERROR: Quantization table precision error"); } Tq[t] = 1; if (Pq[t] == 8) { for (i = 0; i < 64; i++) { if (count > Lq) { error("ERROR: Quantization table format error"); } Q[t][i] = get8(in); count++; } EnhanceQuantizationTable(Q[t]); } else { for (i = 0; i < 64; i++) { if (count > Lq) { error("ERROR: Quantization table format error"); } Q[t][i] = get16(in); count += 2; } EnhanceQuantizationTable(Q[t]); } } if (count != Lq) { error("ERROR: Quantization table error [count!=Lq]"); } return 1; } } class HuffmanTable { int Lh; //Length int[][] Tc = new int[4][2]; //1: this table is presented int Th[] = new int[4]; //1: this table is presented int L[][][] = new int[4][2][16]; int V[][][][] = new int[4][2][16][200]; //tables public HuffmanTable() { Tc[0][0] = 0; Tc[1][0] = 0; Tc[2][0] = 0; Tc[3][0] = 0; Tc[0][1] = 0; Tc[1][1] = 0; Tc[2][1] = 0; Tc[3][1] = 0; Th[0] = 0; Th[1] = 0; Th[2] = 0; Th[3] = 0; } int get(InputStream in) throws Exception { //get data from file stream in //return 0 : correct otherwise : error int i, j, temp, count = 0, t, c; Lh = get16(in); count += 2; while (count < Lh) { temp = get8(in); count++; t = temp & 0x0F; if (t > 3) { error("ERROR: Huffman table ID > 3"); } c = temp >> 4; if (c > 2) { error("ERROR: Huffman table [Table class > 2 ]"); } Th[t] = 1; Tc[t][c] = 1; for (i = 0; i < 16; i++) { L[t][c][i] = get8(in); count++; } for (i = 0; i < 16; i++) for (j = 0; j < L[t][c][i]; j++) { if (count > Lh) { error("ERROR: Huffman table format error [count>Lh]"); } V[t][c][i][j] = get8(in); count++; } } if (count != Lh) { error("ERROR: Huffman table format error [count!=Lf]"); } for (i = 0; i < 4; i++) for (j = 0; j < 2; j++) if (Tc[i][j] != 0) { Build_HuffTab(HuffTab[i][j], L[i][j], V[i][j]); } return 1; } } private int readNumber(InputStream in) throws Exception { int Ld; Ld = get16(in); if (Ld != 4) { error("ERROR: Define number format error [Ld!=4]"); } return get16(in); } private String readComment(InputStream in) throws Exception { int Lc, count = 0, i; StringBuffer sb = new StringBuffer(); Lc = get16(in); count += 2; for (i = 0; count < Lc; i++) { sb.append((char) get8(in)); count++; } return sb.toString(); } private int readApp(InputStream in) throws Exception { int Lp; int count = 0; Lp = get16(in); count += 2; while (count < Lp) { get8(in); count++; } return Lp; } private final int get8(InputStream in) throws Exception { try { return in.read(); } catch (IOException e) { error("get8() read error: " + e.toString()); return -1; } } //get 16-bit data private final int get16(InputStream in) throws Exception { int temp; try { temp = in.read(); temp <<= 8; return temp | in.read(); } catch (IOException e) { error("get16() read error: " + e.toString()); return -1; } } /** * ***************************************************************** * Huffman table for fast search: (HuffTab) 8-bit Look up table * 2-layer search architecture, 1st-layer represent 256 node (8 bits) * if codeword-length > 8 bits, then * the entry of 1st-layer = (# of 2nd-layer table) | MSB * and it is stored in the 2nd-layer * Size of tables in each layer are 256. * HuffTab[*][*][0-256] is always the only 1st-layer table. * <p/> * An entry can be: * (1) (# of 2nd-layer table) | MSB , for code length > 8 in 1st-layer * (2) (Code length) << 8 | HuffVal * ****************************************************************** */ private int HuffTab[][][] = new int[4][2][MAX_HUFFMAN_SUBTREE * 256]; /* Build_HuffTab() Parameter: t table ID c table class ( 0 for DC, 1 for AC ) L[i] # of codewords which length is i V[i][j] Huffman Value (length=i) Effect: build up HuffTab[t][c] using L and V. */ private void Build_HuffTab(int tab[], int L[], int V[][]) throws Exception { int current_table, i, j, n, table_used, temp; int k; temp = 256; k = 0; for (i = 0; i < 8; i++) { // i+1 is Code length for (j = 0; j < L[i]; j++) { for (n = 0; n < (temp >> (i + 1)); n++) { tab[k] = V[i][j] | ((i + 1) << 8); k++; } } } for (i = 1; k < 256; i++, k++) tab[k] = i | MSB; if (i > 50) { error("ERROR: Huffman table out of memory!"); } table_used = i; current_table = 1; k = 0; for (i = 8; i < 16; i++) { // i+1 is Code length for (j = 0; j < L[i]; j++) { for (n = 0; n < (temp >> (i - 7)); n++) { tab[current_table * 256 + k] = V[i][j] | ((i + 1) << 8); k++; } if (k >= 256) { if (k > 256) { error("ERROR: Huffman table error(1)!"); } k = 0; current_table++; } } } } /* HuffmanValue(table HuffTab[x][y] (ex) HuffmanValue(HuffTab[1][0],...) ): return: Huffman Value of table 0xFF?? if it receives a MARKER Parameter: table HuffTab[x][y] (ex) HuffmanValue(HuffTab[1][0],...) temp temp storage for remainded bits index index to bit of temp in FILE pointer Effect: temp store new remainded bits index change to new index in change to new position NOTE: Initial by temp=0; index=0; NOTE: (explain temp and index) temp: is always in the form at calling time or returning time | byte 4 | byte 3 | byte 2 | byte 1 | | 0 | 0 | 00000000 | 00000??? | if not a MARKER ^index=3 (from 0 to 15) 321 NOTE (marker and marker_index): If get a MARKER from 'in', marker=the low-byte of the MARKER and marker_index=9 If marker_index=9 then index is always > 8, or HuffmanValue() will not be called. */ private int HuffmanValue(int table[], int temp[], int index[], InputStream in) throws Exception { int code, input, mask = 0xFFFF; if (index[0] < 8) { temp[0] <<= 8; input = get8(in); if (input == 0xFF) { marker = get8(in); if (marker != 0) marker_index = 9; } temp[0] |= input; } else index[0] -= 8; code = table[temp[0] >> index[0]]; if ((code & MSB) != 0) { if (marker_index != 0) { marker_index = 0; return 0xFF00 | marker; } temp[0] &= (mask >> (16 - index[0])); temp[0] <<= 8; input = get8(in); if (input == 0xFF) { marker = get8(in); if (marker != 0) marker_index = 9; } temp[0] |= input; code = table[(code & 0xFF) * 256 + (temp[0] >> index[0])]; index[0] += 8; } index[0] += 8 - (code >> 8); if (index[0] < 0) error("index=" + index[0] + " temp=" + temp[0] + " code=" + code + " in HuffmanValue()"); if (index[0] < marker_index) { marker_index = 0; return 0xFF00 | marker; } temp[0] &= (mask >> (16 - index[0])); return code & 0xFF; } //get n-bit signed data from file 'in' // temp is de //get n-bit sfined as before // return signed integer or 0x00FF??00 if it sees a MARKER private int getn(InputStream in, int n, int temp[], int index[]) throws Exception { int result, one = 1, n_one = -1; int mask = 0xFFFF, input; if (n == 0) return 0; index[0] -= n; if (index[0] >= 0) { if (index[0] < marker_index) { marker_index = 0; return (0xFF00 | marker) << 8; } result = temp[0] >> index[0]; temp[0] &= (mask >> (16 - index[0])); } else { temp[0] <<= 8; input = get8(in); if (input == 0xFF) { marker = get8(in); if (marker != 0) marker_index = 9; } temp[0] |= input; index[0] += 8; if (index[0] < 0) { if (marker_index != 0) { marker_index = 0; return (0xFF00 | marker) << 8; } temp[0] <<= 8; input = get8(in); if (input == 0xFF) { marker = get8(in); if (marker != 0) marker_index = 9; } temp[0] |= input; index[0] += 8; } if (index[0] < 0) error("index=" + index[0] + " in getn()"); if (index[0] < marker_index) { marker_index = 0; return (0xFF00 | marker) << 8; } result = temp[0] >> index[0]; temp[0] &= (mask >> (16 - index[0])); } if (result < (one << (n - 1))) result += (n_one << n) + 1; return result; } /** * *************************************************************** * <p/> * Decode MCU * <p/> * DU[i][j][8][8] the j-th data unit of component i. * <p/> * **************************************************************** */ private int YUV_to_BGR(int Y, int u, int v) { if (Y < 0) Y = 0; int tempB, tempG, tempR; tempB = Y + ((116130 * u) >> 16); if (tempB < 0) tempB = 0; else if (tempB > 255) tempB = 255; tempG = Y - ((22554 * u + 46802 * v) >> 16); if (tempG < 0) tempG = 0; else if (tempG > 255) tempG = 255; tempR = Y + ((91881 * v) >> 16); if (tempR < 0) tempR = 0; else if (tempR > 255) tempR = 255; return 0xff000000 | ((tempR << 16) + (tempG << 8) + tempB); } /* output() x, y should be the starting point of MCU when calling output(..) it means output() should set x,y for the next MCU at the end. */ private void output(PixelArray out) { int temp_x, temp_8y, temp; int k = 0; int DU10[], DU20[]; DU10 = DU[1][0]; DU20 = DU[2][0]; num++; for (int i = 0; i < YV; i++) { for (int j = 0; j < YH; j++) { temp_8y = i * 32; temp_x = temp = j * 4; for (int l = 0; l < 64; l++) { if (x < Xsize && y < Ysize) { out.setPixel(x, y, YUV_to_BGR(DU[0][k][l] + 128, DU10[temp_8y + temp_x], DU20[temp_8y + temp_x])); } x++; if ((x % YH) == 0) temp_x++; if ((x % 8) == 0) { y++; x -= 8; temp_x = temp; if ((y % YV) == 0) temp_8y += 8; } } k++; x += 8; y -= 8; } x -= YH * 8; y += 8; } x += YH * 8; y -= YV * 8; if (x >= Xsize) { y += YV * 8; x = 0; } yp = y; } private void level_shift(int du[], int P) throws Exception { int i; if (P == 8) { for (i = 0; i < 64; i++) du[i] += 128; } else if (P == 12) { for (i = 0; i < 64; i++) du[i] += 2048; } else error("ERROR: Precision=" + P); } /* decode_MCU() return 0 if correctly decoded 0xFF?? if it sees a MARKER */ private int decode_MCU(InputStream in, int PrevDC[], int temp[], int index[]) throws Exception { int value, actab[], dctab[]; int qtab[], Cs; for (Cs = 0; Cs < nComp; Cs++) { qtab = qTab[Cs]; actab = acTab[Cs]; dctab = dcTab[Cs]; for (int i = 0; i < nBlock[Cs]; i++) { for (int k = 0; k < IDCT_Source.length; k++) IDCT_Source[k] = 0; value = HuffmanValue(dctab, temp, index, in); if (value >= 0xFF00) return value; PrevDC[Cs] = IDCT_Source[0] = PrevDC[Cs] + getn(in, value, temp, index); IDCT_Source[0] *= qtab[0]; for (int j = 1; j < 64; j++) { value = HuffmanValue(actab, temp, index, in); if (value >= 0xFF00) return value; j += (value >> 4); if ((value & 0x0F) == 0) { if ((value >> 4) == 0) break; } else { IDCT_Source[IDCT_P[j]] = getn(in, value & 0x0F, temp, index) * qtab[j]; } } ScaleIDCT(DU[Cs][i]); } } return 0; } // in-place operation private void EnhanceQuantizationTable(int qtab[]) { int i; for (i = 0; i < 8; i++) { qtab[table[0 * 8 + i]] *= 90; qtab[table[4 * 8 + i]] *= 90; qtab[table[2 * 8 + i]] *= 118; qtab[table[6 * 8 + i]] *= 49; qtab[table[5 * 8 + i]] *= 71; qtab[table[1 * 8 + i]] *= 126; qtab[table[7 * 8 + i]] *= 25; qtab[table[3 * 8 + i]] *= 106; } for (i = 0; i < 8; i++) { qtab[table[0 + 8 * i]] *= 90; qtab[table[4 + 8 * i]] *= 90; qtab[table[2 + 8 * i]] *= 118; qtab[table[6 + 8 * i]] *= 49; qtab[table[5 + 8 * i]] *= 71; qtab[table[1 + 8 * i]] *= 126; qtab[table[7 + 8 * i]] *= 25; qtab[table[3 + 8 * i]] *= 106; } for (i = 0; i < 64; i++) { qtab[i] >>= 6; } } // out-of-place operation // input: IDCT_Source // output: matrix private void ScaleIDCT(int matrix[]) { int p[][] = new int[8][8]; int t0, t1, t2, t3, i; int src0, src1, src2, src3, src4, src5, src6, src7; int det0, det1, det2, det3, det4, det5, det6, det7; int mindex = 0; for (i = 0; i < 8; i++) { src0 = IDCT_Source[0 * 8 + i]; src1 = IDCT_Source[1 * 8 + i]; src2 = IDCT_Source[2 * 8 + i] - IDCT_Source[3 * 8 + i]; src3 = IDCT_Source[3 * 8 + i] + IDCT_Source[2 * 8 + i]; src4 = IDCT_Source[4 * 8 + i] - IDCT_Source[7 * 8 + i]; src6 = IDCT_Source[5 * 8 + i] - IDCT_Source[6 * 8 + i]; t0 = IDCT_Source[5 * 8 + i] + IDCT_Source[6 * 8 + i]; t1 = IDCT_Source[4 * 8 + i] + IDCT_Source[7 * 8 + i]; src5 = t0 - t1; src7 = t0 + t1; // det4 = -src4 * 480 - src6 * 192; det5 = src5 * 384; det6 = src6 * 480 - src4 * 192; det7 = src7 * 256; t0 = src0 * 256; t1 = src1 * 256; t2 = src2 * 384; t3 = src3 * 256; det3 = t3; det0 = t0 + t1; det1 = t0 - t1; det2 = t2 - t3; // src0 = det0 + det3; src1 = det1 + det2; src2 = det1 - det2; src3 = det0 - det3; src4 = det6 - det4 - det5 - det7; src5 = det5 - det6 + det7; src6 = det6 - det7; src7 = det7; // p[0][i] = (src0 + src7 + (1 << 12)) >> 13; p[1][i] = (src1 + src6 + (1 << 12)) >> 13; p[2][i] = (src2 + src5 + (1 << 12)) >> 13; p[3][i] = (src3 + src4 + (1 << 12)) >> 13; p[4][i] = (src3 - src4 + (1 << 12)) >> 13; p[5][i] = (src2 - src5 + (1 << 12)) >> 13; p[6][i] = (src1 - src6 + (1 << 12)) >> 13; p[7][i] = (src0 - src7 + (1 << 12)) >> 13; } // for (i = 0; i < 8; i++) { src0 = p[i][0]; src1 = p[i][1]; src2 = p[i][2] - p[i][3]; src3 = p[i][3] + p[i][2]; src4 = p[i][4] - p[i][7]; src6 = p[i][5] - p[i][6]; t0 = p[i][5] + p[i][6]; t1 = p[i][4] + p[i][7]; src5 = t0 - t1; src7 = t0 + t1; // det4 = -src4 * 480 - src6 * 192; det5 = src5 * 384; det6 = src6 * 480 - src4 * 192; det7 = src7 * 256; t0 = src0 * 256; t1 = src1 * 256; t2 = src2 * 384; t3 = src3 * 256; det3 = t3; det0 = t0 + t1; det1 = t0 - t1; det2 = t2 - t3; // src0 = det0 + det3; src1 = det1 + det2; src2 = det1 - det2; src3 = det0 - det3; src4 = det6 - det4 - det5 - det7; src5 = det5 - det6 + det7; src6 = det6 - det7; src7 = det7; // matrix[mindex++] = (src0 + src7 + (1 << 12)) >> 13; matrix[mindex++] = (src1 + src6 + (1 << 12)) >> 13; matrix[mindex++] = (src2 + src5 + (1 << 12)) >> 13; matrix[mindex++] = (src3 + src4 + (1 << 12)) >> 13; matrix[mindex++] = (src3 - src4 + (1 << 12)) >> 13; matrix[mindex++] = (src2 - src5 + (1 << 12)) >> 13; matrix[mindex++] = (src1 - src6 + (1 << 12)) >> 13; matrix[mindex++] = (src0 - src7 + (1 << 12)) >> 13; } } public void decode(InputStream in, PixelArray out) throws Exception { int current, m, i, scan_num = 0, RST_num; int PRED[] = new int[10]; if (in == null) return; x = 0; y = 0; yp = 0; num = 0; current = get16(in); if (current != 0xFFD8) { //SOI error("Not a JPEG file"); return; } current = get16(in); while (current >> 4 != 0x0FFC || current == 0xFFC4) { //SOF 0~15 switch (current) { case 0xFFC4: //DHT HT.get(in); break; case 0xFFCC: //DAC error("Program doesn't support arithmetic coding. (format error)"); return; case 0xFFDB: QT.get(in); break; case 0xFFDD: Ri = readNumber(in); break; case 0xFFE0: case 0xFFE1: case 0xFFE2: case 0xFFE3: case 0xFFE4: case 0xFFE5: case 0xFFE6: case 0xFFE7: case 0xFFE8: case 0xFFE9: case 0xFFEA: case 0xFFEB: case 0xFFEC: case 0xFFED: case 0xFFEE: case 0xFFEF: readApp(in); break; case 0xFFFE: readComment(in); break; default: if (current >> 8 != 0xFF) { error("ERROR: format error! (decode)"); } } current = get16(in); } if (current < 0xFFC0 || current > 0xFFC7) { error("ERROR: could not handle arithmetic code!"); } FH.get(in, current); current = get16(in); // pix = new int[FH.X * FH.Y]; out.setSize(FH.X, FH.Y); do { while (current != 0x0FFDA) { //SOS switch (current) { case 0xFFC4: //DHT HT.get(in); break; case 0xFFCC: //DAC error("Program doesn't support arithmetic coding. (format error)"); case 0xFFDB: QT.get(in); break; case 0xFFDD: Ri = readNumber(in); break; case 0xFFE0: case 0xFFE1: case 0xFFE2: case 0xFFE3: case 0xFFE4: case 0xFFE5: case 0xFFE6: case 0xFFE7: case 0xFFE8: case 0xFFE9: case 0xFFEA: case 0xFFEB: case 0xFFEC: case 0xFFED: case 0xFFEE: case 0xFFEF: readApp(in); break; case 0xFFFE: readComment(in); break; default: if (current >> 8 != 0xFF) { error("ERROR: format error! (Parser.decode)"); } } current = get16(in); } SH.get(in); nComp = (int) SH.Ns; for (i = 0; i < nComp; i++) { int CompN = SH.Comp[i].Cs; qTab[i] = QT.Q[FH.Comp[CompN].Tq]; nBlock[i] = FH.Comp[CompN].V * FH.Comp[CompN].H; dcTab[i] = HuffTab[SH.Comp[i].Td][0]; acTab[i] = HuffTab[SH.Comp[i].Ta][1]; } YH = FH.Comp[1].H; YV = FH.Comp[1].V; Xsize = FH.X; Ysize = FH.Y; scan_num++; m = 0; for (RST_num = 0;; RST_num++) { //Decode one scan int MCU_num; int temp[] = new int[1]; // to store remainded bits int index[] = new int[1]; temp[0] = 0; index[0] = 0; for (i = 0; i < 10; i++) PRED[i] = 0; if (Ri == 0) { current = decode_MCU(in, PRED, temp, index); // 0: correctly decoded // otherwise: MARKER while (current == 0) { m++; output(out); current = decode_MCU(in, PRED, temp, index); } break; //current=MARKER } for (MCU_num = 0; MCU_num < Ri; MCU_num++) { current = decode_MCU(in, PRED, temp, index); output(out); //fprintf(show,"%i ",MCU_num); if (current != 0) break; } if (current == 0) { if (marker_index != 0) { current = (0xFF00 | marker); marker_index = 0; } else current = get16(in); } if (current >= 0xFFD0 && current <= 0xFFD7) { //empty } else break; //current=MARKER } if (current == 0xFFDC && scan_num == 1) { //DNL readNumber(in); current = get16(in); } } while (current != 0xFFD9); } }