#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <liboil/liboil-stdint.h>
#include <liboil/liboil.h>
#include <liboil/liboildebug.h>
#include <stdarg.h>
#include "jpeg_internal.h"
#define MAX(a,b) ((a)>(b) ? (a) : (b))
extern uint8_t jpeg_standard_tables[];
extern int jpeg_standard_tables_size;
void jpeg_decoder_error(JpegDecoder *dec, char *fmt, ...);
void jpeg_decoder_define_huffman_tables (JpegDecoder * dec);
void jpeg_decoder_define_arithmetic_conditioning (JpegDecoder *dec);
void jpeg_decoder_define_quantization_tables (JpegDecoder *dec);
void jpeg_decoder_define_restart_interval (JpegDecoder *dec);
void jpeg_decoder_start_of_frame (JpegDecoder * dec, int marker);
void jpeg_decoder_start_of_scan (JpegDecoder * dec);
/* misc helper function declarations */
static void dumpbits (JpegBits * bits);
static char *sprintbits (char *str, unsigned int bits, int n);
static void huffman_table_load_std_jpeg (JpegDecoder * dec);
static void jpeg_decoder_verify_header (JpegDecoder *dec);
static void jpeg_decoder_init_decoder (JpegDecoder *dec);
static void
jpeg_decoder_verify_header (JpegDecoder *dec)
{
int max_quant_table = 0;
int i;
if (dec->sof_type != JPEG_MARKER_SOF_0) {
OIL_ERROR("only handle baseline DCT");
dec->error = TRUE;
}
if (dec->width < 1) {
OIL_ERROR("height can't be 0");
dec->error = TRUE;
}
switch (dec->sof_type) {
case JPEG_MARKER_SOF_0:
/* baseline DCT */
max_quant_table = 3;
if (dec->depth != 8) {
OIL_ERROR("depth must be 8 (%d)", dec->depth);
dec->error = TRUE;
}
break;
case JPEG_MARKER_SOF_1:
/* extended DCT */
max_quant_table = 3;
if (dec->depth != 8 && dec->depth != 12) {
OIL_ERROR("depth must be 8 or 12 (%d)", dec->depth);
dec->error = TRUE;
}
break;
case JPEG_MARKER_SOF_2:
/* progressive DCT */
max_quant_table = 3;
if (dec->depth != 8 && dec->depth != 12) {
OIL_ERROR("depth must be 8 or 12 (%d)", dec->depth);
dec->error = TRUE;
}
break;
case JPEG_MARKER_SOF_3:
/* lossless DCT */
max_quant_table = 0;
if (dec->depth < 2 || dec->depth > 16) {
OIL_ERROR("depth must be between 2 and 16 (%d)", dec->depth);
dec->error = TRUE;
}
break;
default:
break;
}
if (dec->n_components < 0 || dec->n_components > 255) {
OIL_ERROR("n_components must be in the range 0-255 (%d)",
dec->n_components);
dec->error = TRUE;
}
if (dec->sof_type == JPEG_MARKER_SOF_2 && dec->n_components > 4) {
OIL_ERROR("n_components must be <= 4 for progressive DCT (%d)",
dec->n_components);
dec->error = TRUE;
}
for (i = 0; i < dec->n_components; i++) {
if (dec->components[i].id < 0 || dec->components[i].id > 255) {
OIL_ERROR("component ID out of range");
dec->error = TRUE;
break;
}
if (dec->components[i].h_sample < 1 || dec->components[i].h_sample > 4 ||
dec->components[i].v_sample < 1 || dec->components[i].v_sample > 4) {
OIL_ERROR("sample factor(s) for component %d out of range %d %d",
i, dec->components[i].h_sample, dec->components[i].v_sample);
dec->error = TRUE;
break;
}
if (dec->components[i].quant_table < 0 ||
dec->components[i].quant_table > max_quant_table) {
OIL_ERROR("quant table for component %d out of range (%d)",
i, dec->components[i].quant_table);
dec->error = TRUE;
break;
}
}
}
static void
jpeg_decoder_init_decoder (JpegDecoder *dec)
{
int max_h_sample = 0;
int max_v_sample = 0;
int i;
/* decoder limitations */
if (dec->n_components != 3) {
jpeg_decoder_error(dec, "wrong number of components %d", dec->n_components);
return;
}
if (dec->sof_type != JPEG_MARKER_SOF_0) {
jpeg_decoder_error(dec, "only handle baseline DCT");
return;
}
for (i=0; i < dec->n_components; i++) {
max_h_sample = MAX (max_h_sample, dec->components[i].h_sample);
max_v_sample = MAX (max_v_sample, dec->components[i].v_sample);
}
dec->width_blocks =
(dec->width + 8 * max_h_sample - 1) / (8 * max_h_sample);
dec->height_blocks =
(dec->height + 8 * max_v_sample - 1) / (8 * max_v_sample);
for (i = 0; i < dec->n_components; i++) {
int rowstride;
int image_size;
dec->components[i].h_subsample = max_h_sample /
dec->components[i].h_sample;
dec->components[i].v_subsample = max_v_sample /
dec->components[i].v_sample;
rowstride = dec->width_blocks * 8 * max_h_sample /
dec->components[i].h_subsample;
image_size = rowstride *
(dec->height_blocks * 8 * max_v_sample /
dec->components[i].v_subsample);
dec->components[i].rowstride = rowstride;
dec->components[i].image = malloc (image_size);
}
}
void
generate_code_table (int *huffsize)
{
int code;
int i;
int j;
int k;
char str[33];
//int l;
code = 0;
k = 0;
for (i = 0; i < 16; i++) {
for (j = 0; j < huffsize[i]; j++) {
OIL_DEBUG ("huffcode[%d] = %s", k,
sprintbits (str, code >> (15 - i), i + 1));
code++;
k++;
}
code <<= 1;
}
}
int
huffman_table_init_jpeg (HuffmanTable *table, JpegBits * bits)
{
int n_symbols;
int huffsize[16];
int i, j, k;
unsigned int symbol;
int n = 0;
huffman_table_init (table);
/* huffsize[i] is the number of symbols that have length
* (i+1) bits. Maximum bit length is 16 bits, so there are
* 16 entries. */
n_symbols = 0;
for (i = 0; i < 16; i++) {
huffsize[i] = jpeg_bits_get_u8 (bits);
n++;
n_symbols += huffsize[i];
}
/* Build up the symbol table. The first symbol is all 0's, with
* the number of bits determined by the first non-zero entry in
* huffsize[]. Subsequent symbols with the same bit length are
* incremented by 1. Increasing the bit length shifts the
* symbol 1 bit to the left. */
symbol = 0;
k = 0;
for (i = 0; i < 16; i++) {
for (j = 0; j < huffsize[i]; j++) {
huffman_table_add (table, symbol, i + 1, jpeg_bits_get_u8 (bits));
n++;
symbol++;
k++;
}
/* This checks that our symbol is actually less than the
* number of bits we think it is. This is only triggered
* for bad huffsize[] arrays. */
if (symbol >= (1 << (i + 1))) {
/* FIXME jpeg_decoder_error() */
OIL_DEBUG ("bad huffsize[] array");
return -1;
}
symbol <<= 1;
}
huffman_table_dump (table);
return n;
}
static void
dumpbits (JpegBits * bits)
{
int i;
int j;
unsigned char *p;
char s[40];
p = bits->ptr;
for (i = 0; i < 8; i++) {
sprintf (s, "%02x %02x %02x %02x %02x %02x %02x %02x ........",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
for (j = 0; j < 8; j++) {
s[j + 24] = (isprint (p[j])) ? p[j] : '.';
}
OIL_DEBUG ("%s", s);
p += 8;
}
}
int
jpeg_decoder_find_component_by_id (JpegDecoder * dec, int id)
{
int i;
for (i = 0; i < dec->n_components; i++) {
if (dec->components[i].id == id)
return i;
}
OIL_DEBUG ("undefined component id %d", id);
return 0;
}
int
jpeg_decoder_application0 (JpegDecoder * dec, JpegBits * bits)
{
int length;
OIL_DEBUG ("app0");
length = get_be_u16 (bits);
OIL_DEBUG ("length=%d", length);
if (memcmp (bits->ptr, "JFIF", 4) == 0 && bits->ptr[4] == 0) {
int version;
int units;
int x_density;
int y_density;
int x_thumbnail;
int y_thumbnail;
OIL_DEBUG ("JFIF");
bits->ptr += 5;
version = get_be_u16 (bits);
units = get_u8 (bits);
x_density = get_be_u16 (bits);
y_density = get_be_u16 (bits);
x_thumbnail = get_u8 (bits);
y_thumbnail = get_u8 (bits);
OIL_DEBUG ("version = %04x", version);
OIL_DEBUG ("units = %d", units);
OIL_DEBUG ("x_density = %d", x_density);
OIL_DEBUG ("y_density = %d", y_density);
OIL_DEBUG ("x_thumbnail = %d", x_thumbnail);
OIL_DEBUG ("y_thumbnail = %d", y_thumbnail);
}
if (memcmp (bits->ptr, "JFXX", 4) == 0 && bits->ptr[4] == 0) {
OIL_DEBUG ("JFIF extension (not handled)");
bits->ptr += length - 2;
}
return length;
}
int
jpeg_decoder_application_misc (JpegDecoder * dec, JpegBits * bits)
{
int length;
OIL_DEBUG ("appX");
length = get_be_u16 (bits);
OIL_DEBUG ("length=%d", length);
OIL_DEBUG ("JPEG application tag X ignored");
dumpbits (bits);
bits->ptr += length - 2;
return length;
}
int
jpeg_decoder_comment (JpegDecoder * dec, JpegBits * bits)
{
int length;
OIL_DEBUG ("comment");
length = get_be_u16 (bits);
OIL_DEBUG ("length=%d", length);
dumpbits (bits);
bits->ptr += length - 2;
return length;
}
int
jpeg_decoder_restart_interval (JpegDecoder * dec, JpegBits * bits)
{
int length;
OIL_DEBUG ("comment");
length = get_be_u16 (bits);
OIL_DEBUG ("length=%d", length);
dec->restart_interval = get_be_u16 (bits);
OIL_DEBUG ("restart_interval=%d", dec->restart_interval);
return length;
}
int
jpeg_decoder_restart (JpegDecoder * dec, JpegBits * bits)
{
OIL_DEBUG ("restart");
return 0;
}
void
jpeg_decoder_decode_entropy_segment (JpegDecoder * dec)
{
JpegBits * bits = &dec->bits;
JpegBits b2, *bits2 = &b2;
short block[64];
short block2[64];
unsigned char *newptr;
int len;
int j;
int i;
int go;
int x, y;
int n;
int ret;
len = 0;
j = 0;
while (1) {
if (bits->ptr[len] == 0xff && bits->ptr[len + 1] != 0x00) {
break;
}
len++;
}
OIL_DEBUG ("entropy length = %d", len);
/* we allocate extra space, since the getbits() code can
* potentially read past the end of the buffer */
newptr = malloc (len + 2);
for (i = 0; i < len; i++) {
newptr[j] = bits->ptr[i];
j++;
if (bits->ptr[i] == 0xff)
i++;
}
bits->ptr += len;
bits2->ptr = newptr;
bits2->idx = 0;
bits2->end = newptr + j;
newptr[j] = 0;
newptr[j + 1] = 0;
dec->dc[0] = dec->dc[1] = dec->dc[2] = dec->dc[3] = 128 * 8;
go = 1;
x = dec->x;
y = dec->y;
n = dec->restart_interval;
if (n == 0) n = INT_MAX;
while (n-- > 0) {
for (i = 0; i < dec->scan_list_length; i++) {
int dc_table_index;
int ac_table_index;
int quant_index;
unsigned char *ptr;
int component_index;
OIL_DEBUG ("%d,%d: component=%d dc_table=%d ac_table=%d",
x, y,
dec->scan_list[i].component_index,
dec->scan_list[i].dc_table, dec->scan_list[i].ac_table);
component_index = dec->scan_list[i].component_index;
dc_table_index = dec->scan_list[i].dc_table;
ac_table_index = dec->scan_list[i].ac_table;
quant_index = dec->scan_list[i].quant_table;
ret = huffman_table_decode_macroblock (block,
&dec->dc_huff_table[dc_table_index],
&dec->ac_huff_table[ac_table_index], bits2);
if (ret < 0) {
OIL_DEBUG ("%d,%d: component=%d dc_table=%d ac_table=%d",
x, y,
dec->scan_list[i].component_index,
dec->scan_list[i].dc_table, dec->scan_list[i].ac_table);
n = 0;
break;
}
OIL_DEBUG ("using quant table %d", quant_index);
oil_mult8x8_s16 (block2, block, dec->quant_tables[quant_index].quantizer,
sizeof (short) * 8, sizeof(short) * 8, sizeof (short) * 8);
dec->dc[component_index] += block2[0];
block2[0] = dec->dc[component_index];
oil_unzigzag8x8_s16 (block, sizeof (short) * 8, block2,
sizeof (short) * 8);
oil_idct8x8_s16 (block2, sizeof (short) * 8, block, sizeof (short) * 8);
oil_trans8x8_s16 (block, sizeof (short) * 8, block2, sizeof (short) * 8);
ptr = dec->components[component_index].image +
x * dec->components[component_index].h_sample +
dec->scan_list[i].offset +
dec->components[component_index].rowstride * y *
dec->components[component_index].v_sample;
oil_clipconv8x8_u8_s16 (ptr,
dec->components[component_index].rowstride,
block, sizeof (short) * 8);
}
x += 8;
if (x * dec->scan_h_subsample >= dec->width) {
x = 0;
y += 8;
}
if (y * dec->scan_v_subsample >= dec->height) {
go = 0;
}
}
dec->x = x;
dec->y = y;
free (newptr);
}
JpegDecoder *
jpeg_decoder_new (void)
{
JpegDecoder *dec;
oil_init ();
dec = malloc (sizeof(JpegDecoder));
memset (dec, 0, sizeof(JpegDecoder));
huffman_table_load_std_jpeg (dec);
return dec;
}
void
jpeg_decoder_free (JpegDecoder * dec)
{
int i;
for (i = 0; i < JPEG_MAX_COMPONENTS; i++) {
if (dec->components[i].image)
free (dec->components[i].image);
}
if (dec->data)
free (dec->data);
free (dec);
}
void
jpeg_decoder_error(JpegDecoder *dec, char *fmt, ...)
{
va_list varargs;
if (dec->error) return;
va_start (varargs, fmt);
vasprintf(&dec->error_message, fmt, varargs);
va_end (varargs);
OIL_ERROR("decoder error: %s", dec->error_message);
abort();
dec->error = TRUE;
}
int
jpeg_decoder_get_marker (JpegDecoder *dec, int *marker)
{
int a,b;
JpegBits *bits = &dec->bits;
if (jpeg_bits_available(bits) < 2) {
return FALSE;
}
a = jpeg_bits_get_u8(bits);
if (a != 0xff) {
jpeg_decoder_error(dec, "expected marker, not 0x%02x", a);
return FALSE;
}
do {
b = jpeg_bits_get_u8 (bits);
} while (b == 0xff && jpeg_bits_error(bits));
*marker = b;
return TRUE;
}
void
jpeg_decoder_skip (JpegDecoder *dec)
{
int length;
length = jpeg_bits_get_u16_be (&dec->bits);
jpeg_bits_skip (&dec->bits, length - 2);
}
int
jpeg_decoder_decode (JpegDecoder *dec)
{
JpegBits *bits;
int marker;
dec->error = FALSE;
bits = &dec->bits;
/* Note: The spec is ambiguous as to whether fill bytes can preceed
* the first marker. We'll assume yes. */
if (!jpeg_decoder_get_marker (dec, &marker)) {
return FALSE;
}
if (marker != JPEG_MARKER_SOI) {
jpeg_decoder_error(dec, "not a JPEG image");
return FALSE;
}
/* Interpret markers up to the start of frame */
while (!dec->error) {
if (!jpeg_decoder_get_marker (dec, &marker)) {
return FALSE;
}
if (marker == JPEG_MARKER_DEFINE_HUFFMAN_TABLES) {
jpeg_decoder_define_huffman_tables (dec);
} else if (marker == JPEG_MARKER_DEFINE_ARITHMETIC_CONDITIONING) {
jpeg_decoder_define_arithmetic_conditioning (dec);
} else if (marker == JPEG_MARKER_DEFINE_QUANTIZATION_TABLES) {
jpeg_decoder_define_quantization_tables (dec);
} else if (marker == JPEG_MARKER_DEFINE_RESTART_INTERVAL) {
jpeg_decoder_define_restart_interval (dec);
} else if (JPEG_MARKER_IS_APP(marker)) {
/* FIXME decode app segment */
jpeg_decoder_skip (dec);
} else if (marker == JPEG_MARKER_COMMENT) {
jpeg_decoder_skip (dec);
} else if (JPEG_MARKER_IS_START_OF_FRAME(marker)) {
break;
} else {
jpeg_decoder_error(dec, "unexpected marker 0x%02x", marker);
return FALSE;
}
}
jpeg_decoder_start_of_frame(dec, marker);
jpeg_decoder_verify_header (dec);
if (dec->error) {
return FALSE;
}
jpeg_decoder_init_decoder (dec);
if (dec->error) {
return FALSE;
}
/* In this section, we loop over parse units until we reach the end
* of the image. */
while (!dec->error) {
if (!jpeg_decoder_get_marker (dec, &marker)) {
return FALSE;
}
if (marker == JPEG_MARKER_DEFINE_HUFFMAN_TABLES) {
jpeg_decoder_define_huffman_tables (dec);
} else if (marker == JPEG_MARKER_DEFINE_ARITHMETIC_CONDITIONING) {
jpeg_decoder_define_arithmetic_conditioning (dec);
} else if (marker == JPEG_MARKER_DEFINE_QUANTIZATION_TABLES) {
jpeg_decoder_define_quantization_tables (dec);
} else if (marker == JPEG_MARKER_DEFINE_RESTART_INTERVAL) {
jpeg_decoder_define_restart_interval (dec);
} else if (JPEG_MARKER_IS_APP(marker)) {
jpeg_decoder_skip (dec);
} else if (marker == JPEG_MARKER_COMMENT) {
jpeg_decoder_skip (dec);
} else if (marker == JPEG_MARKER_SOS) {
jpeg_decoder_start_of_scan (dec);
jpeg_decoder_decode_entropy_segment (dec);
} else if (JPEG_MARKER_IS_RESET(marker)) {
jpeg_decoder_decode_entropy_segment (dec);
} else if (marker == JPEG_MARKER_EOI) {
break;
} else {
jpeg_decoder_error(dec, "unexpected marker 0x%02x", marker);
return FALSE;
}
}
return TRUE;
}
/* handle markers */
void
jpeg_decoder_define_huffman_tables (JpegDecoder * dec)
{
JpegBits *bits = &dec->bits;
int length;
int tc;
int th;
int x;
HuffmanTable *hufftab;
OIL_DEBUG ("define huffman tables");
length = jpeg_bits_get_u16_be (bits);
if (length < 2) {
jpeg_decoder_error(dec, "length too short");
return;
}
length -= 2;
while (length > 0) {
x = jpeg_bits_get_u8 (bits);
length--;
tc = x >> 4;
th = x & 0xf;
OIL_DEBUG ("huff table type %d (%s) index %d", tc, tc ? "ac" : "dc", th);
if (tc > 1 || th > 3) {
jpeg_decoder_error(dec, "huffman table type or index out of range");
return;
}
if (tc) {
hufftab = &dec->ac_huff_table[th];
length -= huffman_table_init_jpeg (hufftab, bits);
} else {
hufftab = &dec->dc_huff_table[th];
length -= huffman_table_init_jpeg (hufftab, bits);
}
}
if (length < 0) {
jpeg_decoder_error(dec, "huffman table overran available bytes");
return;
}
}
void
jpeg_decoder_define_quantization_tables (JpegDecoder *dec)
{
JpegBits *bits = &dec->bits;
JpegQuantTable *table;
int length;
int pq;
int tq;
int i;
OIL_INFO ("define quantization table");
length = jpeg_bits_get_u16_be (bits);
if (length < 2) {
jpeg_decoder_error(dec, "length too short");
return;
}
length -= 2;
while (length > 0) {
int x;
x = jpeg_bits_get_u8 (bits);
length--;
pq = x >> 4;
tq = x & 0xf;
if (pq > 1) {
jpeg_decoder_error (dec, "bad pq value");
return;
}
if (tq > 3) {
jpeg_decoder_error (dec, "bad tq value");
return;
}
table = &dec->quant_tables[tq];
if (pq) {
for (i = 0; i < 64; i++) {
table->quantizer[i] = jpeg_bits_get_u16_be (bits);
length -= 2;
}
} else {
for (i = 0; i < 64; i++) {
table->quantizer[i] = jpeg_bits_get_u8 (bits);
length -= 1;
}
}
}
if (length < 0) {
jpeg_decoder_error(dec, "quantization table overran available bytes");
return;
}
}
void
jpeg_decoder_define_restart_interval (JpegDecoder *dec)
{
JpegBits *bits = &dec->bits;
int length;
length = jpeg_bits_get_u16_be (bits);
if (length != 4) {
jpeg_decoder_error(dec, "length supposed to be 4 (%d)", length);
return;
}
/* FIXME this needs to be checked somewhere */
dec->restart_interval = jpeg_bits_get_u16_be (bits);
}
void
jpeg_decoder_define_arithmetic_conditioning (JpegDecoder *dec)
{
/* we don't handle arithmetic coding, so skip it */
jpeg_decoder_skip (dec);
}
void
jpeg_decoder_start_of_frame (JpegDecoder * dec, int marker)
{
JpegBits *bits = &dec->bits;
int i;
int length;
OIL_INFO ("start of frame");
dec->sof_type = marker;
length = jpeg_bits_get_u16_be (bits);
if (jpeg_bits_available(bits) < length) {
jpeg_decoder_error(dec, "not enough data for start_of_frame (%d < %d)",
length, jpeg_bits_available(bits));
return;
}
dec->depth = jpeg_bits_get_u8 (bits);
dec->height = jpeg_bits_get_u16_be (bits);
dec->width = jpeg_bits_get_u16_be (bits);
dec->n_components = jpeg_bits_get_u8 (bits);
OIL_DEBUG (
"frame_length=%d depth=%d height=%d width=%d n_components=%d", length,
dec->depth, dec->height, dec->width, dec->n_components);
if (dec->n_components * 3 + 8 != length) {
jpeg_decoder_error(dec, "inconsistent header");
return;
}
for (i = 0; i < dec->n_components; i++) {
dec->components[i].id = get_u8 (bits);
dec->components[i].h_sample = getbits (bits, 4);
dec->components[i].v_sample = getbits (bits, 4);
dec->components[i].quant_table = get_u8 (bits);
OIL_DEBUG (
"[%d] id=%d h_sample=%d v_sample=%d quant_table=%d", i,
dec->components[i].id, dec->components[i].h_sample,
dec->components[i].v_sample, dec->components[i].quant_table);
}
}
void
jpeg_decoder_start_of_scan (JpegDecoder * dec)
{
JpegBits *bits = &dec->bits;
int length;
int i;
int spectral_start;
int spectral_end;
int approx_high;
int approx_low;
int n;
int tmp;
int n_components;
OIL_DEBUG ("start of scan");
length = jpeg_bits_get_u16_be (bits);
OIL_DEBUG ("length=%d", length);
n_components = jpeg_bits_get_u8 (bits);
n = 0;
dec->scan_h_subsample = 0;
dec->scan_v_subsample = 0;
for (i = 0; i < n_components; i++) {
int component_id;
int dc_table;
int ac_table;
int x;
int y;
int index;
int h_subsample;
int v_subsample;
int quant_index;
component_id = jpeg_bits_get_u8 (bits);
tmp = jpeg_bits_get_u8 (bits);
dc_table = tmp >> 4;
ac_table = tmp & 0xf;
index = jpeg_decoder_find_component_by_id (dec, component_id);
h_subsample = dec->components[index].h_sample;
v_subsample = dec->components[index].v_sample;
quant_index = dec->components[index].quant_table;
for (y = 0; y < v_subsample; y++) {
for (x = 0; x < h_subsample; x++) {
dec->scan_list[n].component_index = index;
dec->scan_list[n].dc_table = dc_table;
dec->scan_list[n].ac_table = ac_table;
dec->scan_list[n].quant_table = quant_index;
dec->scan_list[n].x = x;
dec->scan_list[n].y = y;
dec->scan_list[n].offset =
y * 8 * dec->components[index].rowstride + x * 8;
n++;
}
}
dec->scan_h_subsample = MAX (dec->scan_h_subsample, h_subsample);
dec->scan_v_subsample = MAX (dec->scan_v_subsample, v_subsample);
OIL_DEBUG ("component %d: index=%d dc_table=%d ac_table=%d n=%d",
component_id, index, dc_table, ac_table, n);
}
dec->scan_list_length = n;
spectral_start = jpeg_bits_get_u8 (bits);
spectral_end = jpeg_bits_get_u8 (bits);
OIL_DEBUG ("spectral range [%d,%d]", spectral_start, spectral_end);
tmp = jpeg_bits_get_u8 (bits);
approx_high = tmp >> 4;
approx_low = tmp & 0xf;
OIL_DEBUG ("approx range [%d,%d]", approx_low, approx_high);
dec->x = 0;
dec->y = 0;
dec->dc[0] = dec->dc[1] = dec->dc[2] = dec->dc[3] = 128 * 8;
}
int
jpeg_decoder_addbits (JpegDecoder * dec, unsigned char *data, unsigned int len)
{
unsigned int offset;
offset = dec->bits.ptr - dec->data;
dec->data = realloc (dec->data, dec->data_len + len);
memcpy (dec->data + dec->data_len, data, len);
dec->data_len += len;
dec->bits.ptr = dec->data + offset;
dec->bits.end = dec->data + dec->data_len;
return 0;
}
int
jpeg_decoder_get_image_size (JpegDecoder * dec, int *width, int *height)
{
if (width)
*width = dec->width;
if (height)
*height = dec->height;
return 0;
}
int
jpeg_decoder_get_component_ptr (JpegDecoder * dec, int id,
unsigned char **image, int *rowstride)
{
int i;
i = jpeg_decoder_find_component_by_id (dec, id);
if (image)
*image = dec->components[i].image;
if (rowstride)
*rowstride = dec->components[i].rowstride;
return 0;
}
int
jpeg_decoder_get_component_size (JpegDecoder * dec, int id,
int *width, int *height)
{
int i;
/* subsampling sizes are rounded up */
i = jpeg_decoder_find_component_by_id (dec, id);
if (width)
*width = (dec->width - 1) / dec->components[i].h_subsample + 1;
if (height)
*height = (dec->height - 1) / dec->components[i].v_subsample + 1;
return 0;
}
int
jpeg_decoder_get_component_subsampling (JpegDecoder * dec, int id,
int *h_subsample, int *v_subsample)
{
int i;
i = jpeg_decoder_find_component_by_id (dec, id);
if (h_subsample)
*h_subsample = dec->components[i].h_subsample;
if (v_subsample)
*v_subsample = dec->components[i].v_subsample;
return 0;
}
#if 0
int
jpeg_decoder_parse (JpegDecoder * dec)
{
JpegBits *bits = &dec->bits;
JpegBits b2;
unsigned int x;
unsigned int tag;
int i;
while (bits->ptr < bits->end) {
x = get_u8 (bits);
if (x != 0xff) {
int n = 0;
while (x != 0xff) {
x = get_u8 (bits);
n++;
}
OIL_DEBUG ("lost sync, skipped %d bytes", n);
}
while (x == 0xff) {
x = get_u8 (bits);
}
tag = x;
OIL_DEBUG ("tag %02x", tag);
b2 = *bits;
for (i = 0; i < n_jpeg_markers - 1; i++) {
if (tag == jpeg_markers[i].tag) {
break;
}
}
OIL_DEBUG ("tag: %s", jpeg_markers[i].name);
if (jpeg_markers[i].func) {
jpeg_markers[i].func (dec, &b2);
} else {
OIL_DEBUG ("unhandled or illegal JPEG marker (0x%02x)", tag);
dumpbits (&b2);
}
if (jpeg_markers[i].flags & JPEG_ENTROPY_SEGMENT) {
jpeg_decoder_decode_entropy_segment (dec, &b2);
}
syncbits (&b2);
bits->ptr = b2.ptr;
}
return 0;
}
#endif
/* misc helper functins */
static char *
sprintbits (char *str, unsigned int bits, int n)
{
int i;
int bit = 1 << (n - 1);
for (i = 0; i < n; i++) {
str[i] = (bits & bit) ? '1' : '0';
bit >>= 1;
}
str[i] = 0;
return str;
}
static void
huffman_table_load_std_jpeg (JpegDecoder * dec)
{
JpegBits b, *bits = &b;
bits->ptr = jpeg_standard_tables;
bits->idx = 0;
bits->end = jpeg_standard_tables + jpeg_standard_tables_size;
huffman_table_init_jpeg (&dec->dc_huff_table[0], bits);
huffman_table_init_jpeg (&dec->ac_huff_table[0], bits);
huffman_table_init_jpeg (&dec->dc_huff_table[1], bits);
huffman_table_init_jpeg (&dec->ac_huff_table[1], bits);
}
syntax highlighted by Code2HTML, v. 0.9.1