summaryrefslogtreecommitdiff
path: root/ip/xjpg_dec.c
diff options
context:
space:
mode:
Diffstat (limited to 'ip/xjpg_dec.c')
-rw-r--r--ip/xjpg_dec.c2838
1 files changed, 2838 insertions, 0 deletions
diff --git a/ip/xjpg_dec.c b/ip/xjpg_dec.c
new file mode 100644
index 0000000..507e11a
--- /dev/null
+++ b/ip/xjpg_dec.c
@@ -0,0 +1,2838 @@
+/* libhpojip -- HP OfficeJet image-processing library. */
+
+/* Copyright (C) 1995-2002 Hewlett-Packard Company
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
+ * NON-INFRINGEMENT. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * In addition, as a special exception, Hewlett-Packard Company
+ * gives permission to link the code of this program with any
+ * version of the OpenSSL library which is distributed under a
+ * license identical to that listed in the included LICENSE.OpenSSL
+ * file, and distribute linked combinations including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * this file, you may extend this exception to your version of the
+ * file, but you are not obligated to do so. If you do not wish to
+ * do so, delete this exception statement from your version.
+ */
+
+/* Original author: Mark Overton and others.
+ *
+ * Ported to Linux by David Paschal.
+ */
+
+/*****************************************************************************\
+ *
+ * xjpg_dec.c - Decodes a JPEG file into a raw gray image
+ *
+ *****************************************************************************
+ *
+ * Name of Global Jump-Table:
+ *
+ * jpgDecodeTbl
+ *
+ * Items in aXformInfo array passed into setXformSpec:
+ *
+ * aXformInfo[IP_JPG_DECODE_OUTPUT_SUBSAMPLED]:
+ * Output only subsampled raw data? 0=no, 1=yes.
+ * aXformInfo[IP_JPG_DECODE_FROM_DENALI]:
+ * Data came from a Denali? 0=no, 1=yes.
+ *
+ * The aXformInfo items above may all be set to 0 for typical JPEG files.
+ *
+ * For Denali, we assume the following:
+ * - Every 8x8 block ends with an EOB
+ * - A slight change in the Huffman tables (no 15-bit code)
+ * - Denali sends us a proprietary short header (APP1 marker)
+ *
+ * Capabilities and Limitations:
+ *
+ * Decodes a standard JPEG file. Also handles JFIF 1.0 (APP0 marker).
+ * Also handles the non-standard short header output by OfficeJet firmware
+ * (APP1 marker). Also handles APP1 markers defined by color fax standard.
+ * Will *not* decode a non-interleaved file; it must be interleaved.
+ * Handles 1-4 components per pixel, and 4 Huffman tables, so SOF1 with
+ * 8 bits/component is okay.
+ *
+ * Default Input Traits, and Output Traits:
+ *
+ * For decoder:
+ *
+ * trait default input output
+ * ------------------- ------------------- ------------------------
+ * iPixelsPerRow ignored based on header
+ * iBitsPerPixel ignored based on header
+ * iComponentsPerPixel ignored based on header
+ * lHorizDPI ignored based on header
+ * lVertDPI ignored based on header
+ * lNumRows ignored based on header
+ * iNumPages passed into output same as default input
+ * iPageNum passed into output same as default input
+ *
+ * Kludges:
+ *
+ * Chromafax and other software inserts fill 0's instead of fill 1's
+ * before a marker, such as the all-important EOI marker. So when
+ * we get a syntax error when parsing those 0's, we do not report
+ * an error if there's a following marker, but simply proceed to
+ * process the marker as usual.
+ *
+ * Chromafax uses an SOF1 instead of the correct SOF0, so we allow
+ * that, and also handle four Huffman tables that SOF1 requires.
+ *
+ * Jan 1998 Mark Overton -- Ported to new software Image Processor
+ * Apr 1996 Mark Overton -- Finished software-only JPEG decoder
+ * Feb 1996 Mark Overton -- initial code
+ *
+\*****************************************************************************/
+
+#include <string.h>
+#include <assert.h>
+
+#include "hpip.h"
+#include "ipdefs.h"
+#include "setjmp.h"
+#include "xjpg_dct.h"
+#include "xjpg_mrk.h"
+
+
+#define DUMP_JPEG 0
+
+#if DUMP_JPEG
+ #include "stdio.h"
+ #include <tchar.h>
+
+ #define DUMP(msg,arg1,arg2,arg3) \
+ _ftprintf(stdout, msg, (int)(arg1), (int)(arg2), (int)(arg3))
+#else
+ #define DUMP(msg,arg1,arg2,arg3)
+#endif
+
+
+#if 0
+ #include "stdio.h"
+ #include <tchar.h>
+ #define PRINT(msg,arg1,arg2) \
+ _ftprintf(stdout, _T("(jpeg) ") msg, (int)arg1, (int)arg2)
+#else
+ #define PRINT(msg,arg1,arg2)
+#endif
+
+
+/*____________________________________________________________________________
+ | |
+ | Constants |
+ |____________________________________________________________________________|
+*/
+
+#define MAX_HUFF_TBLS 4
+
+#define UNEXPECTED_MARKER 1
+#define BAD_MARKER_ID 2
+#define BAD_MARKER_DATA 3
+#define NO_RESTART_MARKER 4
+#define BAD_HUFF_CODE 5
+#define UNEXPECTED_END_OF_DATA 6
+#define NOT_IMPLEMENTED 7
+
+#define MAX_MARKER_LEN 15000 /* large in case marker holds a thumbnail */
+#define MAX_HEADER_SIZE (MAX_MARKER_LEN+2000)
+#define MAX_BLOCKS_IN_MCU 6
+#define MAX_MCU_SIZE (MAX_BLOCKS_IN_MCU*304)
+ /* max encoded MCU size, plus stuff-bytes */
+#define INBUF_NUM_MCUS 2 /* workbuf will be this multiple of max MCU */
+
+#define DC_TBL_INDEX_LEN 9
+#define AC_TBL_INDEX_LEN 12
+
+#define CHECK_VALUE 0x1ce5ca7e
+
+
+
+/*____________________________________________________________________________
+ | |
+ | Instance Variables |
+ |____________________________________________________________________________|
+*/
+
+typedef struct {
+ BYTE size; /* number of bits in the Huff code (code is the index) */
+ BYTE value; /* value that was coded */
+} main_huff_elem_t;
+
+typedef struct {
+ WORD code; /* Huff code to use for the 'value' below */
+ BYTE size; /* number of bits in above Huff 'code' */
+ BYTE value; /* value that was coded */
+} aux_huff_elem_t;
+
+typedef struct {
+ BYTE *index_p;
+ main_huff_elem_t *main_p;
+ aux_huff_elem_t *aux_p;
+} huff_tbl_t;
+
+
+/* Decoding is centered around out_rows_ap. It is indexed by
+ * [color_component_number][row_number].
+ * color_component_number 0 is Y (intensity); mono only has this component.
+ *
+ * Each component in out_rows_ap has a height (# rows) equal to the number of
+ * samples in the MCU, and a width equal to the number of samples in all the
+ * MCUs in a row. That is, pixels are stored in out_rows_ap with NO REPLICATION.
+ * So if a component has sample factors of H and V, it will have 8*V rows and
+ * pixels_in_row*H/max_horiz_samp_fac columns in out_rows_ap.
+ */
+
+typedef struct {
+ BYTE *out_rows_ap[4][32]; /* row-buffers [component][row] */
+
+ /***** Items from SOF, Start Of Frame *****/
+
+ IP_IMAGE_TRAITS traits; /* traits of the image */
+ BYTE num_comps; /* # of components (1 => mono) */
+ BYTE horiz_samp_facs[4]; /* horizontal sampling factors */
+ BYTE vert_samp_facs [4]; /* vertical sampling factors */
+ BYTE max_horiz_samp_fac; /* max sample factors */
+ BYTE max_vert_samp_fac;
+ BYTE which_quant_tbl[4]; /* selects q tbl for component */
+ UINT rows_per_mcu; /* # rows & cols in each MCU */
+ UINT cols_per_mcu;
+ UINT mcus_per_row; /* # of MCUs in each row */
+ UINT rowCountOffset;
+
+ /***** Items from other markers *****/
+
+ WORD restart_interval; /* restart interval (0 -> none) */
+ long quant_tbls[4][64]; /* quantization tables */
+ BYTE which_dc_tbl[4]; /* selects DC tbl for component */
+ BYTE which_ac_tbl[4]; /* selects AC tbl for component */
+ BOOL fColorFax; /* is this from a fax? */
+
+ /***** Huffman tables *****/
+
+ huff_tbl_t dc_tbls[MAX_HUFF_TBLS];
+ huff_tbl_t ac_tbls[MAX_HUFF_TBLS];
+
+ /***** Configuration variables *****/
+
+ BOOL output_subsampled; /* output subsampled data? */
+ BOOL fDenali; /* data is from a Denali? */
+
+ /***** Variables used while decoding *****/
+
+ DWORD dwInNextPos; /* next read pos in input file */
+ DWORD dwOutNextPos; /* next write pos in output file */
+ long rows_done; /* # rows decoded and output */
+ UINT mcus_done; /* # MCUs decoded so far in row */
+ BOOL sending_rows; /* returning the decoded rows? */
+ BOOL got_short_header; /* got an OfficeJet short header? */
+ BOOL got_EOI; /* hit the end-of-image marker? */
+ BYTE restart_cur_marker; /* index of next expected marker */
+ WORD restart_cur_mcu; /* current MCU-count in interval */
+ int prior_dc[4]; /* DC values of prior block */
+ jmp_buf syntax_error; /* jump-target for syntax errors */
+ jmp_buf old_syntax_error;
+ DWORD dwValidChk; /* struct validity check value */
+
+ /***** Reading bits variables *****/
+
+ DWORD rd_bit_buf;
+ /* Bits to be read from inbuf (read left-to-right). */
+
+ int rd_bits_avail;
+ /* Number of bits not yet read in rd_bit_buf (= 32 - number read). */
+
+ BYTE *rd_inbuf_beg;
+ /* The beginning of the input buffer. */
+
+ BYTE *rd_inbuf_next;
+ /* Next byte in inbuf to be read. */
+
+ /***** Decoding 8x8 blocks *****/
+
+ int block[64]; /* scratch-pad 8x8 block */
+ int *block_zz[64+16]; /* zig-zag ptrs into above block */
+
+} JDEC_INST, *PJDEC_INST;
+
+
+
+/*____________________________________________________________________________
+ | |
+ | Forward Routines |
+ |____________________________________________________________________________|
+*/
+
+static void huff_define_table (
+ PJDEC_INST g,
+ BOOL ac, /* defining an AC table? (else DC) */
+ UINT id, /* which table is being defined (0-3) */
+ const BYTE counts[16], /* number of Huffman codes of each length 1-16 */
+ const BYTE values[]); /* values associated with codes of above lengths */
+
+void wino_scale_table (long *tbl_p);
+
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ R E A D I N G
+
+
+ Interface into this section:
+
+ read_init - inits this section
+ read_buf_open - we are being given a (new) input buffer
+ read_buf_close - done with current input buffer; return # bytes used
+ read_byte - returns next input byte (syncs to byte-boundary)
+ read_uint - returns next 2-byte integer (syncs)
+ read_skip_forward - discards the given number of input bytes
+ read_skip_backward - backs up the given number of bytes
+ READ_BITS_LOAD - loads N bits of input into lsb's of a var (no advance)
+ READ_BITS_ADVANCE - advance input N bits; you must call this to eat input
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_init | Inits this section |
+ |___________|________________________________________________________________|
+*/
+static void read_init (PJDEC_INST g)
+{
+ g->rd_bits_avail = 0;
+ g->rd_bit_buf = 0;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_buf_open | We are being given a (new) buffer to read input |
+ |_______________|____________________________________________________________|
+ | |
+ | This routine records the location of the new input buffer. |
+ |____________________________________________________________________________|
+*/
+static void read_buf_open (PJDEC_INST g, BYTE *buf_p)
+{
+ g->rd_inbuf_beg = buf_p;
+ g->rd_inbuf_next = buf_p;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_buf_close | We are done with the current input buffer |
+ |________________|___________________________________________________________|
+ | |
+ | This function returns # bytes read from the input buffer. |
+ |____________________________________________________________________________|
+*/
+static int read_buf_close (PJDEC_INST g)
+{
+ return g->rd_inbuf_next - g->rd_inbuf_beg;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | rd_sync | Empties the bit-cache, and syncs to a byte-boundary |
+ |_________|__________________________________________________________________|
+*/
+static void rd_sync (PJDEC_INST g)
+{
+ g->rd_bits_avail = 0;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_byte | returns next input byte (syncs to byte-boundary) |
+ |___________|________________________________________________________________|
+*/
+static BYTE read_byte (PJDEC_INST g)
+{
+ rd_sync (g);
+ return *(g->rd_inbuf_next)++;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_uint | returns next 2-byte integer (syncs) |
+ |___________|________________________________________________________________|
+*/
+static unsigned read_uint (PJDEC_INST g)
+{
+ UINT uval;
+
+ rd_sync (g);
+ uval = (unsigned)*(g->rd_inbuf_next)++ << 8;
+ return uval | *(g->rd_inbuf_next)++;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_skip_forward | discards the given number of input bytes |
+ |___________________|________________________________________________________|
+*/
+static void read_skip_forward (PJDEC_INST g, UINT n)
+{
+ if (n > MAX_MARKER_LEN)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+ rd_sync (g);
+ g->rd_inbuf_next += n;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | read_skip_backward | backs up N bytes in the input buffer |
+ |____________________|_______________________________________________________|
+*/
+static void read_skip_backward (PJDEC_INST g, UINT n)
+{
+ rd_sync (g);
+ g->rd_inbuf_next -= n;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | READ_BITS_LOAD | loads next par_n_bits of input into par_value (no advance)|
+ |________________|___________________________________________________________|
+ | |
+ | If a marker is encountered: |
+ | - this macro will goto hit_marker |
+ | - the marker will be the next two bytes in the buffer |
+ | - the cache will be empty (ie, any fill 1's were discarded) |
+ | |
+ | If the JPEG file erroneously has fill 0's (instead of 1's) before a |
+ | marker, we'll parse them as Huffman codes. If such a bogus Huffman code |
+ | has more bits than were in our bit-buffer, the extra non-existent bits |
+ | will be returned as zeroes. |
+ |____________________________________________________________________________|
+*/
+
+#define CANT_LOAD_NEAR_MARKER(g) \
+ (g->rd_bits_avail<=0 || \
+ (g->rd_bits_avail<=7 && (((1u<<g->rd_bits_avail)-1) & ~g->rd_bit_buf) == 0))
+ /* we just parsed past erroneous fill 0's OR */
+ /* cached bits are just fill 1's; toss them */
+
+
+#define READ_BITS_LOAD(g, fixed_len, par_n_bits, par_value, hit_marker) \
+{ \
+ if ((int)(par_n_bits) > g->rd_bits_avail) { \
+ BYTE a_byte; \
+ \
+ do { \
+ a_byte = *(g->rd_inbuf_next)++; \
+ DUMP (_T("<%02x>"), a_byte, 0, 0); \
+ \
+ if (a_byte == (BYTE )0xffu) { \
+ if (*(g->rd_inbuf_next)++ != 0) { /* we hit a marker */ \
+ g->rd_inbuf_next -= 2; \
+ if (CANT_LOAD_NEAR_MARKER(g)) \
+ goto hit_marker; \
+ break; /* exit 'while' loop */ \
+ } \
+ } \
+ \
+ g->rd_bit_buf = (g->rd_bit_buf<<8) | a_byte; \
+ g->rd_bits_avail += 8; \
+ } while (g->rd_bits_avail <= 24); \
+ } \
+ \
+ par_value = (g->rd_bit_buf << (32-g->rd_bits_avail)) >> (32-(par_n_bits)); \
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | READ_BITS_ADVANCE | discards next par_n_bits of input |
+ |___________________|________________________________________________________|
+*/
+#define READ_BITS_ADVANCE(g, par_n_bits) \
+{ \
+ g->rd_bits_avail -= par_n_bits; \
+}
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ M A R K E R S
+
+
+ Interface into this section:
+
+ mar_get - parses and returns next marker-id
+ mar_parse - parses the data associated with the marker
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | parse_factors | parses sample-factors as nibbles into array |
+ |_______________|____________________________________________________________|
+ | |
+ | This is only called by parse_app_short_header below. |
+ | Function return value = maximum sample factor. |
+ |____________________________________________________________________________|
+*/
+static UINT parse_factors (
+ UINT factors, /* in: sample factors, one nibble each, l-to-r */
+ BYTE fac_array[4]) /* out: array of sample factors */
+{
+ int i;
+ UINT fac;
+ UINT max_fac;
+
+ max_fac = 0;
+
+ for (i=3; i>=0; i--) {
+ fac = factors & 0x000fu;
+ factors >>= 4;
+ if (fac > max_fac) max_fac = fac;
+ fac_array[i] = fac;
+ }
+
+ return max_fac;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | calc_quant_table | calculates a quantization table |
+ |__________________|_________________________________________________________|
+ | |
+ | This is only called by parse_app_short_header below. |
+ | Warning: The calculation below should match the firmware. |
+ |____________________________________________________________________________|
+*/
+static void calc_quant_table (
+ PJDEC_INST g,
+ UINT dc_q_fac, /* orig DC is scaled by (dc_q_fac/50) */
+ UINT ac_q_fac, /* orig ACs are scaled by (ac_q_fac/50) */
+ const BYTE *orig_tbl_p, /* original table */
+ UINT which_q_tbl) /* which table is being defined (0-3) */
+{
+ int i;
+ UINT quant;
+ long *tbl_p;
+
+ tbl_p = g->quant_tbls[which_q_tbl];
+
+ for (i=0; i<64; i++) {
+ quant = ((*orig_tbl_p++)*(i==0 ? dc_q_fac : ac_q_fac) + 25u) / 50u;
+ if (quant == 0) quant = 1;
+ if (quant > 255) quant = 255;
+ tbl_p[i] = quant;
+ }
+
+ wino_scale_table (tbl_p);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_get | parses and returns next marker-id |
+ |_________|__________________________________________________________________|
+*/
+static UINT mar_get (PJDEC_INST g)
+{
+ UINT marker = 0; /* init to eliminate a compiler warning */
+ BOOL got_ff;
+
+ got_ff = FALSE;
+
+ while (TRUE) {
+ marker = read_byte (g);
+ if (marker == 0xff) got_ff = TRUE;
+ else break;
+ }
+
+ if (!got_ff || marker==0)
+ longjmp (g->syntax_error, BAD_MARKER_ID);
+
+ return marker;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_flush | discards data associated with current marker |
+ |___________|________________________________________________________________|
+*/
+static void mar_flush (PJDEC_INST g, UINT marker)
+{
+ if (marker==MARKER_SOI || marker==MARKER_EOI ||
+ (marker>=MARKER_RST0 && marker<=MARKER_RST7))
+ return; /* marker has no associated segment */
+
+ read_skip_forward (g, read_uint(g) - 2);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | parse_app_jfif | parses a JFIF APP0 marker |
+ |________________|___________________________________________________________|
+ | |
+ | Sets these fields in 'traits': lHorizDPI, lVertDPI |
+ |____________________________________________________________________________|
+*/
+static void parse_app_jfif (PJDEC_INST g)
+{
+ UINT len;
+ BYTE byt;
+ UINT h_dpi, v_dpi;
+
+ len = read_uint (g);
+ byt = read_byte (g);
+ if (! (len==16 && (byt==(BYTE )'J' || byt==(BYTE )'j'))) {
+ /* This is not a JFIF APP-marker, so silently discard it */
+ read_skip_forward (g, len-3);
+ return;
+ }
+
+ read_skip_forward (g,6); /* discard "FIF\0" + 0x01 + 0x00 */
+ byt = read_byte (g);
+ h_dpi = read_uint (g);
+ v_dpi = read_uint (g);
+ read_skip_forward (g,2); /* discard thumbnail X and Y */
+
+ if (byt == 1) { /* 1 means that units are dots/inch */
+ g->traits.lHorizDPI = (DWORD)h_dpi << 16;
+ g->traits.lVertDPI = (DWORD)v_dpi << 16;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | parse_app_g3fax | parses a color fax APP1 marker |
+ |_________________|__________________________________________________________|
+ | |
+ | Can set these fields in 'traits': lHorizDPI, lVertDPI |
+ |____________________________________________________________________________|
+ */
+static void parse_app_g3fax (PJDEC_INST g)
+{
+ int i;
+ UINT len, dpi;
+ BYTE id_ver[8];
+ const BYTE valid_id_ver[8] = {
+ 0x47, 0x33, 0x46, 0x41, 0x58, 0x00, /* "G3FAX" plus a 0 byte */
+ 0x07, 0xca }; /* version is year of std, 1994 */
+
+ len = read_uint (g);
+ if (len != 12) {
+ /* wrong version, or a gamut or illuminant spec which we ignore */
+ read_skip_forward (g, len-2);
+ return;
+ }
+
+ for (i=0; i<8; i++) /* fax id is 6 bytes; version is 2 bytes */
+ id_ver[i] = read_byte (g);
+
+ dpi = read_uint (g);
+
+ if (memcmp(id_ver,valid_id_ver,8) == 0
+ && (dpi==200 || dpi==300 || dpi==400)) {
+ /* everything is valid (whew!), so save dpi */
+ g->traits.lHorizDPI = g->traits.lVertDPI = (long)dpi << 16;
+ g->fColorFax = TRUE;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | parse_app_short_header | An APP1 marker output by OfficeJet firmware |
+ |________________________|___________________________________________________|
+*/
+static void parse_app_short_header (PJDEC_INST g)
+{
+ /* Since the firmware does not supply tables in its header,
+ * the tables used in the firmware are supplied below. */
+
+ static const BYTE orig_lum_quant[64] = {
+ 16, 11, 12, 14, 12, 10, 16, 14,
+ 13, 14, 18, 17, 16, 19, 24, 40,
+ 26, 24, 22, 22, 24, 49, 35, 37,
+ 29, 40, 58, 51, 61, 60, 57, 51,
+ 56, 55, 64, 72, 92, 78, 64, 68,
+ 87, 69, 55, 56, 80, 109, 81, 87,
+ 95, 98, 103, 104, 103, 62, 77, 113,
+ 121, 112, 100, 120, 92, 101, 103, 99
+ };
+
+
+ static const BYTE orig_chrom_quant[64] = {
+ 17, 18, 18, 24, 21, 24, 47, 26,
+ 26, 47, 99, 66, 56, 66, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+ };
+
+ static const BYTE lum_DC_counts[16] = {
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ static const BYTE lum_DC_values[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
+ };
+
+ static const BYTE chrom_DC_counts[16] = {
+ 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ static const BYTE chrom_DC_values[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
+ };
+
+ static const BYTE lum_AC_counts[16] = {
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d
+ };
+
+ static const BYTE lum_AC_counts_Denali[16] = {
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x00, 0x7e
+ /* Above, the [01,7d] in the normal table was changed to [00,7e].
+ * This alteration eliminates the sole 15-bit code, and yields
+ * Huffman codes as follows:
+ * - common codes are 12 bits wide or less,
+ * - uncommon codes are exactly 16 bits wide, and all those codes
+ * start with nine '1' bits, leaving seven bits of useful info.
+ * Denali uses a 4K-entry table for the common codes, and a
+ * quick lookup for the 7-bit leftover codes. So parsing of all
+ * codes is simple and fast.
+ */
+ };
+
+ static const BYTE lum_AC_values[162] = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+ };
+
+ static const BYTE chrom_AC_counts[16] = {
+ 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+ 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77
+ };
+
+ static const BYTE chrom_AC_values[162] = {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+ };
+
+ UINT len;
+ UINT dc_q_fac, ac_q_fac;
+ UINT reserved;
+
+ /***** default items not in the short header *****/
+
+ g->restart_interval = 0;
+
+ g->which_quant_tbl[0] = 0;
+ g->which_quant_tbl[1] = 1;
+ g->which_quant_tbl[2] = 1;
+
+ g->which_dc_tbl[0] = 0;
+ g->which_ac_tbl[0] = 0;
+ g->which_dc_tbl[1] = 1;
+ g->which_ac_tbl[1] = 1;
+ g->which_dc_tbl[2] = 1;
+ g->which_ac_tbl[2] = 1;
+
+ huff_define_table (g, FALSE, 0, lum_DC_counts , lum_DC_values);
+ huff_define_table (g, TRUE , 0, g->fDenali ? lum_AC_counts_Denali
+ : lum_AC_counts, lum_AC_values);
+ huff_define_table (g, FALSE, 1, chrom_DC_counts, chrom_DC_values);
+ huff_define_table (g, TRUE , 1, chrom_AC_counts, chrom_AC_values);
+
+ /***** parse the short header *****/
+
+ len = read_uint (g);
+ if (len != 18)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+
+ g->traits.lNumRows = read_uint (g);
+ g->traits.iPixelsPerRow = read_uint (g);
+ g->traits.lHorizDPI = (long)read_uint(g) << 16;
+ g->traits.lVertDPI = (long)read_uint(g) << 16;
+ ac_q_fac = read_byte (g);
+ g->num_comps = read_byte (g);
+ g->max_horiz_samp_fac = parse_factors (read_uint(g), g->horiz_samp_facs);
+ g->max_vert_samp_fac = parse_factors (read_uint(g), g->vert_samp_facs);
+ dc_q_fac = read_byte (g);
+ reserved = read_byte (g); /* should be 0 */
+
+ g->traits.iComponentsPerPixel = g->num_comps;
+ g->traits.iBitsPerPixel = g->num_comps * 8;
+ if (g->traits.lNumRows == 0)
+ g->traits.lNumRows = -1; /* -1 means 'unknown' */
+ if (dc_q_fac == 0)
+ dc_q_fac = ac_q_fac;
+
+ calc_quant_table (g, dc_q_fac, ac_q_fac, orig_lum_quant, 0);
+ calc_quant_table (g, dc_q_fac, ac_q_fac, orig_chrom_quant, 1);
+
+ g->got_short_header = TRUE;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_app | application-specific marker |
+ |_______________|____________________________________________________________|
+ | |
+ | Can set these fields in 'traits': lHorizDPI, lVertDPI |
+ |____________________________________________________________________________|
+ */
+static void mar_parse_app (PJDEC_INST g, UINT marker)
+{
+ UINT len;
+ BYTE id1, id2, id3;
+
+ len = read_uint (g);
+ if (len <= 5) {
+ /* unknown marker; discard it */
+ read_skip_forward (g, len-2);
+ return;
+ }
+
+ id1 = read_byte (g);
+ id2 = read_byte (g);
+ id3 = read_byte (g);
+ read_skip_backward (g, 5);
+
+ if (marker==MARKER_APP+1 && id1==0x47 && id2==0x33 && id3==0x46) {
+ /* G3 color fax APP1 marker */
+ parse_app_g3fax (g);
+ } else if (marker==MARKER_APP+0 && (id1=='J' || id1=='j')
+ && (id2=='F' || id2=='f') && (id3=='I' || id3=='i')) {
+ /* JFIF APP0 marker for generic JPEG files */
+ parse_app_jfif (g);
+ } else if (marker==MARKER_APP+1 && len==18) {
+ /* assume that APP1 marker is a short header */
+ parse_app_short_header (g);
+ } else {
+ /* unrecognized APP marker; discard it */
+ read_skip_forward (g, len);
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_sof | start of frame |
+ |_______________|____________________________________________________________|
+ | |
+ | Sets these fields in 'traits': lNumRows, iPixelsPerRow, iBitsPerPixel, |
+ | iComponentsPerPixel. |
+ | |
+ | Sets these variables: num_comps (equal to iComponentsPerPixel), |
+ | horiz_samp_facs, vert_samp_facs, which_quant_tbl, |
+ | max_horiz_samp_fac, max_vert_samp_fac |
+ |____________________________________________________________________________|
+*/
+static void mar_parse_sof (PJDEC_INST g, UINT marker)
+{
+ UINT len;
+ UINT uBitsPerComp;
+ UINT comp;
+ BYTE comp_id;
+ BYTE hv_samp;
+ BYTE q_table;
+ BYTE h, v;
+
+ len = read_uint (g);
+ uBitsPerComp = read_byte (g);
+ g->rowCountOffset=g->rd_inbuf_next-g->rd_inbuf_beg;
+ g->traits.lNumRows = read_uint (g);
+ g->traits.iPixelsPerRow = read_uint (g);
+ g->traits.iComponentsPerPixel = g->num_comps = read_byte (g);
+ g->traits.iBitsPerPixel = g->num_comps * uBitsPerComp;
+
+ if (g->traits.lNumRows == 0)
+ g->traits.lNumRows = -1; /* -1 means 'unknown' */
+
+ if (len != (8u + 3u*g->num_comps) || g->num_comps==0)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+
+ /* Below, we also check for SOF1 because Chromafax erroneously outputs it */
+ if ((marker!=MARKER_SOF0 && marker!=MARKER_SOF0+1)
+ || uBitsPerComp!=8 || g->num_comps>4)
+ longjmp (g->syntax_error, NOT_IMPLEMENTED);
+
+ g->max_horiz_samp_fac = 1;
+ g->max_vert_samp_fac = 1;
+
+ #if DUMP_JPEG
+ _ftprintf (stderr, _T("\nSOF marker:\n"));
+ _ftprintf (stderr, _T(" bits per sample = %d\n"), uBitsPerComp);
+ _ftprintf (stderr, _T(" number of rows = %d\n"), g->traits.lNumRows);
+ _ftprintf (stderr, _T(" pixels per row = %d\n"), g->traits.iPixelsPerRow);
+ _ftprintf (stderr, _T(" # components = %d\n"), g->num_comps);
+ #endif
+
+ for (comp=0; comp<g->num_comps; comp++) {
+ comp_id = read_byte (g);
+ hv_samp = read_byte (g);
+ q_table = read_byte (g);
+
+ #if DUMP_JPEG
+ _ftprintf (stderr,
+ _T(" %d: comp id = %d, hv samp fac = %02x, which q = %d\n"),
+ comp, comp_id, hv_samp, q_table);
+ #endif
+
+ g->horiz_samp_facs[comp] = h = hv_samp >> 4;
+ g->vert_samp_facs [comp] = v = hv_samp & 0x0fu;
+ g->which_quant_tbl[comp] = q_table;
+
+ if (h > g->max_horiz_samp_fac) g->max_horiz_samp_fac = h;
+ if (v > g->max_vert_samp_fac ) g->max_vert_samp_fac = v;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_dqt | discrete quantization table |
+ |_______________|____________________________________________________________|
+ | |
+ | Sets the following variables: quant_tbls. |
+ |____________________________________________________________________________|
+*/
+static void mar_parse_dqt (PJDEC_INST g)
+{
+ int len, i;
+ BYTE pt;
+ long *tbl_p;
+
+ len = read_uint(g) - 2;
+
+ while (len >= 65) {
+ len -= 65;
+ pt = read_byte (g);
+ if ((pt & 0xfcu) != 0)
+ longjmp (g->syntax_error, NOT_IMPLEMENTED);
+ tbl_p = g->quant_tbls[pt & 3];
+ DUMP (_T("\nDQT marker: table=%d"), pt & 3, 0, 0);
+ for (i=0; i<64; i++) {
+ if ((i & 15) == 0) DUMP(_T("\n "), 0,0,0);
+ tbl_p[i] = read_byte (g);
+ DUMP (_T("%2d "), tbl_p[i], 0, 0);
+ }
+ DUMP (_T("\n"), 0,0,0);
+ wino_scale_table (tbl_p);
+ }
+
+ if (len != 0)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_dht | define Huffman tables |
+ |_______________|____________________________________________________________|
+ | |
+ | Sets the following variables: dc_tbls, ac_tbls. |
+ |____________________________________________________________________________|
+*/
+static void mar_parse_dht (PJDEC_INST g)
+{
+ BYTE num_codes[16];
+ BYTE values[256];
+
+ int len, i, tot_codes;
+ BYTE class_id;
+
+ len = read_uint(g) - 2;
+
+ while (len > 17) {
+ class_id = read_byte (g);
+
+ for (tot_codes=0, i=0; i<=15; i++) {
+ num_codes[i] = read_byte (g);
+ tot_codes += num_codes[i];
+ }
+
+ len -= 17;
+ if (len < tot_codes)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+
+ for (i=0; i<tot_codes; i++)
+ values[i] = read_byte (g);
+ len -= tot_codes;
+
+ #if DUMP_JPEG
+ _ftprintf (stderr, _T("\nDHT marker: class=%d, id=%d\n counts = "),
+ (BOOL )(class_id>>4), class_id & 0x0f);
+ for (i=0; i<16; i++)
+ _ftprintf (stderr, _T("%2d "), num_codes[i]);
+ _ftprintf (stderr, _T("\n values = "));
+ for (i=0; i<tot_codes; i++)
+ _ftprintf (stderr, _T("%02x "), values[i]);
+ _ftprintf (stderr, _T("\n"));
+ #endif
+
+ huff_define_table (g, (BOOL)(class_id>>4), class_id & 0x0f,
+ num_codes, values);
+ }
+
+ if (len != 0)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_dri | define restart interval |
+ |_______________|____________________________________________________________|
+ | |
+ | Sets the following variable: restart_interval. |
+ |____________________________________________________________________________|
+*/
+static void mar_parse_dri (PJDEC_INST g)
+{
+ UINT len;
+
+ len = read_uint (g);
+ if (len != 4)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+
+ g->restart_interval = read_uint (g);
+ DUMP (_T("\nDRI marker: restart interval = %d\n"), g->restart_interval, 0,0);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_sos | start of scan |
+ |_______________|____________________________________________________________|
+*/
+static void mar_parse_sos (PJDEC_INST g)
+{
+ UINT len;
+ UINT comp;
+ UINT cs;
+ UINT dc_ac;
+
+ len = read_uint (g);
+ if (len != 6u+2u*g->num_comps)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+
+ read_byte (g); /* skip Ns value (number of components in scan) */
+
+ DUMP (_T("\nSOS marker:\n"), 0,0,0);
+
+ for (comp=0; comp<g->num_comps; comp++) {
+ cs = read_byte (g); /* skip Cs value (component selector) */
+ dc_ac = read_byte (g);
+ DUMP (_T(" %d: cs = %d, which dc_ac tbl = %02x\n"), comp, cs, dc_ac);
+ g->which_dc_tbl[comp] = dc_ac >> 4;
+ g->which_ac_tbl[comp] = dc_ac & 0x0fu;
+ }
+
+ read_byte (g); /* skip Ss value (start selection) */
+ read_byte (g); /* skip Se value (end selection) */
+ read_byte (g); /* skip AhAl value (approximation bit positions) */
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse_dnl | Define Number of Lines |
+ |_______________|____________________________________________________________|
+ | |
+ | Sets the following variable: traits.lNumRows |
+ |____________________________________________________________________________|
+*/
+static void mar_parse_dnl (PJDEC_INST g)
+{
+ UINT len, nRows;
+
+ len = read_uint (g);
+ nRows = read_uint (g);
+
+ if (len!=4u || nRows==0)
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+
+ DUMP (_T("\nDNL marker: %d\n"), nRows,0,0);
+ g->traits.lNumRows = nRows;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | mar_parse | parses the marker, storing results in global variables |
+ |___________|________________________________________________________________|
+*/
+static void mar_parse (PJDEC_INST g, UINT marker)
+{
+ PRINT (_T("mar_parse: marker = %02xh\n"), marker, 0);
+
+ switch (marker)
+ {
+ case MARKER_APP+0:
+ case MARKER_APP+1:
+ case MARKER_APP+2:
+ case MARKER_APP+3:
+ case MARKER_APP+4:
+ case MARKER_APP+5:
+ case MARKER_APP+6:
+ case MARKER_APP+7:
+ case MARKER_APP+8:
+ case MARKER_APP+9:
+ case MARKER_APP+10:
+ case MARKER_APP+11:
+ case MARKER_APP+12:
+ case MARKER_APP+13:
+ case MARKER_APP+14:
+ case MARKER_APP+15:
+ mar_parse_app (g, marker);
+ break;
+
+ case MARKER_COM: /* comment marker */
+ case MARKER_JPG+0:
+ case MARKER_JPG+1:
+ case MARKER_JPG+2:
+ case MARKER_JPG+3:
+ case MARKER_JPG+4:
+ case MARKER_JPG+5:
+ case MARKER_JPG+6:
+ case MARKER_JPG+7:
+ case MARKER_JPG+8:
+ case MARKER_JPG+9:
+ case MARKER_JPG+10:
+ case MARKER_JPG+11:
+ case MARKER_JPG+12:
+ case MARKER_JPG+13:
+ mar_flush (g, marker);
+ break;
+
+ case MARKER_SOF0:
+ case MARKER_SOF1:
+ case MARKER_SOF2:
+ case MARKER_SOF3:
+ case MARKER_SOF5:
+ case MARKER_SOF6:
+ case MARKER_SOF7:
+ case MARKER_SOF8:
+ case MARKER_SOF9:
+ case MARKER_SOFA:
+ case MARKER_SOFB:
+ case MARKER_SOFD:
+ case MARKER_SOFE:
+ case MARKER_SOFF:
+ mar_parse_sof (g, marker);
+ break;
+
+ case MARKER_RST0:
+ case MARKER_RST1:
+ case MARKER_RST2:
+ case MARKER_RST3:
+ case MARKER_RST4:
+ case MARKER_RST5:
+ case MARKER_RST6:
+ case MARKER_RST7:
+ DUMP (_T("\nRST marker.\n"), 0,0,0);
+ break;
+
+ case MARKER_DHT: mar_parse_dht (g); break;
+ case MARKER_DQT: mar_parse_dqt (g); break;
+ case MARKER_DRI: mar_parse_dri (g); break;
+ case MARKER_SOS: mar_parse_sos (g); break;
+ case MARKER_DNL: mar_parse_dnl (g); break;
+
+ case MARKER_DAC:
+ case MARKER_DHP:
+ case MARKER_EXP:
+ longjmp (g->syntax_error, NOT_IMPLEMENTED);
+ break;
+
+ /* The following markers have no data following them */
+
+ case MARKER_SOI:
+ DUMP (_T("\nSOI marker.\n"), 0,0,0);
+ break;
+
+ case MARKER_EOI:
+ DUMP (_T("\nEOI marker.\n"), 0,0,0);
+ break;
+
+ default:
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+ }
+}
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ H U F F M A N
+
+
+ Interface into this section:
+
+ huff_init - inits this section
+ huff_free_tbl - deallocates memory for one table
+ huff_free_all - deallocates memory for all tables
+ huff_define_table - defines a new Huffman table
+ DECODE_HUFF - decodes and returns next Huffman code
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | DECODE_HUFF | Decodes a Huffman code, returning corresponding value |
+ |_____________|______________________________________________________________|
+*/
+#define DECODE_HUFF( \
+ g, \
+ huff_tbl_p, \
+ main_ix_len, \
+ par_result, \
+ hit_marker) \
+{ \
+ UINT tbl_index, code, size; \
+ main_huff_elem_t *elem; \
+ \
+ READ_BITS_LOAD (g, FALSE, main_ix_len, code, hit_marker) \
+ tbl_index = huff_tbl_p->index_p[code]; \
+ elem = &(huff_tbl_p->main_p[tbl_index]); \
+ par_result = elem->value; \
+ size = elem->size; \
+ \
+ if (size == 0) { \
+ par_result = parse_aux_code (g, huff_tbl_p->aux_p); \
+ } else { \
+ DUMP (_T(" %2d-%04x-%3d(main) "), size, code, par_result); \
+ READ_BITS_ADVANCE (g, size) \
+ } \
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | parse_aux_code | Code is not in short-width table; look in aux table |
+ |________________|___________________________________________________________|
+ | |
+ | Returns the value associated with the code. |
+ |____________________________________________________________________________|
+*/
+static UINT parse_aux_code (
+ PJDEC_INST g,
+ aux_huff_elem_t *aux_tbl_par_p)
+{
+ UINT code, size, val;
+ UINT diff;
+ UINT excess;
+ aux_huff_elem_t *lo_p, *hi_p, *mid_p;
+
+ READ_BITS_LOAD (g, FALSE, 16, code, syntax_err)
+
+#if 0 /* we are no longer using ROM tables */
+ if ((BYTE *)aux_tbl_par_p == dec_AC_aux_tbl)
+ {
+ /* We are using our default ROM table */
+ val = dec_AC_aux_tbl [code & 0x7f];
+ DUMP (_T(" %2d-%4x-%3d(aux-rom) "), 16, code, val);
+ if (val==0 || (code & 0xff80)!=0xff80) goto syntax_err;
+ READ_BITS_ADVANCE (g,16)
+ }
+#endif
+
+ lo_p = aux_tbl_par_p;
+ hi_p = lo_p + lo_p->size - 1;
+ lo_p += 1; /* 1st table-entry is a dummy containing above table-size */
+
+ while ((diff=(hi_p-lo_p)) > 1) {
+ mid_p = lo_p + (diff>>1);
+ if (mid_p->code > code) hi_p = mid_p;
+ else lo_p = mid_p;
+ }
+
+ size = lo_p->size;
+ excess = 16u - size;
+ if ((code>>excess) != (UINT)(lo_p->code>>excess)) {
+ lo_p = hi_p;
+ size = lo_p->size;
+ excess = 16u - size;
+ if ((code>>excess) != (UINT)(lo_p->code>>excess)) {
+ PRINT (_T("aux code of %x not found\n"), code, 0);
+ goto syntax_err;
+ }
+ }
+
+ val = lo_p->value;
+ READ_BITS_ADVANCE (g,size)
+ DUMP (_T(" %2d-%4x-%3d(aux) "), size, code, val);
+
+ return val;
+
+ syntax_err:
+ PRINT (_T("parse_aux_code: syntax error\n"), 0, 0);
+ longjmp (g->syntax_error, BAD_HUFF_CODE);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | huff_init | Inits this section |
+ |___________|________________________________________________________________|
+*/
+static void huff_init (PJDEC_INST g)
+{
+ memset (g->dc_tbls, 0, sizeof(g->dc_tbls));
+ memset (g->ac_tbls, 0, sizeof(g->ac_tbls));
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | huff_free_tbl | Frees memory allocated for the given table |
+ |_______________|____________________________________________________________|
+*/
+static void huff_free_tbl (PJDEC_INST g, huff_tbl_t *tbl_p)
+{
+ if (tbl_p->index_p != NULL)
+ IP_MEM_FREE (tbl_p->index_p);
+ if (tbl_p->main_p != NULL)
+ IP_MEM_FREE (tbl_p->main_p);
+ if (tbl_p->aux_p != NULL)
+ IP_MEM_FREE (tbl_p->aux_p);
+
+ tbl_p->index_p = NULL;
+ tbl_p->main_p = NULL;
+ tbl_p->aux_p = NULL;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | huff_free_all | Frees all memory allocated for Huffman tables |
+ |_______________|____________________________________________________________|
+*/
+static void huff_free_all (PJDEC_INST g)
+{
+ int i;
+
+ for (i=0; i<MAX_HUFF_TBLS; i++) {
+ huff_free_tbl (g, &(g->dc_tbls[i]));
+ huff_free_tbl (g, &(g->ac_tbls[i]));
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | calc_table | Defines a Huffman table |
+ |____________|_______________________________________________________________|
+*/
+static void calc_table (
+ const BYTE counts[16], /* in: # Huffman codes of each length 1-16 */
+ const BYTE huffval[], /* in: values for codes of above lengths */
+ UINT main_ix_len, /* in: # bits in main tbl index (0=use max) */
+ huff_tbl_t *huff_tbl_p) /* out: the three tables */
+{
+ BYTE huffsize[257];
+ WORD huffcode[257];
+ int tot_codes;
+ int i;
+ BYTE *index_p;
+ main_huff_elem_t *main_p;
+ aux_huff_elem_t *aux_p;
+
+ /***************************************************/
+ /* Compute a complete Huffman table. */
+ /* output: huffval, huffsize, huffcode, tot_codes */
+ /***************************************************/
+
+ {
+ int i, j, k, code, siz;
+
+ /* Generate size array -- see JPEG document
+ *
+ * Note that list BITS in JPEG doc. has index from 1-16, but this list
+ * is called 'counts', indexed 0-15. This thus BITS[i] is replaced
+ * by counts[i-1]
+ */
+ tot_codes = 0;
+ for (i=1; i<=16; i++)
+ for (j=1; j<=counts[i-1]; j++)
+ huffsize[tot_codes++] = i;
+
+ huffsize[tot_codes] = 0;
+
+ #if 0 /* we now only use RAM tables */
+ if (memcmp(counts, rom_counts, 16) == 0 &&
+ memcmp(huffval, rom_val, tot_codes) == 0) {
+ PRINT (_T("calc_table: using ROM Huffman tables\n"), 0, 0);
+ return FALSE; /* tell caller to use ROM-tables instead */
+ }
+ #endif
+
+ /* Generate code array -- see JPEG document
+ *
+ * The resulting table is sorted by increasing 'code', and also by
+ * increasing 'size'.
+ */
+ k = 0;
+ code = 0;
+ siz = huffsize[0];
+ while (TRUE) {
+ do {
+ huffcode[k++] = code++;
+ } while (huffsize[k]==siz && k<257); /* Overflow Detection */
+ if (huffsize[k] == 0)
+ break; /* all done */
+ do { /* Shift next code to expand prefix */
+ code <<= 1;
+ siz += 1;
+ } while (huffsize[k] != siz);
+ }
+ }
+
+ /****************************************/
+ /* Make the main table (output: main_p) */
+ /****************************************/
+
+ { /* This "main" table is indexed by the output of the "table table",
+ * which is indexed by 'main_ix_len' bits of input.
+ * If the table-entry has a 'size' of 0, the aux table is examined.
+ */
+ int i, nbytes;
+ int extra_bits;
+ UINT first, final, code_plus_junk;
+
+ if (main_ix_len == 0)
+ main_ix_len = huffsize[tot_codes-1];
+
+ nbytes = (tot_codes+1) * sizeof(main_huff_elem_t);
+ IP_MEM_ALLOC (nbytes, main_p);
+ memset (main_p, 0, nbytes);
+
+ nbytes = 1lu << main_ix_len;
+ IP_MEM_ALLOC (nbytes, index_p);
+ memset (index_p, 0, nbytes);
+
+ for (i=0; i<tot_codes && huffsize[i]<=main_ix_len; i++) {
+ main_p[i+1].value = huffval [i];
+ main_p[i+1].size = huffsize[i] ;
+
+ extra_bits = main_ix_len - huffsize[i];
+ first = huffcode[i] << extra_bits;
+ final = first + (1lu << extra_bits) - 1;
+ for (code_plus_junk = first;
+ code_plus_junk <= final;
+ code_plus_junk++)
+ index_p[code_plus_junk] = i+1;
+ }
+ }
+
+ /********************************************/
+ /* Make the auxiliary table (output: aux_p) */
+ /********************************************/
+
+ { /* This is used when an entry in the main table was 0, meaning that
+ * the code is longer than 'main_ix_len'. The aux table consists of
+ * all [code, size, value] triples for sizes > main_ix_len. A binary
+ * search is used to locate the code.
+ * The first table-entry is a dummy whose 'size' field is the number
+ * of table-entries (including the dummy).
+ */
+ int first, n_entries;
+ aux_huff_elem_t *p;
+
+ /* locate first huffsize > main_ix_len */
+ for (first=0; first<tot_codes && huffsize[first]<=main_ix_len; first++);
+
+ if (first == tot_codes) {
+ /* the main table captured everything; no aux table is needed */
+ IP_MEM_ALLOC (1, aux_p);
+ } else {
+ n_entries = tot_codes - first + 1; /* +1 because of dummy entry */
+ IP_MEM_ALLOC (n_entries * sizeof(aux_huff_elem_t), aux_p);
+
+ /* fill-in the dummy entry (contains # entries in table) */
+ p = aux_p;
+ p->size = (UINT) n_entries;
+ p->code = p->value = 0;
+ p += 1;
+
+ for (i=first; i<tot_codes; i++) {
+ p->size = huffsize[i];
+ p->code = huffcode[i] << (16u - p->size);
+ p->value = huffval [i];
+ p += 1;
+ }
+ }
+ }
+
+ #if DUMP_JPEG
+ {
+ int i, n;
+
+ _ftprintf (stderr, _T("\nOriginal size-code-val tuples:\n"));
+ for (i=0; i<tot_codes; i++) {
+ if ((i&7) == 0) _ftprintf(stderr, _T(" "));
+ _ftprintf (stderr, _T("%2d-%04x-%02x "),
+ huffsize[i], huffcode[i], huffval[i]);
+ if ((i&7)==7 || i==tot_codes-1) _ftprintf(stderr, _T("\n"));
+ }
+
+ _ftprintf(stderr, _T("\nIndex table: (%d entries)\n"), 1lu<<main_ix_len);
+ for (i=0; i<(1lu<<main_ix_len); i++) {
+ if ((i&7) == 0) _ftprintf(stderr, _T(" %3d: "), i);
+ _ftprintf (stderr, _T("%3d, "), index_p[i]);
+ if ((i&7) == 7) _ftprintf(stderr, _T("\n"));
+ }
+
+ _ftprintf(stderr, _T("\nMain table: (%d entries)\n"), tot_codes+1);
+ for (i=0; i<tot_codes; i++) {
+ if ((i&7) == 0) _ftprintf(stderr, _T(" %3d: "), i);
+ _ftprintf (stderr, _T("%04x(%2d) "), main_p[i].value, main_p[i].size);
+ if ((i&7)==7 || i==tot_codes-1) _ftprintf(stderr, _T("\n"));
+ }
+
+ if (huffsize[tot_codes-1] > main_ix_len) {
+ n = aux_p[0].size;
+ _ftprintf(stderr, _T("\nAux table: (%d entries of size-code-value)\n"),n);
+ for (i=0; i<n; i++) {
+ if ((i&3) == 0) _ftprintf(stderr, _T(" %3d: "), i);
+ _ftprintf (stderr, _T("%2d-%4x-%3d "),
+ aux_p[i].size, aux_p[i].code, aux_p[i].value);
+ if ((i&3)==3 || i==n-1) _ftprintf(stderr, _T("\n"));
+ }
+ }
+ }
+ #endif
+
+ huff_tbl_p->index_p = index_p;
+ huff_tbl_p->main_p = main_p;
+ huff_tbl_p->aux_p = aux_p;
+ return;
+
+ fatal_error:
+ assert (0); /* todo: eliminate this assert */
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | huff_define_table | Defines the given Huffman table |
+ |___________________|________________________________________________________|
+ | |
+ | Sets the following variables: dc_tbls, ac_tbls. |
+ |____________________________________________________________________________|
+*/
+static void huff_define_table (
+ PJDEC_INST g,
+ BOOL ac, /* defining an AC table? (else DC) */
+ UINT id, /* which table is being defined (0-3) */
+ const BYTE counts[16], /* number of Huffman codes of each length 1-16 */
+ const BYTE values[]) /* values associated with codes of above lengths */
+{
+ huff_tbl_t *tbl_p;
+
+ tbl_p = ac ? &(g->ac_tbls[id]) : &(g->dc_tbls[id]);
+ huff_free_tbl (g,tbl_p);
+
+ DUMP (_T("\nhuff_define_table: ac=%d, id=%d\n"), ac, id, 0);
+ calc_table (counts, values,
+ ac ? AC_TBL_INDEX_LEN : DC_TBL_INDEX_LEN,
+ tbl_p);
+}
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ W I N O G R A D
+
+
+ Interface into this section:
+
+ QNORM_TO_INPUT - adjusts precision of scaled DCT value for wino-input
+ INPUT_PRECISION - scales result of wino_inverse_dct back to pixels
+ wino_scale_table - scale a quantization table into a Winograd table
+ wino_inverse_dct - computes inverse DCT using Winograd's algorithm
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+#define SHIFT_TRUNC(mvalue,mshift) ((mvalue) >> (mshift))
+
+#define QNORM_TO_INPUT(mval) SHIFT_TRUNC(mval, QNORM_PRECISION-INPUT_PRECISION)
+
+#define QNORM_PRECISION 16 /* prec of q-table scaled by Wino norm constants */
+#define INPUT_PRECISION 5 /* prec of input to inverse-DCT */
+#define CONST_PRECISION 9 /* prec of b1-b5 below */
+
+#define b1 724L
+#define b2 1338L
+#define b3 724L
+#define b4 554L
+#define b5 392L
+
+#if 0
+#define CONST_PRECISION 15
+
+#define b1 46341L
+#define b2 85627L
+#define b3 46341L
+#define b4 35468L
+#define b5 25080L
+#endif
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | wino_scale_table | Scales a quantization table into a Winograd table |
+ |__________________|_________________________________________________________|
+ | |
+ | Multiplies all the components of the Quantization matrix by the fractional |
+ | normalization constants as required by the Winograd Transform. The |
+ | results are fixed-point with QNORM_PRECISION bits of fraction. |
+ |____________________________________________________________________________|
+*/
+
+static const float inv_dct_norm[] = {
+ 0.125000f, 0.173380f, 0.173380f, 0.163320f,
+ 0.240485f, 0.163320f, 0.146984f, 0.226532f,
+ 0.226532f, 0.146984f, 0.125000f, 0.203873f,
+ 0.213388f, 0.203873f, 0.125000f, 0.098212f,
+ 0.173380f, 0.192044f, 0.192044f, 0.173380f,
+ 0.098212f, 0.067650f, 0.136224f, 0.163320f,
+ 0.172835f, 0.163320f, 0.136224f, 0.067650f,
+ 0.034566f, 0.093833f, 0.128320f, 0.146984f,
+ 0.146984f, 0.128320f, 0.093833f, 0.034566f,
+ 0.047944f, 0.088388f, 0.115485f, 0.125000f,
+ 0.115485f, 0.088388f, 0.047944f, 0.045162f,
+ 0.079547f, 0.098212f, 0.098212f, 0.079547f,
+ 0.045162f, 0.040645f, 0.067650f, 0.077165f,
+ 0.067650f, 0.040645f, 0.034566f, 0.053152f,
+ 0.053152f, 0.034566f, 0.027158f, 0.036612f,
+ 0.027158f, 0.018707f, 0.018707f, 0.009558f
+};
+
+void wino_scale_table (
+ long *tbl_p)
+{
+ const float *fptr;
+ int i;
+
+ fptr = inv_dct_norm;
+ for (i=0; i<64; i++) {
+ *tbl_p = (long ) ((*tbl_p) * (*fptr++) * (1l<<QNORM_PRECISION) + 0.5);
+ tbl_p += 1;
+ }
+}
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ D E C O D I N G
+
+
+ Interface into this section:
+
+ zero_prior_DC - sets the predicted DC values to zero
+ decode_MCU - decodes a single Minimum Coded Unit
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+static BYTE const zigzag_index_tbl[] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* extra 16 elements in case */
+ 0, 0, 0, 0, 0, 0, 0, 0 /* parse_block overruns */
+};
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | decode_init | inits this section |
+ |_____________|______________________________________________________________|
+*/
+static void decode_init (PJDEC_INST g)
+{
+ BYTE const *zig_p;
+ int **block_pp;
+
+ zig_p = zigzag_index_tbl;
+ for (block_pp=g->block_zz; block_pp<g->block_zz+(64+16); block_pp++)
+ *block_pp = &(g->block[*zig_p++]);
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | zero_prior_DC | zeroes the predicted DC values |
+ |_______________|____________________________________________________________|
+*/
+static void zero_prior_DC (PJDEC_INST g)
+{
+ g->prior_dc[0] = g->prior_dc[1] = g->prior_dc[2] = g->prior_dc[3] = 0;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | parse_block | parses an 8x8 block; return data is ready for inverse DCT |
+ |_____________|______________________________________________________________|
+ | |
+ | Return value: TRUE = we parsed a block, |
+ | FALSE = hit a marker. |
+ | Output data is put in 'block' array. |
+ |____________________________________________________________________________|
+*/
+static BOOL parse_block (
+ PJDEC_INST g,
+ int comp) /* in: image component number */
+{
+ /* FIX_TERM - changes a term (fetched from JPEG file) into an integer.
+ * The term is in ones-complement, with the sign-bit (and higher bits)
+ * zeroed. So the leftmost bit within the given size is the opposite of
+ * the desired sign bit. If that bit is 1, the number is positive, and
+ * needs no change. If it's 0, we set the higher bits to 1s, and add 1
+ * to convert from ones-complement to twos-complement.
+ * Select the macro below which is fastest on your computer.
+ */
+
+ #if 1
+ #define FIX_TERM(msize,mterm) { \
+ if ((mterm & (1u<<((msize)-1))) == 0) \
+ mterm = (mterm | (-1 << (msize))) + 1; \
+ }
+ #endif
+
+ #if 0
+ #define FIX_TERM(msize,mterm) { \
+ int mask = -1 << msize; \
+ if (((mterm<<1) & mask) == 0) \
+ mterm += mask + 1; \
+ }
+ #endif
+
+ #if 0
+ #define FIX_TERM(msize,mterm) \
+ mterm += ((mterm>>(msize-1)) - 1) & ~((1<<msize) - 2);
+ #endif
+
+ huff_tbl_t *huff_p;
+ int **block_p;
+ long *dequant_p;
+ UINT siz, run, rl_byte;
+ int dc, ac;
+
+ /* memset (block, 0, 64*sizeof(int)); */
+ {
+ int *block_p, *after_p;
+
+ for (block_p=g->block, after_p=g->block+64; block_p<after_p; ) {
+ *block_p++ = 0;
+ *block_p++ = 0;
+ *block_p++ = 0;
+ *block_p++ = 0;
+ *block_p++ = 0;
+ *block_p++ = 0;
+ *block_p++ = 0;
+ *block_p++ = 0;
+ }
+ }
+
+ dequant_p = g->quant_tbls[g->which_quant_tbl[comp]];
+ block_p = g->block_zz;
+
+ /**************************************/
+ /* Decode and dequantize the DC value */
+ /**************************************/
+
+ DUMP (_T("\nStart of block for component %d:\n"), comp, 0, 0);
+
+ huff_p = &(g->dc_tbls[g->which_dc_tbl[comp]]);
+ DECODE_HUFF (g, huff_p, DC_TBL_INDEX_LEN, siz, hit_marker)
+
+ if (siz == 0) {
+ DUMP (_T("dc=0, size of dc=0\n"), 0,0,0);
+ dc = 0;
+ } else {
+ READ_BITS_LOAD (g, TRUE, siz, dc, syntax_err)
+ READ_BITS_ADVANCE (g, siz)
+ DUMP (_T("dc=%x, size of dc=%d\n"), dc, siz, 0);
+ FIX_TERM (siz, dc)
+ }
+
+ dc += g->prior_dc[comp];
+ g->prior_dc[comp] = dc;
+ *(*block_p++) = QNORM_TO_INPUT ((long )*dequant_p++ * dc);
+
+ /*************************************************/
+ /* Decode, dezigzag and dequantize the AC values */
+ /*************************************************/
+
+ huff_p = &(g->ac_tbls[g->which_ac_tbl[comp]]);
+
+ /* The two 'hit_marker's below should be 'syntax_error' instead. But
+ * Chromafax and other software erroneously uses fill 0's instead
+ * of fill 1's, so we parse a few of those 0's before hitting the
+ * marker.
+ */
+
+ while (TRUE) {
+ DECODE_HUFF (g, huff_p, AC_TBL_INDEX_LEN, rl_byte, hit_marker);
+ run = rl_byte >> 4;
+ siz = rl_byte & 0x0f;
+ DUMP (_T("rlc: run=%d, size of ac=%d"), run, siz, 0);
+
+ if (siz == 0) {
+ if (run == 15) {
+ DUMP (_T(", run of 16\n"), 0,0,0);
+ block_p += 16;
+ dequant_p += 16;
+ } else if (run == 0) {
+ DUMP (_T(", EOB\n"), 0,0,0);
+ break; /* hit EOB */
+ } else
+ goto syntax_err;
+ } else {
+ block_p += run;
+ dequant_p += run;
+ READ_BITS_LOAD (g, TRUE, siz, ac, hit_marker);
+ READ_BITS_ADVANCE (g, siz);
+ DUMP (_T(", ac=%x\n"), ac, siz, 0);
+ FIX_TERM (siz, ac);
+ *(*block_p++) = QNORM_TO_INPUT ((long )*dequant_p++ * ac);
+ }
+
+ if (block_p >= g->block_zz+64) {
+ if (block_p > g->block_zz+64) {
+ PRINT(_T("parse_block: over 63 AC terms\n"), 0,0);
+ goto syntax_err;
+ }
+ if (! g->fDenali)
+ break; /* 63rd AC term was non-zero */
+ }
+ }
+
+ return TRUE;
+
+ syntax_err:
+ PRINT(_T("parse_block: syntax error\n"), 0,0);
+ longjmp (g->syntax_error, BAD_HUFF_CODE);
+
+ hit_marker:
+ return FALSE;
+
+ #undef FIX_TERM
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | handleMarkerInStream | handles a marker in the data-stream |
+ |______________________|_____________________________________________________|
+ | |
+ | Parses EOI, DNL and RST; other markers cause an error (longjmp). |
+ | For an EOI, g->got_EOI is set to true. |
+ |____________________________________________________________________________|
+*/
+static void handleMarkerInStream (PJDEC_INST g)
+{
+ BYTE marker;
+
+ marker = mar_get(g);
+
+ if (marker == MARKER_EOI) {
+ PRINT (_T("handleMarkerInStream: parsed EOI\n"), 0, 0);
+ g->got_EOI = TRUE;
+ } else if (marker == MARKER_DNL) {
+ PRINT (_T("handleMarkerInStream: parsing DNL\n"), 0, 0);
+ mar_parse_dnl (g);
+ } else if (g->restart_interval > 0
+ && g->restart_cur_mcu == g->restart_interval
+ && (marker-MARKER_RST0) == g->restart_cur_marker)
+ {
+ /* it's a restart, and we expected it at this point in the data */
+ PRINT (_T("handleMarkerInStream: parsed expected RST\n"), 0, 0);
+ g->restart_cur_marker = (g->restart_cur_marker+1) & 7;
+ g->restart_cur_mcu = 0;
+ zero_prior_DC (g);
+ } else {
+ PRINT (_T("handleMarkerInStream: illegal marker=0x%2.2X\n"), marker, 0);
+ longjmp (g->syntax_error, BAD_MARKER_DATA);
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | LevelShiftAndRound | Level-shifts, rounds, and outputs pixels in 0..255 |
+ |____________________|_______________________________________________________|
+*/
+static void LevelShiftAndRound (int *inBlock_p, BYTE *outBlock_p)
+{
+ BYTE *outAfter;
+ int pixel;
+
+ for (outAfter = outBlock_p + 64;
+ outBlock_p < outAfter;
+ outBlock_p++, inBlock_p++)
+ {
+ pixel = (*inBlock_p +
+ ((1<<(INPUT_PRECISION-1)) + (128<<INPUT_PRECISION)))
+ >> INPUT_PRECISION;
+ if (pixel>>8 != 0)
+ pixel = pixel>0 ? 255 : 0; /* clamp to 0 or 255 */
+ *outBlock_p = (BYTE) pixel;
+ }
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | decode_MCU | Parses a Minimum Coded Unit, and loads pixels into out_rows_ap|
+ |____________|_______________________________________________________________|
+ | |
+ | The pixels are loaded starting at mcus_done (not incremented). |
+ | This routine handles the restart interval logic, and markers. |
+ | |
+ | Returns TRUE if an MCU was parsed, else FALSE. |
+ |____________________________________________________________________________|
+*/
+static BOOL decode_MCU (PJDEC_INST g)
+{
+ BYTE baPixels[256];
+ BYTE *pPixel;
+ int comp;
+ int h_block, v_block;
+ int ul_row, ul_col;
+ int row;
+ BYTE **row_pp;
+ BYTE *row_p;
+
+ for (comp=0; comp<g->num_comps; comp++) {
+ for (v_block=0; v_block<g->vert_samp_facs[comp]; v_block++) {
+ for (h_block=0; h_block<g->horiz_samp_facs[comp]; h_block++) {
+
+ /***** parse and inverse-dct an 8x8 block *****/
+
+ while (! parse_block(g,comp)) {
+ /* we hit a marker */
+ #if 0
+ /* The error-check below is commented-out to make us
+ * more forgiving of unexpected in-data markers, which
+ * we saw the Genoa color-fax test suite output at the
+ * end of the file.
+ */
+ if (comp>0 || v_block>0 || h_block>0)
+ longjmp (g->syntax_error, UNEXPECTED_MARKER);
+ #endif
+ handleMarkerInStream(g);
+ if (g->got_EOI)
+ return FALSE; /* we're out of data; cannot proceed */
+ }
+
+ dct_inverse (g->block);
+
+ /***** compute output pixels *****/
+
+ LevelShiftAndRound (g->block, baPixels);
+
+ /***** copy block into out_rows_ap *****/
+
+ ul_row = v_block*8;
+ ul_col = (g->mcus_done*g->horiz_samp_facs[comp] + h_block) * 8;
+ row_pp = &(g->out_rows_ap[comp][ul_row]);
+ pPixel = baPixels;
+
+ for (row=0; row<8; row++) {
+ row_p = *row_pp++ + ul_col;
+ /* copy the 8 pixel row quickly, using two dword transfers */
+ *(DWORD*) row_p = *(DWORD*) pPixel;
+ *(DWORD*)(row_p+4) = *(DWORD*)(pPixel+4);
+ pPixel += 8;
+ }
+ }
+ }
+ }
+
+ if (g->restart_interval>0 && g->restart_cur_mcu==g->restart_interval)
+ longjmp (g->syntax_error, NO_RESTART_MARKER);
+ g->restart_cur_mcu += 1;
+
+ return TRUE;
+}
+
+
+
+/*____________________________________________________________________________
+ | | |
+ | copy_out_rows | copies a row (or rows) from out_rows_ap to output buffer |
+ |_______________|____________________________________________________________|
+ | |
+ | If output_subsampled is true, we output row data in the same odd order |
+ | which the ASIC outputs it. |
+ | |
+ | View a period as being a group of max_horiz_samp_fac by max_vert_samp_fac |
+ | samples. (BTW, an MCU contains exactly 8x8 periods.) Divide the entire |
+ | image into a grid of such periods. The ASIC outputs the periods left to |
+ | right, top to bottom. It outputs all the data in each period, before |
+ | moving to the next period. Within a period, it outputs the components in |
+ | succession; within a component, it outputs the samples left to right, top |
+ | to bottom. |
+ | |
+ | For example: |
+ | Three components = Y U V |
+ | Horiz sample factors = 2 1 1 |
+ | Vert sample factors = 2 1 1 |
+ | A period is 2x2 samples (i.e., a 2x2 square). |
+ | Each period contains these samples: YYYYUV. |
+ | Bytes output: YYYYUV YYYYUV YYYYUV .... |
+ | |
+ | In this routine, |
+ | |
+ | vert_period = index of which period we're outputting vertically within|
+ | an MCU (0-7). |
+ | |
+ | horiz_period = index of which period we're outputting horizontally; |
+ | since an MCU has 8 periods, this is 0 .. 8*mcus_per_row.|
+ |____________________________________________________________________________|
+*/
+static void copy_out_rows (
+ PJDEC_INST g,
+ UINT row_index, /* in: index of next row to send within MCU */
+ BYTE *outbuf_p, /* out: copied-out row data */
+ UINT *n_rows_p, /* out: # of rows copied out */
+ UINT *n_bytes_p) /* out: # of bytes output */
+{
+ BYTE *out_p;
+ UINT comp;
+ UINT vert_period, vert_mod;
+ UINT row, col;
+ BYTE *row_p;
+
+ vert_period = row_index / g->max_vert_samp_fac;
+ vert_mod = row_index % g->max_vert_samp_fac;
+
+ if (! g->output_subsampled) {
+
+ /*******************************************/
+ /* Perform duplication to undo subsampling */
+ /*******************************************/
+
+ UINT samp_fac;
+ UINT horiz_mod;
+
+ for (comp=0; comp<g->num_comps; comp++) {
+ samp_fac = g->vert_samp_facs[comp];
+ out_p = outbuf_p + comp;
+ row = vert_period*samp_fac +
+ (vert_mod<samp_fac ? vert_mod : samp_fac-1);
+ row_p = g->out_rows_ap[comp][row];
+
+ horiz_mod = 0;
+ samp_fac = g->horiz_samp_facs[comp];
+
+ if (samp_fac == g->max_horiz_samp_fac) {
+
+ /***** fast case: copying all pixels, with no duplication *****/
+
+ if (g->num_comps == 1) {
+ memcpy (out_p, row_p, g->traits.iPixelsPerRow);
+ } else {
+ for (col=0; col<(UINT)g->traits.iPixelsPerRow; col++) {
+ *out_p = *row_p++;
+ out_p += g->num_comps;
+ }
+ }
+
+ } else if (samp_fac==1 && g->max_horiz_samp_fac==2) {
+
+ /***** fast case: duplicating every other pixel *****/
+
+ BYTE prev_pix;
+ for (col=0; col<(UINT)g->traits.iPixelsPerRow; col+=2) {
+ *out_p = prev_pix = *row_p++;
+ out_p += g->num_comps;
+ *out_p = prev_pix;
+ out_p += g->num_comps;
+ }
+
+ } else {
+
+ /***** slow general case *****/
+
+ for (col=0; col<(UINT)g->traits.iPixelsPerRow; col++) {
+ *out_p = horiz_mod<samp_fac ? *row_p++ : row_p[-1];
+ out_p += g->num_comps;
+ horiz_mod += 1;
+ if (horiz_mod == g->max_horiz_samp_fac) horiz_mod = 0;
+ }
+ }
+ }
+
+ *n_rows_p = 1;
+ *n_bytes_p = g->num_comps * g->traits.iPixelsPerRow;
+
+ } else {
+
+ /**********************************************/
+ /* Output subsampled data in ASIC's odd order */
+ /**********************************************/
+
+ UINT horiz_period, periods_per_row;
+ UINT ul_row, ul_col;
+ BYTE *row_y1_p, *row_y2_p, *row_cb_p, *row_cr_p;
+
+ out_p = outbuf_p;
+ periods_per_row = g->mcus_per_row * 8;
+
+ if (g->num_comps==1 && g->max_horiz_samp_fac==1 && g->max_vert_samp_fac==1) {
+
+ /***** fast case: one component; just copy the row *****/
+
+ memcpy (out_p, g->out_rows_ap[0][row_index], g->traits.iPixelsPerRow);
+ out_p += g->traits.iPixelsPerRow;
+
+ } else if (g->num_comps==3 &&
+ (g->horiz_samp_facs[0]==1 &&
+ g->horiz_samp_facs[1]==1 &&
+ g->horiz_samp_facs[2]==1) &&
+ (g->vert_samp_facs[0]==1 &&
+ g->vert_samp_facs[1]==1 &&
+ g->vert_samp_facs[2]==1)) {
+
+ /***** fast case: color with no subsampling *****/
+
+ row_y1_p = g->out_rows_ap[0][vert_period];
+ row_cb_p = g->out_rows_ap[1][vert_period];
+ row_cr_p = g->out_rows_ap[2][vert_period];
+ for (col=0; col<(UINT)g->traits.iPixelsPerRow; col++) {
+ *out_p++ = *row_y1_p++;
+ *out_p++ = *row_cb_p++;
+ *out_p++ = *row_cr_p++;
+ }
+
+ } else if (g->num_comps==3 &&
+ (g->horiz_samp_facs[0]==2 &&
+ g->horiz_samp_facs[1]==1 &&
+ g->horiz_samp_facs[2]==1) &&
+ (g->vert_samp_facs[0]==2 &&
+ g->vert_samp_facs[1]==1 &&
+ g->vert_samp_facs[2]==1)) {
+
+ /***** fast case: 4-1-1 color subsampling *****/
+
+ row_y1_p = g->out_rows_ap[0][2*vert_period];
+ row_y2_p = g->out_rows_ap[0][2*vert_period+1];
+ row_cb_p = g->out_rows_ap[1][vert_period];
+ row_cr_p = g->out_rows_ap[2][vert_period];
+ for (horiz_period=0; horiz_period<periods_per_row; horiz_period++) {
+ *out_p++ = *row_y1_p++;
+ *out_p++ = *row_y1_p++;
+ *out_p++ = *row_y2_p++;
+ *out_p++ = *row_y2_p++;
+ *out_p++ = *row_cb_p++;
+ *out_p++ = *row_cr_p++;
+ }
+
+ } else {
+
+ /***** slow general case *****/
+
+ for (horiz_period=0; horiz_period<periods_per_row; horiz_period++) {
+ for (comp=0; comp<g->num_comps; comp++) {
+ ul_row = vert_period * g->vert_samp_facs[comp];
+ ul_col = horiz_period * g->horiz_samp_facs[comp];
+
+ for (row=ul_row; row<ul_row+ g->vert_samp_facs[comp]; row++)
+ for (col=ul_col; col<ul_col+g->horiz_samp_facs[comp]; col++) {
+ *out_p++ = g->out_rows_ap[comp][row][col];
+ }
+ }
+ }
+ }
+
+ *n_rows_p = g->max_vert_samp_fac;
+ *n_bytes_p = out_p - outbuf_p;
+ }
+}
+
+
+
+
+/******************************************************************************
+ ******************************************************************************
+
+ E X P O R T E D R O U T I N E S
+
+ ******************************************************************************
+ ******************************************************************************/
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_openXform - Creates a new instance of the transformer
+ *
+ *****************************************************************************
+ *
+ * This returns a handle for the new instance to be passed into
+ * all subsequent calls.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_openXform (
+ IP_XFORM_HANDLE *pXform) /* out: returned handle */
+{
+ PJDEC_INST g;
+
+ INSURE (pXform != NULL);
+ IP_MEM_ALLOC (sizeof(JDEC_INST), g);
+ *pXform = g;
+ memset (g, 0, sizeof(JDEC_INST));
+ g->dwValidChk = CHECK_VALUE;
+ decode_init (g);
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_setDefaultInputTraits - Specifies default input image traits
+ *
+ *****************************************************************************
+ *
+ * The header of the file-type handled by the transform probably does
+ * not include *all* the image traits we'd like to know. Those not
+ * specified in the file-header are filled in from info provided by
+ * this routine.
+ *
+ * Return value: IP_DONE=success; IP_FATAL_ERROR=misc error.
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_setDefaultInputTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PIP_IMAGE_TRAITS pTraits) /* in: default image traits */
+{
+ PJDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ g->traits = *pTraits; /* a structure copy */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_setXformSpec - Provides xform-specific information
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_setXformSpec (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD_OR_PVOID aXformInfo[]) /* in: xform information */
+{
+ PJDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ g->output_subsampled = aXformInfo[IP_JPG_DECODE_OUTPUT_SUBSAMPLED].dword;
+ g->fDenali = aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_getHeaderBufSize- Returns size of input buf needed to hold header
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_getHeaderBufSize (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD *pdwInBufLen) /* out: buf size for parsing header */
+{
+ PJDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwInBufLen = MAX_HEADER_SIZE;
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_getActualTraits - Parses header, and returns input & output traits
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_getActualTraits (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ DWORD dwInputAvail, /* in: # avail bytes in input buf */
+ PBYTE pbInputBuf, /* in: ptr to input buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from input buf */
+ PDWORD pdwInputNextPos,/* out: file-pos to read from next */
+ PIP_IMAGE_TRAITS pInTraits, /* out: input image traits */
+ PIP_IMAGE_TRAITS pOutTraits) /* out: output image traits */
+{
+ PJDEC_INST g;
+ UINT comp;
+ UINT marker;
+ UINT row_len, n_rows;
+ UINT row;
+ UINT err;
+ BYTE *p;
+
+ /**************/
+ /* Misc. Init */
+ /**************/
+
+ HANDLE_TO_PTR (hXform, g);
+
+ g->rows_done = 0;
+ g->mcus_done = 0;
+ g->sending_rows = FALSE;
+ g->got_EOI = FALSE;
+ g->got_short_header = FALSE;
+ read_init (g);
+ huff_init (g);
+ zero_prior_DC (g);
+ g->restart_cur_mcu = 0;
+ g->restart_cur_marker = 0;
+ g->dwOutNextPos = 0;
+
+ /********************/
+ /* Parse the header */
+ /********************/
+
+ if ((err=setjmp(g->syntax_error)) != 0) {
+ PRINT (_T("jpeg_decode_parse_header: syntax error = %d\n"), err, 0);
+ return IP_FATAL_ERROR | IP_INPUT_ERROR;
+ }
+
+ read_buf_open (g, pbInputBuf);
+
+ if (mar_get(g) != MARKER_SOI)
+ return IP_FATAL_ERROR | IP_INPUT_ERROR;
+
+ do {
+ marker = mar_get (g);
+ mar_parse (g, marker);
+ if (marker == MARKER_EOI)
+ return IP_FATAL_ERROR | IP_INPUT_ERROR;
+ } while (!(marker==MARKER_SOS || g->got_short_header));
+
+ *pdwInputNextPos = g->dwInNextPos = *pdwInputUsed = read_buf_close (g);
+
+ /* todo: check that all markers arrived */
+
+ PRINT (_T("jpeg_decode_parse_header: pixels/row=%d, num_rows=%d\n"),
+ g->traits.iPixelsPerRow, g->traits.lNumRows);
+
+ g->cols_per_mcu = g->max_horiz_samp_fac * 8;
+ g->rows_per_mcu = g->max_vert_samp_fac * 8;
+ g->mcus_per_row = (g->traits.iPixelsPerRow + g->cols_per_mcu - 1) / g->cols_per_mcu;
+
+ /*******************************************/
+ /* Allocate the row-buffers in out_rows_ap */
+ /*******************************************/
+
+ memset (g->out_rows_ap, 0, sizeof(g->out_rows_ap));
+
+ for (comp=0; comp<g->num_comps; comp++) {
+ row_len = g->horiz_samp_facs[comp] * g->mcus_per_row * 8;
+ n_rows = g->vert_samp_facs[comp] * 8;
+
+ for (row=0; row<n_rows; row++) {
+ IP_MEM_ALLOC (row_len, p);
+ g->out_rows_ap[comp][row] = p;
+ }
+ }
+
+ /***************/
+ /* Return info */
+ /***************/
+
+ *pInTraits = g->traits;
+ *pOutTraits = g->traits;
+
+ return IP_DONE | IP_READY_FOR_DATA;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/****************************************************************************\
+ *
+ * jpgDecode_getActualBufSizes - Returns buf sizes needed for remainder of job
+ *
+\****************************************************************************/
+
+static WORD jpgDecode_getActualBufSizes (
+ IP_XFORM_HANDLE hXform, /* in: handle for xform */
+ PDWORD pdwMinInBufLen, /* out: min input buf size */
+ PDWORD pdwMinOutBufLen) /* out: min output buf size */
+{
+ PJDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pdwMinInBufLen = INBUF_NUM_MCUS * MAX_MCU_SIZE;
+ *pdwMinOutBufLen = g->num_comps * g->traits.iPixelsPerRow;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_convert - the work-horse routine
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_convert (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwInputAvail, /* in: # avail bytes in in-buf */
+ PBYTE pbInputBuf, /* in: ptr to in-buffer */
+ PDWORD pdwInputUsed, /* out: # bytes used from in-buf */
+ PDWORD pdwInputNextPos, /* out: file-pos to read from next */
+ DWORD dwOutputAvail, /* in: # avail bytes in out-buf */
+ PBYTE pbOutputBuf, /* in: ptr to out-buffer */
+ PDWORD pdwOutputUsed, /* out: # bytes written in out-buf */
+ PDWORD pdwOutputThisPos) /* out: file-pos to write the data */
+{
+ PJDEC_INST g;
+ /* The "static" keyword for ret_val and bDecoded is to prevent the
+ * "variable `' might be clobbered by `longjmp' or `vfork'" warning. */
+ static unsigned ret_val;
+ UINT comp, row, row_len, n_rows, n_bytes, trash;
+ int iErrorCode;
+ static BOOL bDecoded;
+ const BYTE ycc_white[4] = { 255, 128, 128, 255 };
+
+ HANDLE_TO_PTR (hXform, g);
+
+ *pdwInputUsed = 0;
+ *pdwOutputThisPos = g->dwOutNextPos;
+ *pdwOutputUsed = 0;
+ ret_val = IP_READY_FOR_DATA;
+
+ if (setjmp(g->syntax_error) != 0) {
+ PRINT (_T("got a syntax error\n"), 0, 0);
+ *pdwInputNextPos = g->dwInNextPos;
+ return IP_FATAL_ERROR | IP_INPUT_ERROR;
+ }
+
+ /**********************/
+ /* Parsing input data */
+ /**********************/
+
+ if (! g->sending_rows) {
+ if (pbInputBuf == NULL) {
+
+ /* We are being told to flush, so we should have consumed the EOI,
+ * and have discarded any bytes following it. */
+ if (! g->got_EOI) {
+ /* Unexpected end of data: we did not get an EOI */
+ ret_val |= IP_INPUT_ERROR;
+ }
+ ret_val |= IP_DONE;
+
+ } else if (g->got_EOI) {
+
+ /* Discard bytes after the EOI. We should report an error here, but
+ * the ASIC+firmware of Denali/Kodiak can send stuff after the EOI. */
+ *pdwInputUsed = dwInputAvail;
+
+ } else {
+
+ if (g->mcus_done == 0) {
+ /* init all row-buffers to white */
+ PRINT (_T("initing all row-buffers to white\n"), 0, 0);
+ for (comp=0; comp<g->num_comps; comp++) {
+ row_len = g->horiz_samp_facs[comp] * g->mcus_per_row * 8;
+ n_rows = g->vert_samp_facs[comp] * 8;
+
+ for (row=0; row<n_rows; row++)
+ memset (g->out_rows_ap[comp][row], ycc_white[comp], row_len);
+ }
+ }
+
+ do {
+ bDecoded = FALSE;
+ read_buf_open (g, pbInputBuf + *pdwInputUsed);
+ memcpy(&(g->old_syntax_error), &(g->syntax_error), sizeof(jmp_buf));
+ iErrorCode = setjmp(g->syntax_error);
+ if (iErrorCode == 0) {
+ bDecoded = decode_MCU(g);
+
+ /* Check for (and handle) a marker (DNL, RST, EOI).
+ * We need to handle DNL here so the sending_rows state below
+ * won't output the pad rows on the bottom of the image
+ */
+ if (! g->got_EOI) {
+ READ_BITS_LOAD (g, FALSE, 8, trash, at_a_marker);
+ goto no_marker;
+ at_a_marker:
+ handleMarkerInStream(g);
+ no_marker:;
+ }
+ }
+ memcpy(&(g->syntax_error), &(g->old_syntax_error), sizeof(jmp_buf));
+ n_bytes = read_buf_close (g);
+
+ *pdwInputUsed += n_bytes;
+ g->dwInNextPos += n_bytes;
+
+ if (*pdwInputUsed > dwInputAvail) {
+ /* Parser read past end of input buffer */
+ *pdwInputUsed = dwInputAvail;
+ g->dwInNextPos += dwInputAvail - n_bytes;
+ /* We will not make this a fatal error because that would
+ * immediately shut down the remaining xforms in the pipeline.
+ * Instead, we assume that the input data was truncated, and
+ * let the pipeline finish up normally so that it'll give a
+ * valid output file.
+ */
+ ret_val |= IP_INPUT_ERROR;
+ } else if (iErrorCode != 0) {
+ /* An error within the data: Make it fatal */
+ longjmp (g->syntax_error, iErrorCode);
+ } else if (g->got_EOI) {
+ ret_val |= IP_NEW_OUTPUT_PAGE;
+ /* Note: we should have just done the final MCU in a row, but
+ * we don't check for this because the firmware of Denali/Kodiak
+ * can't guarantee it. */
+ }
+
+ if (bDecoded) {
+ g->mcus_done += 1;
+
+ if (g->mcus_done >= g->mcus_per_row) {
+ PRINT (_T("done with row of MCUs; starting row-sends\n"), 0, 0);
+ g->sending_rows = TRUE;
+ g->mcus_done = 0;
+ }
+ }
+ } while (!g->got_EOI && !g->sending_rows &&
+ (dwInputAvail-*pdwInputUsed) >= MAX_MCU_SIZE);
+ }
+ }
+
+ /***************************/
+ /* Sending the output rows */
+ /***************************/
+
+ if (g->sending_rows) {
+ if (g->rows_done>=g->traits.lNumRows && g->traits.lNumRows>=0) {
+ /* we've already output all rows, so discard these */
+ g->sending_rows = FALSE;
+ } else {
+ copy_out_rows (
+ g,
+ g->rows_done % g->rows_per_mcu, /* in: index of next row to send */
+ pbOutputBuf, /* out: copied-out row data */
+ &n_rows, /* out: # of rows copied out */
+ &n_bytes); /* out: # of bytes output */
+ PRINT (_T("copied out %d rows\n"), n_rows, 0);
+ *pdwOutputUsed = n_bytes;
+ g->dwOutNextPos += n_bytes;
+ g->rows_done += n_rows;
+
+ if ((g->rows_done>=g->traits.lNumRows && g->traits.lNumRows>=0)
+ || (g->rows_done % g->rows_per_mcu)==0) {
+ g->sending_rows = FALSE;
+ }
+ /* n_rows is 1, unless the never-used output_subsampled feature is used */
+ if (n_rows > 0)
+ ret_val |= IP_CONSUMED_ROW | IP_PRODUCED_ROW;
+ }
+ }
+
+ *pdwInputNextPos = g->dwInNextPos;
+
+ PRINT (_T("jpeg_decode_convert_row: Returning %04x, in_used=%d\n"),
+ ret_val, *pdwInputUsed);
+ return ret_val;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_insertedData - client inserted into our output stream
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_insertedData (
+ IP_XFORM_HANDLE hXform,
+ DWORD dwNumBytes)
+{
+ fatalBreakPoint ();
+ return IP_FATAL_ERROR; /* must never be called (can't insert data) */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_newPage - Tells us to flush this page, and start a new page
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_newPage (
+ IP_XFORM_HANDLE hXform)
+{
+ return IP_DONE; /* can't insert page-breaks, so ignore this call */
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_closeXform - Destroys this instance
+ *
+\*****************************************************************************/
+
+static WORD jpgDecode_closeXform (IP_XFORM_HANDLE hXform)
+{
+ PJDEC_INST g;
+ BYTE **row_pp, **after_pp, *p;
+
+ HANDLE_TO_PTR (hXform, g);
+ PRINT (_T("jpeg_decode_close\n"), 0, 0);
+
+ row_pp = &(g->out_rows_ap[0][0]);
+ after_pp = row_pp + (sizeof(g->out_rows_ap)/sizeof(BYTE *));
+
+ for ( ; row_pp<after_pp; row_pp++) {
+ p = *row_pp;
+ if (p != NULL) {
+ IP_MEM_FREE (p);
+ *row_pp = NULL;
+ }
+ }
+
+ huff_free_all (g);
+ g->dwValidChk = 0;
+ IP_MEM_FREE (g); /* free memory for the instance */
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecode_getRowCountInfo - Returns information for determining row count
+ *
+\*****************************************************************************/
+
+WORD jpgDecode_getRowCountInfo(IP_XFORM_HANDLE hXform,
+ int *pRcCountup,int *pRcTraits,int *pSofOffset)
+{
+ PJDEC_INST g;
+
+ HANDLE_TO_PTR (hXform, g);
+ *pRcCountup=g->rows_done;
+ *pRcTraits=g->traits.lNumRows;
+ *pSofOffset=g->rowCountOffset;
+
+ return IP_DONE;
+
+ fatal_error:
+ return IP_FATAL_ERROR;
+}
+
+
+
+/*****************************************************************************\
+ *
+ * jpgDecodeTbl - Jump-table for decoder
+ *
+\*****************************************************************************/
+
+IP_XFORM_TBL jpgDecodeTbl = {
+ jpgDecode_openXform,
+ jpgDecode_setDefaultInputTraits,
+ jpgDecode_setXformSpec,
+ jpgDecode_getHeaderBufSize,
+ jpgDecode_getActualTraits,
+ jpgDecode_getActualBufSizes,
+ jpgDecode_convert,
+ jpgDecode_newPage,
+ jpgDecode_insertedData,
+ jpgDecode_closeXform
+};
+
+/* End of File */
+
+
+
+
+
+
+
+
+
+