/*
* JPEG software copyright:
*
* The authors make NO WARRANTY or representation, either express or implied,
* with respect to this software, its quality, accuracy, merchantability, or
* fitness for a particular purpose. This software is provided "AS IS", and you,
* its user, assume the entire risk as to its quality and accuracy.
*
* This software is copyright (C) 1991, Thomas G. Lane.
* All Rights Reserved except as specified below.
*
* Permission is hereby granted to use, copy, modify, and distribute this
* software (or portions thereof) for any purpose, without fee, subject to these
* conditions:
* (1) If any part of the source code for this software is distributed, then this
* README file must be included, with this copyright and no-warranty notice
* unaltered; and any additions, deletions, or changes to the original files
* must be clearly indicated in accompanying documentation.
* (2) If only executable code is distributed, then the accompanying
* documentation must state that "this software is based in part on the work of
* the Independent JPEG Group".
* (3) Permission for use of this software is granted only if the user accepts
* full responsibility for any undesirable consequences; the authors accept
* NO LIABILITY for damages of any kind.
*
* Permission is NOT granted for the use of any author's name or author's company
* name in advertising or publicity relating to this software or products derived
* from it. This software may be referred to only as "the Independent JPEG
* Group's software".
*
* We specifically permit and encourage the use of this software as the basis of
* commercial products, provided that all warranty or liability claims are
* assumed by the product vendor.
*
*/
/*
* jpeg - This is a quick hack to give xloadimage the ability to
* read a JFIF file. The jpeg sofware is based on the first public
* release of the Independent JPEG Group's free JPEG software.
*
* Graeme Gill 18/11/91
*
*/
#undef DEBUG
#ifdef DEBUG
# define debug(xx) fprintf(stderr,xx)
#else
# define debug(xx)
#endif
#include "image.h"
#include "jpeg.h"
METHODDEF int read_jpeg_data ();
int jpegIdent(fullname, name)
char *fullname, *name;
{
struct decompress_info_struct cinfo;
struct decompress_methods_struct dc_methods;
struct external_methods_struct e_methods;
int retv = 0;
/* Initialize the system-dependent method pointers. */
cinfo.methods = &dc_methods;
cinfo.emethods = &e_methods;
jselerror(&e_methods); /* error/trace message routines */
jselvirtmem(&e_methods); /* memory allocation routines */
dc_methods.d_ui_method_selection = jselwxli;
dc_methods.read_jpeg_data = read_jpeg_data;
/* Tell methods about input file */
cinfo.filename = name;
cinfo.input_file = zopen(fullname);
cinfo.verbose = 1;
cinfo.image = NULL; /* in case we fail */
/* Allocate memory for input buffer. */
cinfo.input_buffer = (char *) (*cinfo.emethods->alloc_small)
((size_t) (JPEG_BUF_SIZE + MIN_UNGET));
cinfo.bytes_in_buffer = 0; /* initialize buffer to empty */
cinfo.eof_found = FALSE;
/* Set up default parameters. */
e_methods.trace_level = 0;
cinfo.do_block_smoothing = FALSE;
cinfo.do_pixel_smoothing = FALSE;
cinfo.out_color_space = CS_RGB;
cinfo.jpeg_color_space = CS_UNKNOWN;
/* Set up to read a JFIF or baseline-JPEG file. */
/* A smarter UI would inspect the first few bytes of the input file */
/* to determine its type. */
jselrjfif(&cinfo);
/* Do it to it! */
if (cinfo.input_file != NULL)
{
if (jpeg_decompress(&cinfo, TRUE))
retv = 1;
zclose(cinfo.input_file);
}
/* Release memory. */
(*cinfo.emethods->free_small) ((void *) cinfo.input_buffer);
/* All done. */
return retv;
}
Image *jpegLoad(fullname,name,verbose)
char *fullname,*name;
unsigned int verbose;
{
struct decompress_info_struct cinfo;
struct decompress_methods_struct dc_methods;
struct external_methods_struct e_methods;
/* Initialize the system-dependent method pointers. */
cinfo.methods = &dc_methods;
cinfo.emethods = &e_methods;
jselerror(&e_methods); /* error/trace message routines */
jselvirtmem(&e_methods); /* memory allocation routines */
dc_methods.d_ui_method_selection = jselwxli;
dc_methods.read_jpeg_data = read_jpeg_data;
cinfo.eof_found = FALSE;
/* Tell methods about input file */
cinfo.filename = name;
cinfo.input_file = zopen(fullname);
cinfo.verbose = verbose;
cinfo.image = NULL; /* in case we fail */
cinfo.rows_put = 0;
/* Allocate memory for input buffer. */
cinfo.input_buffer = (char *) (*cinfo.emethods->alloc_small)
((size_t) (JPEG_BUF_SIZE + MIN_UNGET));
cinfo.bytes_in_buffer = 0; /* initialize buffer to empty */
/* Set up default parameters. */
e_methods.trace_level = 0;
cinfo.do_block_smoothing = FALSE;
cinfo.do_pixel_smoothing = FALSE;
cinfo.out_color_space = CS_RGB;
cinfo.jpeg_color_space = CS_UNKNOWN;
/* Set up to read a JFIF or baseline-JPEG file. */
/* A smarter UI would inspect the first few bytes of the input file */
/* to determine its type. */
jselrjfif(&cinfo);
/* Do it to it! */
if (cinfo.input_file != NULL)
{
jpeg_decompress(&cinfo, FALSE);
if (cinfo.image != NULL && cinfo.eof_found)
fprintf(stderr, "jpeg: Short read data in file");
zclose(cinfo.input_file);
}
/* Release memory. */
(*cinfo.emethods->free_small) ((void *) cinfo.input_buffer);
/* All done. */
return (cinfo.image);
}
/*****************************************/
/* Output stuff */
/*****************************************/
METHODDEF void
output_init (cinfo)
decompress_info_ptr cinfo;
{
int i;
if (cinfo->out_color_space == CS_GRAYSCALE)
{
cinfo->image = newRGBImage(cinfo->image_width,cinfo->image_height,8);
cinfo->image->title = dupString(cinfo->filename);
/* set a linear map */
for(i=0;i<256;i++)
{
*(cinfo->image->rgb.red + i) =
*(cinfo->image->rgb.green + i) =
*(cinfo->image->rgb.blue + i) = i<<8;
}
cinfo->image->rgb.used = 256;
}
else if (cinfo->out_color_space == CS_RGB)
{
cinfo->image = newTrueImage(cinfo->image_width,cinfo->image_height);
cinfo->image->title = dupString(cinfo->filename);
}
else
{
cinfo->image = NULL;
fprintf(stderr, "Can't cope with JPEG image type\n");
}
}
/*
* Write some pixel data.
*/
METHODDEF void
put_pixel_rows (cinfo, num_rows, pixel_data)
decompress_info_ptr cinfo;
int num_rows;
JSAMPIMAGE pixel_data;
{
register unsigned char *bufp;
register JSAMPROW ptr0, ptr1, ptr2;
register long col;
register long width = cinfo->image_width;
register int row;
/* Assume JSAMPLE == chars */
if (cinfo->out_color_space == CS_GRAYSCALE)
{
bufp = cinfo->image->data + cinfo->rows_put * width;
for (row = 0; row < num_rows; row++)
{
memcpy(bufp, pixel_data[0][row], width);
bufp += width;
}
}
else
{
bufp = cinfo->image->data + cinfo->rows_put * width * 3;
for (row = 0; row < num_rows; row++)
{
ptr0 = pixel_data[0][row];
ptr1 = pixel_data[1][row];
ptr2 = pixel_data[2][row];
for (col = width; col > 0; col--)
{
*bufp = *ptr0;
bufp++; ptr0++;
*bufp = *ptr1;
bufp++; ptr1++;
*bufp = *ptr2;
bufp++; ptr2++;
}
}
}
cinfo->rows_put += num_rows;
}
/*
* Finish up at the end of the file.
*/
METHODDEF void
output_term (cinfo)
decompress_info_ptr cinfo;
{
zclose(cinfo->input_file);
}
/*
* The method selection routine for xloadimage internal format output.
*/
GLOBAL void
jselwxli (cinfo)
decompress_info_ptr cinfo;
{
/* if grayscale or CMYK input, force similar output; */
/* else leave the output colorspace as set by options. */
if (cinfo->jpeg_color_space == CS_GRAYSCALE)
cinfo->out_color_space = CS_GRAYSCALE;
else if (cinfo->jpeg_color_space == CS_CMYK)
cinfo->out_color_space = CS_CMYK;
cinfo->methods->output_init = output_init;
cinfo->methods->put_pixel_rows = put_pixel_rows;
cinfo->methods->output_term = output_term;
}
/*****************************************/
/* Input Stuff */
/*****************************************/
/*
* Reload the input buffer after it's been emptied, and return the next byte.
* See the JGETC macro for calling conditions.
*
* This routine would need to be replaced if reading JPEG data from something
* other than a stdio stream.
*/
METHODDEF int
read_jpeg_data (cinfo)
decompress_info_ptr cinfo;
{
cinfo->bytes_in_buffer = zread(cinfo->input_file,
cinfo->input_buffer + MIN_UNGET,
JPEG_BUF_SIZE);
cinfo->next_input_byte = cinfo->input_buffer + MIN_UNGET;
if (cinfo->bytes_in_buffer <= 0)
cinfo->eof_found = TRUE;
return JGETC(cinfo);
}
/* ########################################################################## */
/*
* jdmaster.c
*
*/
METHODDEF void
d_per_scan_method_selection (cinfo)
decompress_info_ptr cinfo;
/* Central point for per-scan method selection */
{
/* MCU disassembly */
jseldmcu(cinfo);
/* Un-subsampling of pixels */
jselunsubsample(cinfo);
}
LOCAL void
d_initial_method_selection (cinfo)
decompress_info_ptr cinfo;
/* Central point for initial method selection (after reading file header) */
{
/* JPEG file scanning method selection is already done. */
/* So is output file format selection (both are done by user interface). */
/* Entropy decoding: either Huffman or arithmetic coding. */
#ifdef ARITH_CODING_SUPPORTED
jseldarithmetic(cinfo);
#else
if (cinfo->arith_code) {
ERREXIT(cinfo->emethods, "Arithmetic coding not supported");
}
#endif
jseldhuffman(cinfo);
/* Cross-block smoothing */
#ifdef BLOCK_SMOOTHING_SUPPORTED
jselbsmooth(cinfo);
#else
cinfo->do_block_smoothing = FALSE;
#endif
/* Gamma and color space conversion */
jseldcolor(cinfo);
/* Pipeline control */
jseldpipeline(cinfo);
/* Overall control (that's me!) */
cinfo->methods->d_per_scan_method_selection = d_per_scan_method_selection;
}
LOCAL void
initial_setup (cinfo)
decompress_info_ptr cinfo;
/* Do computations that are needed before initial method selection */
{
short ci;
jpeg_component_info *compptr;
/* Compute maximum sampling factors; check factor validity */
cinfo->max_h_samp_factor = 1;
cinfo->max_v_samp_factor = 1;
for (ci = 0; ci < cinfo->num_components; ci++) {
compptr = &cinfo->comp_info[ci];
if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||
compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
ERREXIT(cinfo->emethods, "Bogus sampling factors");
cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,
compptr->h_samp_factor);
cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,
compptr->v_samp_factor);
}
/* Compute logical subsampled dimensions of components */
for (ci = 0; ci < cinfo->num_components; ci++) {
compptr = &cinfo->comp_info[ci];
compptr->true_comp_width = (cinfo->image_width * compptr->h_samp_factor
+ cinfo->max_h_samp_factor - 1)
/ cinfo->max_h_samp_factor;
compptr->true_comp_height = (cinfo->image_height * compptr->v_samp_factor
+ cinfo->max_v_samp_factor - 1)
/ cinfo->max_v_samp_factor;
}
}
/*
* This is the main entry point to the JPEG decompressor.
* Set identify TRUE if you just want to check if this is a JPEG file.
* This returns TRUE if we think it is a JPEG file.
*/
GLOBAL boolean
jpeg_decompress (cinfo, identify)
decompress_info_ptr cinfo;
boolean identify;
{
short i;
boolean retv = FALSE;
/* Initialize pointers as needed to mark stuff unallocated. */
cinfo->comp_info = NULL;
for (i = 0; i < NUM_QUANT_TBLS; i++)
cinfo->quant_tbl_ptrs[i] = NULL;
for (i = 0; i < NUM_HUFF_TBLS; i++) {
cinfo->dc_huff_tbl_ptrs[i] = NULL;
cinfo->ac_huff_tbl_ptrs[i] = NULL;
}
/* Read the JPEG file header markers; everything up through the first SOS
* marker is read now. NOTE: the user interface must have initialized the
* read_file_header method pointer (eg, by calling jselrjfif or jselrtiff).
* The other file reading methods (read_scan_header etc.) were probably
* set at the same time, but could be set up by read_file_header itself.
*/
if (! ((*cinfo->methods->read_file_header) (cinfo)))
goto rett; /* image will be null */
if (! ((*cinfo->methods->read_scan_header) (cinfo)))
goto rett; /* Empty JPEG file - something went wrong */
if (cinfo->verbose)
{
fprintf(stderr, "%s is a %dx%d JPEG Image, color space ",
cinfo->filename, (int) cinfo->image_width, (int) cinfo->image_height);
switch (cinfo->jpeg_color_space)
{
case CS_UNKNOWN:
fprintf(stderr, "Unknown");
break;
case CS_GRAYSCALE:
fprintf(stderr, "Grayscale");
break;
case CS_RGB:
fprintf(stderr, "RGB");
break;
case CS_YCbCr:
fprintf(stderr, "YCbCr");
break;
case CS_YIQ:
fprintf(stderr, "YIQ");
break;
case CS_CMYK:
fprintf(stderr, "CMYK");
break;
}
fprintf(stderr, ", %d comp%s,",cinfo->num_components, cinfo->num_components ? "s." : ".");
if (cinfo->arith_code)
fprintf(stderr, " Arithmetic coding\n");
else
fprintf(stderr, " Huffman coding\n");
}
if (identify)
{
retv = TRUE;
goto rett;
}
/* Give UI a chance to adjust decompression parameters and select */
/* output file format based on info from file header. */
(*cinfo->methods->d_ui_method_selection) (cinfo);
/* Now select methods for decompression steps. */
initial_setup(cinfo);
d_initial_method_selection(cinfo);
/* Initialize the output file & other modules as needed */
(*cinfo->methods->output_init) (cinfo);
(*cinfo->methods->colorout_init) (cinfo);
/* And let the pipeline controller do the rest. */
(*cinfo->methods->d_pipeline_controller) (cinfo);
/* Finish output file, release working storage, etc */
(*cinfo->methods->colorout_term) (cinfo);
(*cinfo->methods->output_term) (cinfo);
(*cinfo->methods->read_file_trailer) (cinfo);
/* Release allocated storage for tables */
#define FREE(ptr) if ((ptr) != NULL) \
(*cinfo->emethods->free_small) ((void *) ptr)
rett:
FREE(cinfo->comp_info);
for (i = 0; i < NUM_QUANT_TBLS; i++)
FREE(cinfo->quant_tbl_ptrs[i]);
for (i = 0; i < NUM_HUFF_TBLS; i++) {
FREE(cinfo->dc_huff_tbl_ptrs[i]);
FREE(cinfo->ac_huff_tbl_ptrs[i]);
}
if (cinfo->image != NULL)
retv = TRUE;
/* My, that was easy, wasn't it? */
return retv;
}
/* ########################################################################## */
/*
* jrdjfif.c
*
*/
typedef enum { /* JPEG marker codes */
M_SOF0 = 0xc0,
M_SOF1 = 0xc1,
M_SOF2 = 0xc2,
M_SOF3 = 0xc3,
M_SOF5 = 0xc5,
M_SOF6 = 0xc6,
M_SOF7 = 0xc7,
M_JPG = 0xc8,
M_SOF9 = 0xc9,
M_SOF10 = 0xca,
M_SOF11 = 0xcb,
M_SOF13 = 0xcd,
M_SOF14 = 0xce,
M_SOF15 = 0xcf,
M_DHT = 0xc4,
M_DAC = 0xcc,
M_RST0 = 0xd0,
M_RST1 = 0xd1,
M_RST2 = 0xd2,
M_RST3 = 0xd3,
M_RST4 = 0xd4,
M_RST5 = 0xd5,
M_RST6 = 0xd6,
M_RST7 = 0xd7,
M_SOI = 0xd8,
M_EOI = 0xd9,
M_SOS = 0xda,
M_DQT = 0xdb,
M_DNL = 0xdc,
M_DRI = 0xdd,
M_DHP = 0xde,
M_EXP = 0xdf,
M_APP0 = 0xe0,
M_APP15 = 0xef,
M_JPG0 = 0xf0,
M_JPG13 = 0xfd,
M_COM = 0xfe,
M_TEM = 0x01,
M_ERROR = 0x100
} JPEG_MARKER;
/*
* Routines to parse JPEG markers & save away the useful info.
*/
LOCAL INT32
get_2bytes (cinfo)
decompress_info_ptr cinfo;
/* Get a 2-byte unsigned integer (e.g., a marker parameter length field) */
{
INT32 a;
a = JGETC(cinfo);
return (a << 8) + JGETC(cinfo);
}
LOCAL void
skip_variable (cinfo, code)
decompress_info_ptr cinfo; int code;
/* Skip over an unknown or uninteresting variable-length marker */
{
INT32 length;
length = get_2bytes(cinfo);
TRACEMS2(cinfo->emethods, 1,
"Skipping marker 0x%02x, length %d", code, length);
for (length -= 2; length > 0; length--)
(void) JGETC(cinfo);
}
LOCAL void
get_dht (cinfo)
decompress_info_ptr cinfo;
/* Process a DHT marker */
{
INT32 length;
UINT8 bits[17];
UINT8 huffval[256];
int i, index, count;
HUFF_TBL **htblptr;
length = get_2bytes(cinfo)-2;
while (length > 0) {
index = JGETC(cinfo);
TRACEMS1(cinfo->emethods, 1, "Define Huffman Table 0x%02x", index);
bits[0] = 0;
count = 0;
for (i = 1; i <= 16; i++) {
bits[i] = JGETC(cinfo);
count += bits[i];
}
TRACEMS8(cinfo->emethods, 2, " %3d %3d %3d %3d %3d %3d %3d %3d",
bits[1], bits[2], bits[3], bits[4],
bits[5], bits[6], bits[7], bits[8]);
TRACEMS8(cinfo->emethods, 2, " %3d %3d %3d %3d %3d %3d %3d %3d",
bits[9], bits[10], bits[11], bits[12],
bits[13], bits[14], bits[15], bits[16]);
if (count > 256)
ERREXIT(cinfo->emethods, "Bogus DHT counts");
for (i = 0; i < count; i++)
huffval[i] = JGETC(cinfo);
length -= 1 + 16 + count;
if (index & 0x10) { /* AC table definition */
index -= 0x10;
htblptr = &cinfo->ac_huff_tbl_ptrs[index];
} else { /* DC table definition */
htblptr = &cinfo->dc_huff_tbl_ptrs[index];
}
if (index < 0 || index >= NUM_HUFF_TBLS)
ERREXIT1(cinfo->emethods, "Bogus DHT index %d", index);
if (*htblptr == NULL)
*htblptr = (HUFF_TBL *)(*cinfo->emethods->alloc_small) (SIZEOF(HUFF_TBL));
memcpy((void *) (*htblptr)->bits, (void *) bits,
SIZEOF((*htblptr)->bits));
memcpy((void *) (*htblptr)->huffval, (void *) huffval,
SIZEOF((*htblptr)->huffval));
}
}
LOCAL void
get_dac (cinfo)
decompress_info_ptr cinfo;
/* Process a DAC marker */
{
INT32 length;
int index, val;
length = get_2bytes(cinfo)-2;
while (length > 0) {
index = JGETC(cinfo);
val = JGETC(cinfo);
TRACEMS2(cinfo->emethods, 1,
"Define Arithmetic Table 0x%02x: 0x%02x", index, val);
if (index < 0 || index >= (2*NUM_ARITH_TBLS))
ERREXIT1(cinfo->emethods, "Bogus DAC index %d", index);
if (index >= NUM_ARITH_TBLS) { /* define AC table */
cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = val;
} else { /* define DC table */
cinfo->arith_dc_L[index] = val & 0x0F;
cinfo->arith_dc_U[index] = val >> 4;
if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index])
ERREXIT1(cinfo->emethods, "Bogus DAC value 0x%x", val);
}
length -= 2;
}
}
LOCAL void
get_dqt (cinfo)
decompress_info_ptr cinfo;
/* Process a DQT marker */
{
INT32 length;
int n, i, prec;
UINT16 tmp;
QUANT_TBL_PTR quant_ptr;
length = get_2bytes(cinfo) - 2;
while (length > 0) {
n = JGETC(cinfo);
prec = n >> 4;
n &= 0x0F;
TRACEMS2(cinfo->emethods, 1,
"Define Quantization Table %d precision %d", n, prec);
if (n >= NUM_QUANT_TBLS)
ERREXIT1(cinfo->emethods, "Bogus table number %d", n);
if (cinfo->quant_tbl_ptrs[n] == NULL)
cinfo->quant_tbl_ptrs[n] = (QUANT_TBL_PTR)(*cinfo->emethods->alloc_small) (SIZEOF(QUANT_TBL));
quant_ptr = cinfo->quant_tbl_ptrs[n];
for (i = 0; i < DCTSIZE2; i++) {
tmp = JGETC(cinfo);
if (prec)
tmp = (tmp<<8) + JGETC(cinfo);
quant_ptr[i] = tmp;
}
for (i = 0; i < DCTSIZE2; i += 8) {
TRACEMS8(cinfo->emethods, 2, " %4d %4d %4d %4d %4d %4d %4d %4d",
quant_ptr[i ], quant_ptr[i+1], quant_ptr[i+2], quant_ptr[i+3],
quant_ptr[i+4], quant_ptr[i+5], quant_ptr[i+6], quant_ptr[i+7]);
}
length -= DCTSIZE2+1;
if (prec) length -= DCTSIZE2;
}
}
LOCAL void
get_dri (cinfo)
decompress_info_ptr cinfo;
/* Process a DRI marker */
{
if (get_2bytes(cinfo) != 4)
ERREXIT(cinfo->emethods, "Bogus length in DRI");
cinfo->restart_interval = get_2bytes(cinfo);
TRACEMS1(cinfo->emethods, 1,
"Define Restart Interval %d", cinfo->restart_interval);
}
LOCAL void
get_app0 (cinfo)
decompress_info_ptr cinfo;
/* Process an APP0 marker */
{
#define JFIF_LEN 14
INT32 length;
UINT8 b[JFIF_LEN];
int buffp;
length = get_2bytes(cinfo) - 2;
/* See if a JFIF APP0 marker is present */
if (length >= JFIF_LEN) {
for (buffp = 0; buffp < JFIF_LEN; buffp++)
b[buffp] = JGETC(cinfo);
length -= JFIF_LEN;
if (b[0]=='J' && b[1]=='F' && b[2]=='I' && b[3]=='F' && b[4]==0) {
/* Found JFIF APP0 marker: check version */
/* Major version must be 1 */
if (b[5] != 1)
ERREXIT2(cinfo->emethods, "Unsupported JFIF revision number %d.%02d",
b[5], b[6]);
/* Minor version should be 0 or 1, but try to process anyway if newer */
if (b[6] != 0 && b[6] != 1)
TRACEMS2(cinfo->emethods, 0, "Warning: unknown JFIF revision number %d.%02d",
b[5], b[6]);
/* Save info */
cinfo->density_unit = b[7];
cinfo->X_density = (b[8] << 8) + b[9];
cinfo->Y_density = (b[10] << 8) + b[11];
/* Assume colorspace is YCbCr, unless UI has overridden me */
if (cinfo->jpeg_color_space == CS_UNKNOWN)
cinfo->jpeg_color_space = CS_YCbCr;
TRACEMS3(cinfo->emethods, 1, "JFIF APP0 marker, density %dx%d %d",
cinfo->X_density, cinfo->Y_density, cinfo->density_unit);
} else {
TRACEMS(cinfo->emethods, 1, "Unknown APP0 marker (not JFIF)");
}
} else {
TRACEMS1(cinfo->emethods, 1,
"Short APP0 marker, length %d", (int) length);
}
while (length-- > 0) /* skip any remaining data */
(void) JGETC(cinfo);
}
LOCAL void
get_sof (cinfo, code)
decompress_info_ptr cinfo;
int code;
/* Process a SOFn marker */
{
INT32 length;
short ci;
int c;
jpeg_component_info * compptr;
length = get_2bytes(cinfo);
cinfo->data_precision = JGETC(cinfo);
cinfo->image_height = get_2bytes(cinfo);
cinfo->image_width = get_2bytes(cinfo);
cinfo->num_components = JGETC(cinfo);
TRACEMS4(cinfo->emethods, 1,
"Start Of Frame 0x%02x: width=%d, height=%d, components=%d",
code, cinfo->image_width, cinfo->image_height,
cinfo->num_components);
/* We don't support files in which the image height is initially specified */
/* as 0 and is later redefined by DNL. As long as we have to check that, */
/* might as well have a general sanity check. */
if (cinfo->image_height <= 0 || cinfo->image_width <= 0
|| cinfo->num_components <= 0)
ERREXIT(cinfo->emethods, "Empty JPEG image (DNL not supported)");
#ifdef EIGHT_BIT_SAMPLES
if (cinfo->data_precision != 8)
ERREXIT(cinfo->emethods, "Unsupported JPEG data precision");
#endif
#ifdef TWELVE_BIT_SAMPLES
if (cinfo->data_precision != 12) /* this needs more thought?? */
ERREXIT(cinfo->emethods, "Unsupported JPEG data precision");
#endif
#ifdef SIXTEEN_BIT_SAMPLES
if (cinfo->data_precision != 16) /* this needs more thought?? */
ERREXIT(cinfo->emethods, "Unsupported JPEG data precision");
#endif
if (length != (cinfo->num_components * 3 + 8))
ERREXIT(cinfo->emethods, "Bogus SOF length");
cinfo->comp_info = (jpeg_component_info *)((*cinfo->emethods->alloc_small)
(cinfo->num_components * SIZEOF(jpeg_component_info)));
for (ci = 0; ci < cinfo->num_components; ci++) {
compptr = &cinfo->comp_info[ci];
compptr->component_index = ci;
compptr->component_id = JGETC(cinfo);
c = JGETC(cinfo);
compptr->h_samp_factor = (c >> 4) & 15;
compptr->v_samp_factor = (c ) & 15;
compptr->quant_tbl_no = JGETC(cinfo);
TRACEMS4(cinfo->emethods, 1, " Component %d: %dhx%dv q=%d",
compptr->component_id, compptr->h_samp_factor,
compptr->v_samp_factor, compptr->quant_tbl_no);
}
}
LOCAL void
get_sos (cinfo)
decompress_info_ptr cinfo;
/* Process a SOS marker */
{
INT32 length;
int i, ci, n, c, cc;
jpeg_component_info * compptr;
length = get_2bytes(cinfo);
n = JGETC(cinfo); /* Number of components */
cinfo->comps_in_scan = n;
length -= 3;
if (length != (n * 2 + 3) || n < 1 || n > MAX_COMPS_IN_SCAN)
ERREXIT(cinfo->emethods, "Bogus SOS length");
TRACEMS1(cinfo->emethods, 1, "Start Of Scan: %d components", n);
for (i = 0; i < n; i++) {
cc = JGETC(cinfo);
c = JGETC(cinfo);
length -= 2;
for (ci = 0; ci < cinfo->num_components; ci++)
if (cc == cinfo->comp_info[ci].component_id)
break;
if (ci >= cinfo->num_components)
ERREXIT(cinfo->emethods, "Invalid component number in SOS");
compptr = &cinfo->comp_info[ci];
cinfo->cur_comp_info[i] = compptr;
compptr->dc_tbl_no = (c >> 4) & 15;
compptr->ac_tbl_no = (c ) & 15;
TRACEMS3(cinfo->emethods, 1, " c%d: [dc=%d ac=%d]", cc,
compptr->dc_tbl_no, compptr->ac_tbl_no);
}
while (length > 0) {
(void) JGETC(cinfo);
length--;
}
}
LOCAL void
get_soi (cinfo)
decompress_info_ptr cinfo;
/* Process an SOI marker */
{
int i;
TRACEMS(cinfo->emethods, 1, "Start of Image");
/* Reset all parameters that are defined to be reset by SOI */
for (i = 0; i < NUM_ARITH_TBLS; i++) {
cinfo->arith_dc_L[i] = 0;
cinfo->arith_dc_U[i] = 1;
cinfo->arith_ac_K[i] = 5;
}
cinfo->restart_interval = 0;
cinfo->density_unit = 0; /* set default JFIF APP0 values */
cinfo->X_density = 1;
cinfo->Y_density = 1;
cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling */
}
LOCAL int
next_marker (cinfo)
decompress_info_ptr cinfo;
/* Find the next JPEG marker */
/* Note that the output might not be a valid marker code, */
/* but it will never be 0 or FF */
{
int c, nbytes;
nbytes = 0;
do {
do { /* skip any non-FF bytes */
nbytes++;
c = JGETC(cinfo);
} while (c != 0xFF && !cinfo->eof_found);
do { /* skip any duplicate FFs */
nbytes++;
c = JGETC(cinfo);
} while (c == 0xFF && !cinfo->eof_found);
} while (c == 0 && !cinfo->eof_found); /* repeat if it was a stuffed FF/00 */
if (nbytes != 2)
TRACEMS2(cinfo->emethods, 1, "Skipped %d bytes before marker 0x%02x",
nbytes-2, c);
return c;
}
LOCAL JPEG_MARKER
process_tables (cinfo)
decompress_info_ptr cinfo;
/* Scan and process JPEG markers that can appear in any order */
/* Return when an SOI, EOI, SOFn, or SOS is found */
{
int c;
while (TRUE) {
c = next_marker(cinfo);
if (cinfo->eof_found)
return 0;
switch (c) {
case M_SOF0:
case M_SOF1:
case M_SOF2:
case M_SOF3:
case M_SOF5:
case M_SOF6:
case M_SOF7:
case M_JPG:
case M_SOF9:
case M_SOF10:
case M_SOF11:
case M_SOF13:
case M_SOF14:
case M_SOF15:
case M_SOI:
case M_EOI:
case M_SOS:
return c;
case M_DHT:
get_dht(cinfo);
break;
case M_DAC:
get_dac(cinfo);
break;
case M_DQT:
get_dqt(cinfo);
break;
case M_DRI:
get_dri(cinfo);
break;
case M_APP0:
get_app0(cinfo);
break;
case M_RST0: /* these are all parameterless */
case M_RST1:
case M_RST2:
case M_RST3:
case M_RST4:
case M_RST5:
case M_RST6:
case M_RST7:
case M_TEM:
TRACEMS1(cinfo->emethods, 1, "Unexpected marker 0x%02x", c);
break;
default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn */
skip_variable(cinfo, c);
break;
}
}
}
/*
* Initialize and read the file header (everything through the SOF marker).
* Return FALSE if we don't recognize the file.
*/
METHODDEF boolean
read_file_header (cinfo)
decompress_info_ptr cinfo;
{
int c;
/* Expect an SOI marker first */
if (next_marker(cinfo) == M_SOI)
get_soi(cinfo);
else
return FALSE;
/* Process markers until SOF */
c = process_tables(cinfo);
switch (c) {
case M_SOF0:
case M_SOF1:
get_sof(cinfo, c);
cinfo->arith_code = FALSE;
break;
case M_SOF9:
get_sof(cinfo, c);
cinfo->arith_code = TRUE;
break;
default:
/* Unsupported SOF marker type */
fprintf(stderr, "unsupported SOF marker type 0x%02x\n", c);
return FALSE;
}
/* Figure out what colorspace we have */
/* (too bad the JPEG committee didn't provide a real way to specify this) */
switch (cinfo->num_components) {
case 1:
cinfo->jpeg_color_space = CS_GRAYSCALE;
break;
case 3:
/* if we saw a JFIF marker, leave it set to YCbCr; */
/* also leave it alone if UI has provided a value */
if (cinfo->jpeg_color_space == CS_UNKNOWN) {
short cid0 = cinfo->comp_info[0].component_id;
short cid1 = cinfo->comp_info[1].component_id;
short cid2 = cinfo->comp_info[2].component_id;
if (cid0 == 1 && cid1 == 2 && cid2 == 3)
cinfo->jpeg_color_space = CS_YCbCr; /* assume it's JFIF w/out marker */
else if (cid0 == 1 && cid1 == 4 && cid2 == 5)
cinfo->jpeg_color_space = CS_YIQ; /* prototype's YIQ matrix */
else {
TRACEMS3(cinfo->emethods, 0,
"Unrecognized component IDs %d %d %d, assuming YCbCr",
cid0, cid1, cid2);
cinfo->jpeg_color_space = CS_YCbCr;
}
}
break;
case 4:
cinfo->jpeg_color_space = CS_CMYK;
break;
default:
cinfo->jpeg_color_space = CS_UNKNOWN;
break;
}
return TRUE;
}
/*
* Read the start of a scan (everything through the SOS marker).
* Return TRUE if find SOS, FALSE if find EOI.
*/
METHODDEF boolean
read_scan_header (cinfo)
decompress_info_ptr cinfo;
{
int c;
/* Process markers until SOS or EOI */
c = process_tables(cinfo);
switch (c) {
case M_SOS:
get_sos(cinfo);
return TRUE;
case M_EOI:
TRACEMS(cinfo->emethods, 1, "End Of Image");
return FALSE;
default:
if (cinfo->eof_found)
return FALSE;
ERREXIT1(cinfo->emethods, "Unexpected marker 0x%02x", c);
break;
}
return FALSE; /* keeps lint happy */
}
/*
* Finish up after a compressed scan (series of read_jpeg_data calls);
* prepare for another read_scan_header call.
*/
METHODDEF void
read_scan_trailer (cinfo)
decompress_info_ptr cinfo;
{
/* no work needed */
}
/*
* Finish up at the end of the file.
*/
METHODDEF void
read_file_trailer (cinfo)
decompress_info_ptr cinfo;
{
/* no work needed */
}
/*
* The method selection routine for standard JPEG header reading.
* Note that this must be called by the user interface before calling
* jpeg_decompress. When a non-JFIF file is to be decompressed (TIFF,
* perhaps), the user interface must discover the file type and call
* the appropriate method selection routine.
*/
GLOBAL void
jselrjfif (cinfo)
decompress_info_ptr cinfo;
{
cinfo->methods->read_file_header = read_file_header;
cinfo->methods->read_scan_header = read_scan_header;
/* For JFIF/raw-JPEG format, the user interface supplies read_jpeg_data. */
#if 0
cinfo->methods->read_jpeg_data = read_jpeg_data;
#endif
cinfo->methods->read_scan_trailer = read_scan_trailer;
cinfo->methods->read_file_trailer = read_file_trailer;
}
/* ########################################################################## */
/*
* jdpipe.c
*
*/
/*
* About the data structures:
*
* The processing chunk size for unsubsampling is referred to in this file as
* a "row group": a row group is defined as Vk (v_samp_factor) sample rows of
* any component while subsampled, or Vmax (max_v_samp_factor) unsubsampled
* rows. In an interleaved scan each MCU row contains exactly DCTSIZE row
* groups of each component in the scan. In a noninterleaved scan an MCU row
* is one row of blocks, which might not be an integral number of row groups;
* therefore, we read in Vk MCU rows to obtain the same amount of data as we'd
* have in an interleaved scan.
* To provide context for the unsubsampling step, we have to retain the last
* two row groups of the previous MCU row while reading in the next MCU row
* (or set of Vk MCU rows). To do this without copying data about, we create
* a rather strange data structure. Exactly DCTSIZE+2 row groups of samples
* are allocated, but we create two different sets of pointers to this array.
* The second set swaps the last two pairs of row groups. By working
* alternately with the two sets of pointers, we can access the data in the
* desired order.
*
* Cross-block smoothing also needs context above and below the "current" row.
* Since this is an optional feature, I've implemented it in a way that is
* much simpler but requires more than the minimum amount of memory. We
* simply allocate three extra MCU rows worth of coefficient blocks and use
* them to "read ahead" one MCU row in the file. For a typical 1000-pixel-wide
* image with 2x2,1x1,1x1 sampling, each MCU row is about 50Kb; an 80x86
* machine may be unable to apply cross-block smoothing to wider images.
*/
/*
* These variables are logically local to the pipeline controller,
* but we make them static so that scan_big_image can use them
* without having to pass them through the quantization routines.
* If you don't support 2-pass quantization, you could make them locals.
*/
static int rows_in_mem; /* # of sample rows in full-size buffers */
/* Full-size image array holding desubsampled, color-converted data. */
/*
* Utility routines: common code for pipeline controllers
*/
LOCAL void
interleaved_scan_setup (cinfo)
decompress_info_ptr cinfo;
/* Compute all derived info for an interleaved (multi-component) scan */
/* On entry, cinfo->comps_in_scan and cinfo->cur_comp_info[] are set up */
{
short ci, mcublks;
jpeg_component_info *compptr;
if (cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)
ERREXIT(cinfo->emethods, "Too many components for interleaved scan");
cinfo->MCUs_per_row = (cinfo->image_width
+ cinfo->max_h_samp_factor*DCTSIZE - 1)
/ (cinfo->max_h_samp_factor*DCTSIZE);
cinfo->MCU_rows_in_scan = (cinfo->image_height
+ cinfo->max_v_samp_factor*DCTSIZE - 1)
/ (cinfo->max_v_samp_factor*DCTSIZE);
cinfo->blocks_in_MCU = 0;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
/* for interleaved scan, sampling factors give # of blocks per component */
compptr->MCU_width = compptr->h_samp_factor;
compptr->MCU_height = compptr->v_samp_factor;
compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
/* compute physical dimensions of component */
compptr->subsampled_width = jround_up(compptr->true_comp_width,
(long) (compptr->MCU_width*DCTSIZE));
compptr->subsampled_height = jround_up(compptr->true_comp_height,
(long) (compptr->MCU_height*DCTSIZE));
/* Sanity check */
if (compptr->subsampled_width !=
(cinfo->MCUs_per_row * (compptr->MCU_width*DCTSIZE)))
ERREXIT(cinfo->emethods, "I'm confused about the image width");
/* Prepare array describing MCU composition */
mcublks = compptr->MCU_blocks;
if (cinfo->blocks_in_MCU + mcublks > MAX_BLOCKS_IN_MCU)
ERREXIT(cinfo->emethods, "Sampling factors too large for interleaved scan");
while (mcublks-- > 0) {
cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
}
}
(*cinfo->methods->d_per_scan_method_selection) (cinfo);
}
LOCAL void
noninterleaved_scan_setup (cinfo)
decompress_info_ptr cinfo;
/* Compute all derived info for a noninterleaved (single-component) scan */
/* On entry, cinfo->comps_in_scan = 1 and cinfo->cur_comp_info[0] is set up */
{
jpeg_component_info *compptr = cinfo->cur_comp_info[0];
/* for noninterleaved scan, always one block per MCU */
compptr->MCU_width = 1;
compptr->MCU_height = 1;
compptr->MCU_blocks = 1;
/* compute physical dimensions of component */
compptr->subsampled_width = jround_up(compptr->true_comp_width,
(long) DCTSIZE);
compptr->subsampled_height = jround_up(compptr->true_comp_height,
(long) DCTSIZE);
cinfo->MCUs_per_row = compptr->subsampled_width / DCTSIZE;
cinfo->MCU_rows_in_scan = compptr->subsampled_height / DCTSIZE;
/* Prepare array describing MCU composition */
cinfo->blocks_in_MCU = 1;
cinfo->MCU_membership[0] = 0;
(*cinfo->methods->d_per_scan_method_selection) (cinfo);
}
LOCAL void
reverse_DCT (cinfo, coeff_data, output_data, start_row)
decompress_info_ptr cinfo;
JBLOCKIMAGE coeff_data; JSAMPIMAGE output_data;
int start_row;
/* Perform inverse DCT on each block in an MCU row's worth of data; */
/* output the results into a sample array starting at row start_row. */
/* NB: start_row can only be nonzero when dealing with a single-component */
/* scan; otherwise we'd have to provide for different offsets for different */
/* components, since the heights of interleaved MCU rows can vary. */
{
DCTBLOCK block;
JBLOCKROW browptr;
JSAMPARRAY srowptr;
long blocksperrow, bi;
short numrows, ri;
short ci;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
/* calc size of an MCU row in this component */
blocksperrow = cinfo->cur_comp_info[ci]->subsampled_width / DCTSIZE;
numrows = cinfo->cur_comp_info[ci]->MCU_height;
/* iterate through all blocks in MCU row */
for (ri = 0; ri < numrows; ri++) {
browptr = coeff_data[ci][ri];
srowptr = output_data[ci] + (ri * DCTSIZE + start_row);
for (bi = 0; bi < blocksperrow; bi++) {
/* copy the data into a local DCTBLOCK. This allows for change of
* representation (if DCTELEM != JCOEF). On 80x86 machines it also
* brings the data back from FAR storage to NEAR storage.
*/
{ register JCOEFPTR elemptr = browptr[bi];
register DCTELEM *localblkptr = block;
register short elem = DCTSIZE2;
while (--elem >= 0)
*localblkptr++ = (DCTELEM) *elemptr++;
}
j_rev_dct(block); /* perform inverse DCT */
/* output the data into the sample array.
* Note change from signed to unsigned representation:
* DCT calculation works with values +-CENTERJSAMPLE,
* but sample arrays always hold 0..MAXJSAMPLE.
* Have to do explicit range-limiting because of quantization errors
* and so forth in the DCT/IDCT phase.
*/
{ register JSAMPROW elemptr;
register DCTELEM *localblkptr = block;
register short elemr, elemc;
register DCTELEM temp;
for (elemr = 0; elemr < DCTSIZE; elemr++) {
elemptr = srowptr[elemr] + (bi * DCTSIZE);
for (elemc = 0; elemc < DCTSIZE; elemc++) {
temp = (*localblkptr++) + CENTERJSAMPLE;
if (temp < 0) temp = 0;
else if (temp > MAXJSAMPLE) temp = MAXJSAMPLE;
*elemptr++ = (JSAMPLE) temp;
}
}
}
}
}
}
}
LOCAL JSAMPIMAGE
alloc_sampimage (cinfo, num_comps, num_rows, num_cols)
decompress_info_ptr cinfo;
int num_comps;
long num_rows;
long num_cols;
/* Allocate an in-memory sample image (all components same size) */
{
JSAMPIMAGE image;
int ci;
image = (JSAMPIMAGE) (*cinfo->emethods->alloc_small)
(num_comps * SIZEOF(JSAMPARRAY));
for (ci = 0; ci < num_comps; ci++) {
image[ci] = (*cinfo->emethods->alloc_small_sarray) (num_cols, num_rows);
}
return image;
}
LOCAL void
free_sampimage (cinfo, image, num_comps, num_rows)
decompress_info_ptr cinfo;
JSAMPIMAGE image;
int num_comps;
long num_rows;
/* Release a sample image created by alloc_sampimage */
{
int ci;
for (ci = 0; ci < num_comps; ci++) {
(*cinfo->emethods->free_small_sarray) (image[ci], num_rows);
}
(*cinfo->emethods->free_small) ((void *) image);
}
LOCAL JBLOCKIMAGE
alloc_MCU_row (cinfo)
decompress_info_ptr cinfo;
/* Allocate one MCU row's worth of coefficient blocks */
{
JBLOCKIMAGE image;
int ci;
image = (JBLOCKIMAGE) (*cinfo->emethods->alloc_small)
(cinfo->comps_in_scan * SIZEOF(JBLOCKARRAY));
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
image[ci] = (*cinfo->emethods->alloc_small_barray)
(cinfo->cur_comp_info[ci]->subsampled_width / DCTSIZE,
(long) cinfo->cur_comp_info[ci]->MCU_height);
}
return image;
}
LOCAL void
free_MCU_row (cinfo, image)
decompress_info_ptr cinfo;
JBLOCKIMAGE image;
/* Release a coefficient block array created by alloc_MCU_row */
{
int ci;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
(*cinfo->emethods->free_small_barray)
(image[ci], (long) cinfo->cur_comp_info[ci]->MCU_height);
}
(*cinfo->emethods->free_small) ((void *) image);
}
LOCAL void
alloc_sampling_buffer (cinfo, subsampled_data)
decompress_info_ptr cinfo;
JSAMPIMAGE subsampled_data[2];
/* Create a subsampled-data buffer having the desired structure */
/* (see comments at head of file) */
{
short ci, vs, i;
/* Get top-level space for array pointers */
subsampled_data[0] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small)
(cinfo->comps_in_scan * SIZEOF(JSAMPARRAY));
subsampled_data[1] = (JSAMPIMAGE) (*cinfo->emethods->alloc_small)
(cinfo->comps_in_scan * SIZEOF(JSAMPARRAY));
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
vs = cinfo->cur_comp_info[ci]->v_samp_factor; /* row group height */
/* Allocate the real storage */
subsampled_data[0][ci] = (*cinfo->emethods->alloc_small_sarray)
(cinfo->cur_comp_info[ci]->subsampled_width,
(long) (vs * (DCTSIZE+2)));
/* Create space for the scrambled-order pointers */
subsampled_data[1][ci] = (JSAMPARRAY) (*cinfo->emethods->alloc_small)
(vs * (DCTSIZE+2) * SIZEOF(JSAMPROW));
/* Duplicate the first DCTSIZE-2 row groups */
for (i = 0; i < vs * (DCTSIZE-2); i++) {
subsampled_data[1][ci][i] = subsampled_data[0][ci][i];
}
/* Copy the last four row groups in swapped order */
for (i = 0; i < vs * 2; i++) {
subsampled_data[1][ci][vs*DCTSIZE + i] = subsampled_data[0][ci][vs*(DCTSIZE-2) + i];
subsampled_data[1][ci][vs*(DCTSIZE-2) + i] = subsampled_data[0][ci][vs*DCTSIZE + i];
}
}
}
LOCAL void
free_sampling_buffer (cinfo, subsampled_data)
decompress_info_ptr cinfo;
JSAMPIMAGE subsampled_data[2];
/* Release a sampling buffer created by alloc_sampling_buffer */
{
short ci, vs;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
vs = cinfo->cur_comp_info[ci]->v_samp_factor; /* row group height */
/* Free the real storage */
(*cinfo->emethods->free_small_sarray)
(subsampled_data[0][ci], (long) (vs * (DCTSIZE+2)));
/* Free the scrambled-order pointers */
(*cinfo->emethods->free_small) ((void *) subsampled_data[1][ci]);
}
/* Free the top-level space */
(*cinfo->emethods->free_small) ((void *) subsampled_data[0]);
(*cinfo->emethods->free_small) ((void *) subsampled_data[1]);
}
LOCAL void
duplicate_row (image_data, num_cols, source_row, num_rows)
JSAMPARRAY image_data;
long num_cols;
int source_row;
int num_rows;
/* Duplicate the source_row at source_row+1 .. source_row+num_rows */
/* This happens only at the bottom of the image, */
/* so it needn't be super-efficient */
{
register int row;
for (row = 1; row <= num_rows; row++) {
jcopy_sample_rows(image_data, source_row, image_data, source_row + row,
1, num_cols);
}
}
LOCAL void
jexpand (cinfo, subsampled_data, fullsize_data, fullsize_width, above, current, below, out)
decompress_info_ptr cinfo;
JSAMPIMAGE subsampled_data;
JSAMPIMAGE fullsize_data;
long fullsize_width;
short above;
short current;
short below;
short out;
/* Do unsubsampling expansion of a single row group (of each component). */
/* above, current, below are indexes of row groups in subsampled_data; */
/* out is the index of the target row group in fullsize_data. */
/* Special case: above, below can be -1 to indicate top, bottom of image. */
{
jpeg_component_info *compptr;
JSAMPARRAY above_ptr, below_ptr;
JSAMPROW dummy[MAX_SAMP_FACTOR]; /* for subsample expansion at top/bottom */
short ci, vs, i;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
vs = compptr->v_samp_factor; /* row group height */
if (above >= 0)
above_ptr = subsampled_data[ci] + above * vs;
else {
/* Top of image: make a dummy above-context with copies of 1st row */
/* We assume current=0 in this case */
for (i = 0; i < vs; i++)
dummy[i] = subsampled_data[ci][0];
above_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */
}
if (below >= 0)
below_ptr = subsampled_data[ci] + below * vs;
else {
/* Bot of image: make a dummy below-context with copies of last row */
for (i = 0; i < vs; i++)
dummy[i] = subsampled_data[ci][(current+1)*vs-1];
below_ptr = (JSAMPARRAY) dummy; /* possible near->far pointer conv */
}
(*cinfo->methods->unsubsample[ci])
(cinfo, (int) ci,
compptr->subsampled_width, (int) vs,
fullsize_width, (int) cinfo->max_v_samp_factor,
above_ptr,
subsampled_data[ci] + current * vs,
below_ptr,
fullsize_data[ci] + out * cinfo->max_v_samp_factor);
}
}
LOCAL void
emit_1pass (cinfo, num_rows, fullsize_data, color_data)
decompress_info_ptr cinfo;
int num_rows;
JSAMPIMAGE fullsize_data;
JSAMPIMAGE color_data;
/* Do color conversion and output of num_rows full-size rows. */
/* This is not used for 2-pass color quantization. */
{
(*cinfo->methods->color_convert) (cinfo, num_rows,
fullsize_data, color_data);
(*cinfo->methods->put_pixel_rows) (cinfo, num_rows,
color_data);
}
/*
* Support routines for cross-block smoothing.
*/
#ifdef BLOCK_SMOOTHING_SUPPORTED
LOCAL void
smooth_mcu_row (cinfo, above, input, below, output)
decompress_info_ptr cinfo;
JBLOCKIMAGE above;
JBLOCKIMAGE input;
JBLOCKIMAGE below;
JBLOCKIMAGE output;
/* Apply cross-block smoothing to one MCU row's worth of coefficient blocks. */
/* above,below are NULL if at top/bottom of image. */
{
jpeg_component_info *compptr;
short ci, ri, last;
JBLOCKROW prev;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
last = compptr->MCU_height - 1;
if (above == NULL)
prev = NULL;
else
prev = above[ci][last];
for (ri = 0; ri < last; ri++) {
(*cinfo->methods->smooth_coefficients) (cinfo, compptr,
prev, input[ci][ri], input[ci][ri+1],
output[ci][ri]);
prev = input[ci][ri];
}
if (below == NULL)
(*cinfo->methods->smooth_coefficients) (cinfo, compptr,
prev, input[ci][last], (JBLOCKROW) NULL,
output[ci][last]);
else
(*cinfo->methods->smooth_coefficients) (cinfo, compptr,
prev, input[ci][last], below[ci][0],
output[ci][last]);
}
}
LOCAL void
get_smoothed_row (cinfo, coeff_data, bsmooth, whichb, cur_mcu_row)
decompress_info_ptr cinfo;
JBLOCKIMAGE coeff_data;
JBLOCKIMAGE bsmooth[3];
int * whichb;
long cur_mcu_row;
/* Get an MCU row of coefficients, applying cross-block smoothing. */
/* The output row is placed in coeff_data. bsmooth and whichb hold */
/* working state, and cur_row is needed to check for image top/bottom. */
/* This routine just takes care of the buffering logic. */
{
int prev, cur, next;
/* Special case for top of image: need to pre-fetch a row & init whichb */
if (cur_mcu_row == 0) {
(*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[0]);
if (cinfo->MCU_rows_in_scan > 1) {
(*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[1]);
smooth_mcu_row(cinfo, (JBLOCKIMAGE) NULL, bsmooth[0], bsmooth[1],
coeff_data);
} else {
smooth_mcu_row(cinfo, (JBLOCKIMAGE) NULL, bsmooth[0], (JBLOCKIMAGE) NULL,
coeff_data);
}
*whichb = 1; /* points to next bsmooth[] element to use */
return;
}
cur = *whichb; /* set up references */
prev = (cur == 0 ? 2 : cur - 1);
next = (cur == 2 ? 0 : cur + 1);
*whichb = next; /* advance whichb for next time */
/* Special case for bottom of image: don't read another row */
if (cur_mcu_row >= cinfo->MCU_rows_in_scan - 1) {
smooth_mcu_row(cinfo, bsmooth[prev], bsmooth[cur], (JBLOCKIMAGE) NULL,
coeff_data);
return;
}
/* Normal case: read ahead a new row, smooth the one I got before */
(*cinfo->methods->disassemble_MCU) (cinfo, bsmooth[next]);
smooth_mcu_row(cinfo, bsmooth[prev], bsmooth[cur], bsmooth[next],
coeff_data);
}
#endif /* BLOCK_SMOOTHING_SUPPORTED */
/*
* Decompression pipeline controller used for single-scan files
* without 2-pass color quantization.
*/
METHODDEF void
single_dcontroller (cinfo)
decompress_info_ptr cinfo;
{
long fullsize_width; /* # of samples per row in full-size buffers */
long cur_mcu_row; /* counts # of MCU rows processed */
long pixel_rows_output; /* # of pixel rows actually emitted */
int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */
/* Work buffer for dequantized coefficients (IDCT input) */
JBLOCKIMAGE coeff_data;
/* Work buffer for cross-block smoothing input */
#ifdef BLOCK_SMOOTHING_SUPPORTED
JBLOCKIMAGE bsmooth[3]; /* this is optional */
int whichb;
#endif
/* Work buffer for subsampled image data (see comments at head of file) */
JSAMPIMAGE subsampled_data[2];
/* Work buffer for desubsampled data */
JSAMPIMAGE fullsize_data;
/* Work buffer for color conversion output (full size) */
JSAMPIMAGE color_data;
int whichss, ri;
short i;
/* Prepare for single scan containing all components */
if (cinfo->comps_in_scan == 1) {
noninterleaved_scan_setup(cinfo);
/* Need to read Vk MCU rows to obtain Vk block rows */
mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor;
} else {
interleaved_scan_setup(cinfo);
/* in an interleaved scan, one MCU row provides Vk block rows */
mcu_rows_per_loop = 1;
}
/* Compute dimensions of full-size pixel buffers */
/* Note these are the same whether interleaved or not. */
rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE;
fullsize_width = jround_up(cinfo->image_width,
(long) (cinfo->max_h_samp_factor * DCTSIZE));
/* Allocate working memory: */
/* coeff_data holds a single MCU row of coefficient blocks */
coeff_data = alloc_MCU_row(cinfo);
/* if doing cross-block smoothing, need extra space for its input */
#ifdef BLOCK_SMOOTHING_SUPPORTED
if (cinfo->do_block_smoothing) {
bsmooth[0] = alloc_MCU_row(cinfo);
bsmooth[1] = alloc_MCU_row(cinfo);
bsmooth[2] = alloc_MCU_row(cinfo);
}
#endif
/* subsampled_data is sample data before unsubsampling */
alloc_sampling_buffer(cinfo, subsampled_data);
/* fullsize_data is sample data after unsubsampling */
fullsize_data = alloc_sampimage(cinfo, (int) cinfo->num_components,
(long) rows_in_mem, fullsize_width);
/* color_data is the result of the colorspace conversion step */
color_data = alloc_sampimage(cinfo, (int) cinfo->color_out_comps,
(long) rows_in_mem, fullsize_width);
/* Tell the memory manager to instantiate big arrays.
* We don't need any big arrays in this controller,
* but some other module (like the output file writer) may need one.
*/
(*cinfo->emethods->alloc_big_arrays)
((long) 0, /* no more small sarrays */
(long) 0, /* no more small barrays */
(long) 0); /* no more "medium" objects */
/* Initialize to read scan data */
(*cinfo->methods->entropy_decoder_init) (cinfo);
(*cinfo->methods->unsubsample_init) (cinfo);
(*cinfo->methods->disassemble_init) (cinfo);
/* Loop over scan's data: rows_in_mem pixel rows are processed per loop */
pixel_rows_output = 0;
whichss = 1; /* arrange to start with subsampled_data[0] */
for (cur_mcu_row = 0; cur_mcu_row < cinfo->MCU_rows_in_scan;
cur_mcu_row += mcu_rows_per_loop) {
whichss ^= 1; /* switch to other subsample buffer */
/* Obtain v_samp_factor block rows of each component in the scan. */
/* This is a single MCU row if interleaved, multiple MCU rows if not. */
/* In the noninterleaved case there might be fewer than v_samp_factor */
/* block rows remaining; if so, pad with copies of the last pixel row */
/* so that unsubsampling doesn't have to treat it as a special case. */
for (ri = 0; ri < mcu_rows_per_loop; ri++) {
if (cur_mcu_row + ri < cinfo->MCU_rows_in_scan) {
/* OK to actually read an MCU row. */
#ifdef BLOCK_SMOOTHING_SUPPORTED
if (cinfo->do_block_smoothing)
get_smoothed_row(cinfo, coeff_data,
bsmooth, &whichb, cur_mcu_row + ri);
else
#endif
(*cinfo->methods->disassemble_MCU) (cinfo, coeff_data);
reverse_DCT(cinfo, coeff_data, subsampled_data[whichss],
ri * DCTSIZE);
} else {
/* Need to pad out with copies of the last subsampled row. */
/* This can only happen if there is just one component. */
duplicate_row(subsampled_data[whichss][0],
cinfo->cur_comp_info[0]->subsampled_width,
ri * DCTSIZE - 1, DCTSIZE);
}
}
/* Unsubsample the data */
/* First time through is a special case */
if (cur_mcu_row) {
/* Expand last row group of previous set */
jexpand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width,
(short) DCTSIZE, (short) (DCTSIZE+1), (short) 0,
(short) (DCTSIZE-1));
/* and dump the previous set's expanded data */
emit_1pass (cinfo, rows_in_mem, fullsize_data, color_data);
pixel_rows_output += rows_in_mem;
/* Expand first row group of this set */
jexpand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width,
(short) (DCTSIZE+1), (short) 0, (short) 1,
(short) 0);
} else {
/* Expand first row group with dummy above-context */
jexpand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width,
(short) (-1), (short) 0, (short) 1,
(short) 0);
}
/* Expand second through next-to-last row groups of this set */
for (i = 1; i <= DCTSIZE-2; i++) {
jexpand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width,
(short) (i-1), (short) i, (short) (i+1),
(short) i);
}
} /* end of outer loop */
/* Expand the last row group with dummy below-context */
/* Note whichss points to last buffer side used */
jexpand(cinfo, subsampled_data[whichss], fullsize_data, fullsize_width,
(short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1),
(short) (DCTSIZE-1));
/* and dump the remaining data (may be less than full height) */
emit_1pass (cinfo, (int) (cinfo->image_height - pixel_rows_output),
fullsize_data, color_data);
/* Clean up after the scan */
(*cinfo->methods->disassemble_term) (cinfo);
(*cinfo->methods->unsubsample_term) (cinfo);
(*cinfo->methods->entropy_decoder_term) (cinfo);
(*cinfo->methods->read_scan_trailer) (cinfo);
/* Verify that we've seen the whole input file */
if ((*cinfo->methods->read_scan_header) (cinfo))
ERREXIT(cinfo->emethods, "Didn't expect more than one scan");
/* Release working memory */
free_MCU_row(cinfo, coeff_data);
#ifdef BLOCK_SMOOTHING_SUPPORTED
if (cinfo->do_block_smoothing) {
free_MCU_row(cinfo, bsmooth[0]);
free_MCU_row(cinfo, bsmooth[1]);
free_MCU_row(cinfo, bsmooth[2]);
}
#endif
free_sampling_buffer(cinfo, subsampled_data);
free_sampimage(cinfo, fullsize_data, (int) cinfo->num_components,
(long) rows_in_mem);
free_sampimage(cinfo, color_data, (int) cinfo->color_out_comps,
(long) rows_in_mem);
}
/*
* Decompression pipeline controller used for multiple-scan files
* without 2-pass color quantization.
*
* The current implementation places the "big" buffer at the stage of
* desubsampled data. Buffering subsampled data instead would reduce the
* size of temp files (by about a factor of 2 in typical cases). However,
* the unsubsampling logic is dependent on the assumption that unsubsampling
* occurs during a scan, so it's much easier to do the enlargement as the
* JPEG file is read. This also simplifies life for the memory manager,
* which would otherwise have to deal with overlapping access_big_sarray()
* requests.
*
* At present it appears that most JPEG files will be single-scan, so
* it doesn't seem worthwhile to try to make this implementation smarter.
*/
#ifdef MULTISCAN_FILES_SUPPORTED
METHODDEF void
multi_dcontroller (cinfo)
decompress_info_ptr cinfo;
{
long fullsize_width; /* # of samples per row in full-size buffers */
long cur_mcu_row; /* counts # of MCU rows processed */
long pixel_rows_output; /* # of pixel rows actually emitted */
int mcu_rows_per_loop; /* # of MCU rows processed per outer loop */
/* Work buffer for dequantized coefficients (IDCT input) */
JBLOCKIMAGE coeff_data;
/* Work buffer for cross-block smoothing input */
#ifdef BLOCK_SMOOTHING_SUPPORTED
JBLOCKIMAGE bsmooth[3]; /* this is optional */
int whichb;
#endif
/* Work buffer for subsampled image data (see comments at head of file) */
JSAMPIMAGE subsampled_data[2];
/* Full-image buffer holding desubsampled, but not color-converted, data */
big_sarray_ptr *fullsize_image;
JSAMPIMAGE fullsize_ptrs; /* workspace for access_big_sarray() results */
/* Work buffer for color conversion output (full size) */
JSAMPIMAGE color_data;
int whichss, ri;
short ci, i;
/* Compute dimensions of full-size pixel buffers */
/* Note these are the same whether interleaved or not. */
rows_in_mem = cinfo->max_v_samp_factor * DCTSIZE;
fullsize_width = jround_up(cinfo->image_width,
(long) (cinfo->max_h_samp_factor * DCTSIZE));
/* Allocate all working memory that doesn't depend on scan info */
/* color_data is the result of the colorspace conversion step */
color_data = alloc_sampimage(cinfo, (int) cinfo->color_out_comps,
(long) rows_in_mem, fullsize_width);
/* Get a big image: fullsize_image is sample data after unsubsampling. */
fullsize_image = (big_sarray_ptr *) (*cinfo->emethods->alloc_small)
(cinfo->num_components * SIZEOF(big_sarray_ptr));
for (ci = 0; ci < cinfo->num_components; ci++) {
fullsize_image[ci] = (*cinfo->emethods->request_big_sarray)
(fullsize_width,
jround_up(cinfo->image_height, (long) rows_in_mem),
(long) rows_in_mem);
}
/* Also get an area for pointers to currently accessible chunks */
fullsize_ptrs = (JSAMPIMAGE) (*cinfo->emethods->alloc_small)
(cinfo->num_components * SIZEOF(JSAMPARRAY));
/* Tell the memory manager to instantiate big arrays */
(*cinfo->emethods->alloc_big_arrays)
/* extra sarray space is for subsampled-data buffers: */
((long) (fullsize_width /* max width in samples */
* cinfo->max_v_samp_factor*(DCTSIZE+2) /* max height */
* cinfo->num_components), /* max components per scan */
/* extra barray space is for MCU-row buffers: */
(long) ((fullsize_width / DCTSIZE) /* max width in blocks */
* cinfo->max_v_samp_factor /* max height */
* cinfo->num_components /* max components per scan */
* (cinfo->do_block_smoothing ? 4 : 1)),/* how many of these we need */
/* no extra "medium"-object space */
(long) 0);
/* Loop over scans in file */
do {
/* Prepare for this scan */
if (cinfo->comps_in_scan == 1) {
noninterleaved_scan_setup(cinfo);
/* Need to read Vk MCU rows to obtain Vk block rows */
mcu_rows_per_loop = cinfo->cur_comp_info[0]->v_samp_factor;
} else {
interleaved_scan_setup(cinfo);
/* in an interleaved scan, one MCU row provides Vk block rows */
mcu_rows_per_loop = 1;
}
/* Allocate scan-local working memory */
/* coeff_data holds a single MCU row of coefficient blocks */
coeff_data = alloc_MCU_row(cinfo);
/* if doing cross-block smoothing, need extra space for its input */
#ifdef BLOCK_SMOOTHING_SUPPORTED
if (cinfo->do_block_smoothing) {
bsmooth[0] = alloc_MCU_row(cinfo);
bsmooth[1] = alloc_MCU_row(cinfo);
bsmooth[2] = alloc_MCU_row(cinfo);
}
#endif
/* subsampled_data is sample data before unsubsampling */
alloc_sampling_buffer(cinfo, subsampled_data);
/* line up the big buffers */
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray)
(fullsize_image[cinfo->cur_comp_info[ci]->component_index],
(long) 0, TRUE);
}
/* Initialize to read scan data */
(*cinfo->methods->entropy_decoder_init) (cinfo);
(*cinfo->methods->unsubsample_init) (cinfo);
(*cinfo->methods->disassemble_init) (cinfo);
/* Loop over scan's data: rows_in_mem pixel rows are processed per loop */
pixel_rows_output = 0;
whichss = 1; /* arrange to start with subsampled_data[0] */
for (cur_mcu_row = 0; cur_mcu_row < cinfo->MCU_rows_in_scan;
cur_mcu_row += mcu_rows_per_loop) {
whichss ^= 1; /* switch to other subsample buffer */
/* Obtain v_samp_factor block rows of each component in the scan. */
/* This is a single MCU row if interleaved, multiple MCU rows if not. */
/* In the noninterleaved case there might be fewer than v_samp_factor */
/* block rows remaining; if so, pad with copies of the last pixel row */
/* so that unsubsampling doesn't have to treat it as a special case. */
for (ri = 0; ri < mcu_rows_per_loop; ri++) {
if (cur_mcu_row + ri < cinfo->MCU_rows_in_scan) {
/* OK to actually read an MCU row. */
#ifdef BLOCK_SMOOTHING_SUPPORTED
if (cinfo->do_block_smoothing)
get_smoothed_row(cinfo, coeff_data,
bsmooth, &whichb, cur_mcu_row + ri);
else
#endif
(*cinfo->methods->disassemble_MCU) (cinfo, coeff_data);
reverse_DCT(cinfo, coeff_data, subsampled_data[whichss],
ri * DCTSIZE);
} else {
/* Need to pad out with copies of the last subsampled row. */
/* This can only happen if there is just one component. */
duplicate_row(subsampled_data[whichss][0],
cinfo->cur_comp_info[0]->subsampled_width,
ri * DCTSIZE - 1, DCTSIZE);
}
}
/* Unsubsample the data */
/* First time through is a special case */
if (cur_mcu_row) {
/* Expand last row group of previous set */
jexpand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width,
(short) DCTSIZE, (short) (DCTSIZE+1), (short) 0,
(short) (DCTSIZE-1));
/* Realign the big buffers */
pixel_rows_output += rows_in_mem;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray)
(fullsize_image[cinfo->cur_comp_info[ci]->component_index],
pixel_rows_output, TRUE);
}
/* Expand first row group of this set */
jexpand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width,
(short) (DCTSIZE+1), (short) 0, (short) 1,
(short) 0);
} else {
/* Expand first row group with dummy above-context */
jexpand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width,
(short) (-1), (short) 0, (short) 1,
(short) 0);
}
/* Expand second through next-to-last row groups of this set */
for (i = 1; i <= DCTSIZE-2; i++) {
jexpand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width,
(short) (i-1), (short) i, (short) (i+1),
(short) i);
}
} /* end of outer loop */
/* Expand the last row group with dummy below-context */
/* Note whichss points to last buffer side used */
jexpand(cinfo, subsampled_data[whichss], fullsize_ptrs, fullsize_width,
(short) (DCTSIZE-2), (short) (DCTSIZE-1), (short) (-1),
(short) (DCTSIZE-1));
/* Clean up after the scan */
(*cinfo->methods->disassemble_term) (cinfo);
(*cinfo->methods->unsubsample_term) (cinfo);
(*cinfo->methods->entropy_decoder_term) (cinfo);
(*cinfo->methods->read_scan_trailer) (cinfo);
/* Release scan-local working memory */
free_MCU_row(cinfo, coeff_data);
#ifdef BLOCK_SMOOTHING_SUPPORTED
if (cinfo->do_block_smoothing) {
free_MCU_row(cinfo, bsmooth[0]);
free_MCU_row(cinfo, bsmooth[1]);
free_MCU_row(cinfo, bsmooth[2]);
}
#endif
free_sampling_buffer(cinfo, subsampled_data);
/* Repeat if there is another scan */
} while ((*cinfo->methods->read_scan_header) (cinfo));
/* Now that we've collected all the data, color convert & output it. */
for (pixel_rows_output = 0; pixel_rows_output < cinfo->image_height;
pixel_rows_output += rows_in_mem) {
/* realign the big buffers */
for (ci = 0; ci < cinfo->num_components; ci++) {
fullsize_ptrs[ci] = (*cinfo->emethods->access_big_sarray)
(fullsize_image[ci], pixel_rows_output, FALSE);
}
emit_1pass (cinfo,
(int) MIN(rows_in_mem, cinfo->image_height-pixel_rows_output),
fullsize_ptrs, color_data);
}
/* Release working memory */
free_sampimage(cinfo, color_data, (int) cinfo->color_out_comps,
(long) rows_in_mem);
for (ci = 0; ci < cinfo->num_components; ci++) {
(*cinfo->emethods->free_big_sarray) (fullsize_image[ci]);
}
(*cinfo->emethods->free_small) ((void *) fullsize_image);
(*cinfo->emethods->free_small) ((void *) fullsize_ptrs);
}
#endif /* MULTISCAN_FILES_SUPPORTED */
/*
* Decompression pipeline controller used for multiple-scan files
* with 2-pass color quantization.
*/
#ifdef MULTISCAN_FILES_SUPPORTED
#ifdef QUANT_2PASS_SUPPORTED
METHODDEF void
multi_2quant_dcontroller
cinfo) decompress_info_ptr cinfo;
{
ERREXIT(cinfo->emethods, "Not implemented yet");
}
#endif /* QUANT_2PASS_SUPPORTED */
#endif /* MULTISCAN_FILES_SUPPORTED */
/*
* The method selection routine for decompression pipeline controllers.
* Note that at this point we've already read the JPEG header and first SOS,
* so we can tell whether the input is one scan or not.
*/
GLOBAL void
jseldpipeline (cinfo)
decompress_info_ptr cinfo;
{
if (cinfo->comps_in_scan == cinfo->num_components) {
/* It's a single-scan file */
cinfo->methods->d_pipeline_controller = single_dcontroller;
} else {
/* It's a multiple-scan file */
#ifdef MULTISCAN_FILES_SUPPORTED
cinfo->methods->d_pipeline_controller = multi_dcontroller;
#else
ERREXIT(cinfo->emethods, "Multiple-scan support was not compiled");
#endif
}
}
/* ########################################################################## */
/*
* jbsmooth.c
*
*/
#ifdef BLOCK_SMOOTHING_SUPPORTED
/*
* Cross-block coefficient smoothing.
*/
METHODDEF void
smooth_coefficients (cinfo, compptr, above, currow, below, output)
decompress_info_ptr cinfo;
jpeg_component_info *compptr;
JBLOCKROW above;
JBLOCKROW currow;
JBLOCKROW below;
JBLOCKROW output;
{
QUANT_TBL_PTR Qptr = cinfo->quant_tbl_ptrs[compptr->quant_tbl_no];
long blocks_in_row = compptr->subsampled_width / DCTSIZE;
long col;
/* First, copy the block row as-is.
* This takes care of the first & last blocks in the row, the top/bottom
* special cases, and the higher-order coefficients in each block.
*/
jcopy_block_row(currow, output, blocks_in_row);
/* Now apply the smoothing calculation, but not to any blocks on the
* edges of the image.
*/
if (above != NULL && below != NULL) {
for (col = 1; col < blocks_in_row-1; col++) {
/* See section 13.10 of JPEG-8-R8, or K.8 of JPEG-9-R6.
*
* As I understand it, this produces approximations
* for the low frequency AC components, based on the
* DC values of the block and its eight neighboring blocks.
* (Thus it can't be used for blocks on the image edges.)
*/
/* The layout of these variables corresponds to
* the text in 13.10
*/
JCOEF DC1, DC2, DC3;
JCOEF DC4, DC5, DC6;
JCOEF DC7, DC8, DC9;
long AC01, AC02;
long AC10, AC11;
long AC20;
DC1 = above [col-1][0];
DC2 = above [col ][0];
DC3 = above [col+1][0];
DC4 = currow[col-1][0];
DC5 = currow[col ][0];
DC6 = currow[col+1][0];
DC7 = below [col-1][0];
DC8 = below [col ][0];
DC9 = below [col+1][0];
#define DIVIDE_256(x) x = ( (x) < 0 ? -((128-(x))/256) : ((x)+128)/256 )
AC01 = (36 * (DC4 - DC6));
DIVIDE_256(AC01);
AC10 = (36 * (DC2 - DC8));
DIVIDE_256(AC10);
AC20 = (9 * (DC2 + DC8 - 2*DC5));
DIVIDE_256(AC20);
AC11 = (5 * ((DC1 - DC3) - (DC7 - DC9)));
DIVIDE_256(AC11);
AC02 = (9 * (DC4 + DC6 - 2*DC5));
DIVIDE_256(AC02);
/* I think that this checks to see if the quantisation
* on the transmitting side would have produced this
* answer. If so, then we use our (hopefully better)
* estimate.
*/
#define ABS(x) ((x) < 0 ? -(x) : (x))
#define COND_ASSIGN(_ac,_n,_z) if ((ABS(output[col][_n] - (_ac))<<1) <= Qptr[_z]) output[col][_n] = (_ac)
COND_ASSIGN(AC01, 1, 1);
COND_ASSIGN(AC02, 2, 5);
COND_ASSIGN(AC10, 8, 2);
COND_ASSIGN(AC11, 9, 4);
COND_ASSIGN(AC20, 16, 3);
}
}
}
/*
* The method selection routine for cross-block smoothing.
*/
GLOBAL void
jselbsmooth (cinfo)
decompress_info_ptr cinfo;
{
/* just one implementation for now */
cinfo->methods->smooth_coefficients = smooth_coefficients;
}
#endif /* BLOCK_SMOOTHING_SUPPORTED */
/* ########################################################################## */
/*
* jdarith.c
*
*/
#ifdef ARITH_CODING_SUPPORTED
/*
* The arithmetic coding option of the JPEG standard specifies Q-coding,
* which is covered by patents held by IBM (and possibly AT&T and Mitsubishi).
* At this time it does not appear to be legal for the Independent JPEG
* Group to distribute software that implements arithmetic coding.
* We have therefore removed arithmetic coding support from the
* distributed source code.
*
* We're not happy about it either.
*/
/*
* The method selection routine for arithmetic entropy decoding.
*/
GLOBAL void
jseldarithmetic (cinfo)
decompress_info_ptr cinfo;
{
if (cinfo->arith_code) {
ERREXIT(cinfo->emethods, "Sorry, there are legal restrictions on arithmetic coding");
}
}
#endif /* ARITH_CODING_SUPPORTED */
/* ########################################################################## */
/*
* jdhuff.c
*
*/
/* Static variables to avoid passing 'round extra parameters */
static decompress_info_ptr dcinfo;
static unsigned int get_buffer; /* current bit-extraction buffer */
static int bits_left; /* # of unused bits in it */
LOCAL void
fix_huff_tbl (htbl)
HUFF_TBL * htbl;
/* Compute derived values for a Huffman table */
{
int p, i, l, lastp, si;
char huffsize[257];
UINT16 huffcode[257];
UINT16 code;
/* Figure 7.3.5.4.2.1: make table of Huffman code length for each symbol */
/* Note that this is in code-length order. */
p = 0;
for (l = 1; l <= 16; l++) {
for (i = 1; i <= htbl->bits[l]; i++)
huffsize[p++] = l;
}
huffsize[p] = 0;
lastp = p;
/* Figure 7.3.5.4.2.2: generate the codes themselves */
/* Note that this is in code-length order. */
code = 0;
si = huffsize[0];
p = 0;
while (huffsize[p]) {
while (huffsize[p] == si) {
huffcode[p++] = code;
code++;
}
code <<= 1;
si++;
}
/* Figure 7.3.5.4.2.3: generate encoding tables */
/* These are code and size indexed by symbol value */
for (p = 0; p < lastp; p++) {
htbl->ehufco[htbl->huffval[p]] = huffcode[p];
htbl->ehufsi[htbl->huffval[p]] = huffsize[p];
}
/* Figure 13.4.2.3.1: generate decoding tables */
p = 0;
for (l = 1; l <= 16; l++) {
if (htbl->bits[l]) {
htbl->valptr[l] = p; /* huffval[] index of 1st sym of code len l */
htbl->mincode[l] = huffcode[p]; /* minimum code of length l */
p += htbl->bits[l];
htbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */
} else {
htbl->maxcode[l] = -1;
}
}
}
/* Extract the next N bits from the input stream (N <= 8) */
LOCAL int
get_bits (nbits)
int nbits;
{
int result;
while (nbits > bits_left) {
int c = JGETC(dcinfo);
get_buffer = (get_buffer << 8) + c;
bits_left += 8;
/* If it's 0xFF, check and discard stuffed zero byte */
if (c == 0xff) {
c = JGETC(dcinfo); /* Byte stuffing */
if (c != 0)
ERREXIT1(dcinfo->emethods,
"Unexpected marker 0x%02x in compressed data", c);
}
}
bits_left -= nbits;
result = (get_buffer >> bits_left) & ((1 << nbits) - 1);
return result;
}
/* Macro to make things go at some speed! */
#define get_bit() (bits_left ? \
((get_buffer >> (--bits_left)) & 1) : \
get_bits(1))
/* Figure 13.4.2.3.2: extract next coded symbol from input stream */
LOCAL int
huff_DECODE (htbl)
HUFF_TBL * htbl;
{
int l, p;
INT32 code;
code = get_bit();
l = 1;
while (code > htbl->maxcode[l]) {
code = (code << 1) + get_bit();
l++;
}
p = htbl->valptr[l] + (code - htbl->mincode[l]);
return htbl->huffval[p];
}
/* Figure 13.4.2.1.1: extend sign bit */
#define huff_EXTEND(x, s) ((x) < (1 << ((s)-1)) ? \
(x) + (-1 << (s)) + 1 : \
(x))
/* Decode a single block's worth of coefficients */
/* Note that only the difference is returned for the DC coefficient */
LOCAL void
decode_one_block (block, dctbl, actbl)
JBLOCK block;
HUFF_TBL *dctbl;
HUFF_TBL *actbl;
{
int s, k, r, n;
/* zero out the coefficient block */
memset((void *) block, 0, SIZEOF(JBLOCK));
/* Section 13.4.2.1: decode the DC coefficient difference */
s = huff_DECODE(dctbl);
r = get_bits(s);
/* bug fix: original code did not care if 's' was zero, causing
* 1 << -1 in the huff_EXTEND macro, which is illegal. - jimf 11.25.91
*/
if (s)
block[0] = huff_EXTEND(r, s);
else
block[0] = r;
/* Section 13.4.2.2: decode the AC coefficients */
for (k = 1; k < DCTSIZE2; k++) {
r = huff_DECODE(actbl);
s = r & 15;
n = r >> 4;
if (s) {
k = k + n;
r = get_bits(s);
block[k] = huff_EXTEND(r, s);
} else {
if (n != 15)
break;
k += 15;
}
}
}
/*
* Initialize for a Huffman-compressed scan.
* This is invoked after reading the SOS marker.
*/
METHODDEF void
huff_decoder_init (cinfo)
decompress_info_ptr cinfo;
{
short ci;
jpeg_component_info * compptr;
/* Initialize static variables */
dcinfo = cinfo;
bits_left = 0;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
/* Make sure requested tables are present */
if (cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no] == NULL ||
cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no] == NULL)
ERREXIT(cinfo->emethods, "Use of undefined Huffman table");
/* Compute derived values for Huffman tables */
/* We may do this more than once for same table, but it's not a big deal */
fix_huff_tbl(cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no]);
fix_huff_tbl(cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no]);
/* Initialize DC predictions to 0 */
cinfo->last_dc_val[ci] = 0;
}
/* Initialize restart stuff */
cinfo->restarts_to_go = cinfo->restart_interval;
cinfo->next_restart_num = 0;
}
/*
* Check for a restart marker & resynchronize decoder.
*/
LOCAL void
process_restart (cinfo)
decompress_info_ptr cinfo;
{
int c, nbytes;
short ci;
/* Throw away any partial unread byte */
bits_left = 0;
/* Scan for next JPEG marker */
nbytes = 0;
do {
do { /* skip any non-FF bytes */
nbytes++;
c = JGETC(cinfo);
} while (c != 0xFF);
do { /* skip any duplicate FFs */
nbytes++;
c = JGETC(cinfo);
} while (c == 0xFF);
} while (c == 0); /* repeat if it was a stuffed FF/00 */
if (c != (RST0 + cinfo->next_restart_num))
ERREXIT2(cinfo->emethods, "Found 0x%02x marker instead of RST%d",
c, cinfo->next_restart_num);
if (nbytes != 2)
TRACEMS2(cinfo->emethods, 1, "Skipped %d bytes before RST%d",
nbytes-2, cinfo->next_restart_num);
else
TRACEMS1(cinfo->emethods, 2, "RST%d", cinfo->next_restart_num);
/* Re-initialize DC predictions to 0 */
for (ci = 0; ci < cinfo->comps_in_scan; ci++)
cinfo->last_dc_val[ci] = 0;
/* Update restart state */
cinfo->restarts_to_go = cinfo->restart_interval;
cinfo->next_restart_num++;
cinfo->next_restart_num &= 7;
}
/*
* Decode and return one MCU's worth of Huffman-compressed coefficients.
*/
METHODDEF void
huff_decode (cinfo, MCU_data)
decompress_info_ptr cinfo; JBLOCK *MCU_data;
{
short blkn, ci;
jpeg_component_info * compptr;
/* Account for restart interval, process restart marker if needed */
if (cinfo->restart_interval) {
if (cinfo->restarts_to_go == 0)
process_restart(cinfo);
cinfo->restarts_to_go--;
}
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
decode_one_block(MCU_data[blkn],
cinfo->dc_huff_tbl_ptrs[compptr->dc_tbl_no],
cinfo->ac_huff_tbl_ptrs[compptr->ac_tbl_no]);
/* Convert DC difference to actual value, update last_dc_val */
MCU_data[blkn][0] += cinfo->last_dc_val[ci];
cinfo->last_dc_val[ci] = MCU_data[blkn][0];
}
}
/*
* Finish up at the end of a Huffman-compressed scan.
*/
METHODDEF void
huff_decoder_term (cinfo)
decompress_info_ptr cinfo;
{
/* No work needed */
}
/*
* The method selection routine for Huffman entropy decoding.
*/
GLOBAL void
jseldhuffman (cinfo)
decompress_info_ptr cinfo;
{
if (! cinfo->arith_code) {
cinfo->methods->entropy_decoder_init = huff_decoder_init;
cinfo->methods->entropy_decode = huff_decode;
cinfo->methods->entropy_decoder_term = huff_decoder_term;
}
}
/* ########################################################################## */
/*
* jdcolor.c
*
*/
/*
* Initialize for colorspace conversion.
*/
METHODDEF void
colorout_init (cinfo)
decompress_info_ptr cinfo;
{
/* no work needed */
}
/*
* Convert some rows of samples to the output colorspace.
* This version handles YCbCr -> RGB conversion.
* YCbCr is defined per CCIR 601-1, except that Cb and Cr are
* normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
*/
METHODDEF void
ycc_rgb_convert (cinfo, num_rows, input_data, output_data)
decompress_info_ptr cinfo; int num_rows;
JSAMPIMAGE input_data; JSAMPIMAGE output_data;
{
register INT32 y, u, v, x;
register JSAMPROW inptr0, inptr1, inptr2;
register JSAMPROW outptr0, outptr1, outptr2;
register long col;
register long width = cinfo->image_width;
register int row;
for (row = 0; row < num_rows; row++) {
inptr0 = input_data[0][row];
inptr1 = input_data[1][row];
inptr2 = input_data[2][row];
outptr0 = output_data[0][row];
outptr1 = output_data[1][row];
outptr2 = output_data[2][row];
for (col = width; col > 0; col--) {
y = GETJSAMPLE(*inptr0++);
u = (int) GETJSAMPLE(*inptr1++) - CENTERJSAMPLE;
v = (int) GETJSAMPLE(*inptr2++) - CENTERJSAMPLE;
/* Note: if the inputs were computed directly from RGB values,
* range-limiting would be unnecessary here; but due to possible
* noise in the DCT/IDCT phase, we do need to apply range limits.
*/
y *= 1024; /* in case compiler can't spot common subexpression */
x = y + 1436*v + 512; /* red */
if (x < 0) x = 0;
if (x > ((INT32) MAXJSAMPLE*1024)) x = (INT32) MAXJSAMPLE*1024;
*outptr0++ = x >> 10;
x = y - 352*u - 731*v + 512; /* green */
if (x < 0) x = 0;
if (x > ((INT32) MAXJSAMPLE*1024)) x = (INT32) MAXJSAMPLE*1024;
*outptr1++ = x >> 10;
x = y + 1815*u + 512; /* blue */
if (x < 0) x = 0;
if (x > ((INT32) MAXJSAMPLE*1024)) x = (INT32) MAXJSAMPLE*1024;
*outptr2++ = x >> 10;
}
}
}
/*
* Color conversion for no colorspace change: just copy the data.
*/
METHODDEF void
null_convert (cinfo, num_rows, input_data, output_data)
decompress_info_ptr cinfo; int num_rows;
JSAMPIMAGE input_data; JSAMPIMAGE output_data;
{
short ci;
for (ci = 0; ci < cinfo->num_components; ci++) {
jcopy_sample_rows(input_data[ci], 0, output_data[ci], 0,
num_rows, cinfo->image_width);
}
}
/*
* Color conversion for grayscale: just copy the data.
* This also works for YCbCr/YIQ -> grayscale conversion, in which
* we just copy the Y (luminance) component and ignore chrominance.
*/
METHODDEF void
grayscale_convert (cinfo, num_rows, input_data, output_data)
decompress_info_ptr cinfo; int num_rows;
JSAMPIMAGE input_data; JSAMPIMAGE output_data;
{
jcopy_sample_rows(input_data[0], 0, output_data[0], 0,
num_rows, cinfo->image_width);
}
/*
* Finish up at the end of the file.
*/
METHODDEF void
colorout_term (cinfo)
decompress_info_ptr cinfo;
{
/* no work needed */
}
/*
* The method selection routine for output colorspace conversion.
*/
GLOBAL void
jseldcolor (cinfo)
decompress_info_ptr cinfo;
{
/* Make sure num_components agrees with jpeg_color_space */
switch (cinfo->jpeg_color_space) {
case CS_GRAYSCALE:
if (cinfo->num_components != 1)
ERREXIT(cinfo->emethods, "Bogus JPEG colorspace");
break;
case CS_RGB:
case CS_YIQ:
case CS_YCbCr:
if (cinfo->num_components != 3)
ERREXIT(cinfo->emethods, "Bogus JPEG colorspace");
break;
case CS_CMYK:
if (cinfo->num_components != 4)
ERREXIT(cinfo->emethods, "Bogus JPEG colorspace");
break;
default:
ERREXIT(cinfo->emethods, "Unsupported JPEG colorspace");
break;
}
/* Set color_out_comps and conversion method based on requested space */
switch (cinfo->out_color_space) {
case CS_GRAYSCALE:
cinfo->color_out_comps = 1;
if (cinfo->jpeg_color_space == CS_GRAYSCALE ||
cinfo->jpeg_color_space == CS_YCbCr ||
cinfo->jpeg_color_space == CS_YIQ)
cinfo->methods->color_convert = grayscale_convert;
else
ERREXIT(cinfo->emethods, "Unsupported color conversion request");
break;
case CS_RGB:
cinfo->color_out_comps = 3;
if (cinfo->jpeg_color_space == CS_YCbCr)
cinfo->methods->color_convert = ycc_rgb_convert;
else if (cinfo->jpeg_color_space == CS_RGB)
cinfo->methods->color_convert = null_convert;
else
ERREXIT(cinfo->emethods, "Unsupported color conversion request");
break;
case CS_CMYK:
cinfo->color_out_comps = 4;
if (cinfo->jpeg_color_space == CS_CMYK)
cinfo->methods->color_convert = null_convert;
else
ERREXIT(cinfo->emethods, "Unsupported color conversion request");
break;
default:
ERREXIT(cinfo->emethods, "Unsupported output colorspace");
break;
}
cinfo->final_out_comps = cinfo->color_out_comps;
cinfo->methods->colorout_init = colorout_init;
cinfo->methods->colorout_term = colorout_term;
}
/* ########################################################################## */
/*
* jdmcu.c
*
*/
/*
* Quantization descaling and zigzag reordering
*/
/* ZAG[i] is the natural-order position of the i'th element of zigzag order. */
static short ZAG[DCTSIZE2] = {
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
};
LOCAL void
qdescale_zig (input, outputptr, quanttbl)
JBLOCK input;
JBLOCKROW outputptr;
QUANT_TBL_PTR quanttbl;
{
short i;
for (i = 0; i < DCTSIZE2; i++) {
(*outputptr)[ZAG[i]] = (*input++) * (*quanttbl++);
}
}
/*
* Fetch one MCU row from entropy_decode, build coefficient array.
* This version is used for noninterleaved (single-component) scans.
*/
METHODDEF void
disassemble_noninterleaved_MCU (cinfo, image_data)
decompress_info_ptr cinfo;
JBLOCKIMAGE image_data;
{
JBLOCK MCU_data[1];
long mcuindex;
jpeg_component_info * compptr;
QUANT_TBL_PTR quant_ptr;
/* this is pretty easy since there is one component and one block per MCU */
compptr = cinfo->cur_comp_info[0];
quant_ptr = cinfo->quant_tbl_ptrs[compptr->quant_tbl_no];
for (mcuindex = 0; mcuindex < cinfo->MCUs_per_row; mcuindex++) {
/* Fetch the coefficient data */
(*cinfo->methods->entropy_decode) (cinfo, MCU_data);
/* Descale, reorder, and distribute it into the image array */
qdescale_zig(MCU_data[0], image_data[0][0] + mcuindex, quant_ptr);
}
}
/*
* Fetch one MCU row from entropy_decode, build coefficient array.
* This version is used for interleaved (multi-component) scans.
*/
METHODDEF void
disassemble_interleaved_MCU (cinfo, image_data)
decompress_info_ptr cinfo;
JBLOCKIMAGE image_data;
{
JBLOCK MCU_data[MAX_BLOCKS_IN_MCU];
long mcuindex;
short blkn, ci, xpos, ypos;
jpeg_component_info * compptr;
QUANT_TBL_PTR quant_ptr;
JBLOCKROW image_ptr;
for (mcuindex = 0; mcuindex < cinfo->MCUs_per_row; mcuindex++) {
/* Fetch the coefficient data */
(*cinfo->methods->entropy_decode) (cinfo, MCU_data);
/* Descale, reorder, and distribute it into the image array */
blkn = 0;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
quant_ptr = cinfo->quant_tbl_ptrs[compptr->quant_tbl_no];
for (ypos = 0; ypos < compptr->MCU_height; ypos++) {
image_ptr = image_data[ci][ypos] + (mcuindex * compptr->MCU_width);
for (xpos = 0; xpos < compptr->MCU_width; xpos++) {
qdescale_zig(MCU_data[blkn], image_ptr, quant_ptr);
image_ptr++;
blkn++;
}
}
}
}
}
/*
* Initialize for processing a scan.
*/
METHODDEF void
disassemble_init (cinfo)
decompress_info_ptr cinfo;
{
/* no work for now */
}
/*
* Clean up after a scan.
*/
METHODDEF void
disassemble_term (cinfo)
decompress_info_ptr cinfo;
{
/* no work for now */
}
/*
* The method selection routine for MCU disassembly.
*/
GLOBAL void
jseldmcu (cinfo)
decompress_info_ptr cinfo;
{
if (cinfo->comps_in_scan == 1)
cinfo->methods->disassemble_MCU = disassemble_noninterleaved_MCU;
else
cinfo->methods->disassemble_MCU = disassemble_interleaved_MCU;
cinfo->methods->disassemble_init = disassemble_init;
cinfo->methods->disassemble_term = disassemble_term;
}
/* ########################################################################## */
/*
* jdsample.c
*
*/
/*
* Initialize for un-subsampling a scan.
*/
METHODDEF void
unsubsample_init (cinfo)
decompress_info_ptr cinfo;
{
/* no work for now */
}
/*
* Un-subsample pixel values of a single component.
* This version only handles integral sampling ratios.
*/
METHODDEF void
unsubsample (cinfo, which_component, input_cols, input_rows, output_cols, output_rows, above, input_data, below, output_data)
decompress_info_ptr cinfo; int which_component;
long input_cols; int input_rows;
long output_cols; int output_rows;
JSAMPARRAY above; JSAMPARRAY input_data; JSAMPARRAY below;
JSAMPARRAY output_data;
{
jpeg_component_info * compptr = cinfo->cur_comp_info[which_component];
short h_expand, v_expand, h, v;
int inrow, outrow;
long incol;
JSAMPROW inptr, outptr;
JSAMPLE invalue;
/* TEMP FOR DEBUGGING PIPELINE CONTROLLER */
if (input_rows != compptr->v_samp_factor ||
output_rows != cinfo->max_v_samp_factor ||
(input_cols % compptr->h_samp_factor) != 0 ||
(output_cols % cinfo->max_h_samp_factor) != 0 ||
output_cols*compptr->h_samp_factor != input_cols*cinfo->max_h_samp_factor)
ERREXIT(cinfo->emethods, "Bogus unsubsample parameters");
h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor;
v_expand = cinfo->max_v_samp_factor / compptr->v_samp_factor;
outrow = 0;
for (inrow = 0; inrow < input_rows; inrow++) {
for (v = 0; v < v_expand; v++) {
inptr = input_data[inrow];
outptr = output_data[outrow++];
for (incol = 0; incol < input_cols; incol++) {
invalue = GETJSAMPLE(*inptr++);
for (h = 0; h < h_expand; h++) {
*outptr++ = invalue;
}
}
}
}
}
/*
* Un-subsample pixel values of a single component.
* This version handles the special case of a full-size component.
*/
METHODDEF void
fullsize_unsubsample (cinfo, which_component, input_cols, input_rows, output_cols, output_rows, above, input_data, below, output_data)
decompress_info_ptr cinfo; int which_component;
long input_cols; int input_rows;
long output_cols; int output_rows;
JSAMPARRAY above; JSAMPARRAY input_data; JSAMPARRAY below;
JSAMPARRAY output_data;
{
if (input_cols != output_cols || input_rows != output_rows) /* DEBUG */
ERREXIT(cinfo->emethods, "Pipeline controller messed up");
jcopy_sample_rows(input_data, 0, output_data, 0, output_rows, output_cols);
}
/*
* Clean up after a scan.
*/
METHODDEF void
unsubsample_term (cinfo)
decompress_info_ptr cinfo;
{
/* no work for now */
}
/*
* The method selection routine for unsubsampling.
* Note that we must select a routine for each component.
*/
GLOBAL void
jselunsubsample (cinfo)
decompress_info_ptr cinfo;
{
short ci;
jpeg_component_info * compptr;
if (cinfo->CCIR601_sampling)
ERREXIT(cinfo->emethods, "CCIR601 subsampling not implemented yet");
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
if (compptr->h_samp_factor == cinfo->max_h_samp_factor &&
compptr->v_samp_factor == cinfo->max_v_samp_factor)
cinfo->methods->unsubsample[ci] = fullsize_unsubsample;
else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 &&
(cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0)
cinfo->methods->unsubsample[ci] = unsubsample;
else
ERREXIT(cinfo->emethods, "Fractional subsampling not implemented yet");
}
cinfo->methods->unsubsample_init = unsubsample_init;
cinfo->methods->unsubsample_term = unsubsample_term;
}
/* ########################################################################## */
/*
* jrevdct.c
*
*/
/* The poop on this scaling stuff is as follows:
*
* Most of the numbers (after multiplication by the constants) are
* (logically) shifted left by LG2_DCT_SCALE. This is undone by UNFIXH
* before assignment to the output array. Note that we want an additional
* division by 2 on the output (required by the equations).
*
* If right shifts are unsigned, then there is a potential problem.
* However, shifting right by 16 and then assigning to a short
* (assuming short = 16 bits) will keep the sign right!!
*
* For other shifts,
*
* ((x + (1 << 30)) >> shft) - (1 << (30 - shft))
*
* gives a nice right shift with sign (assuming no overflow). However, all the
* scaling is such that this isn't a problem. (Is this true?)
*/
#define ONE 1L /* remove L if long > 32 bits */
#ifdef RIGHT_SHIFT_IS_UNSIGNED
#define LG2_DCT_SCALE 15
#define RIGHT_SHIFT(_x,_shft) ((((_x) + (ONE << 30)) >> (_shft)) - (ONE << (30 - (_shft))))
#else
#define LG2_DCT_SCALE 16
#define RIGHT_SHIFT(_x,_shft) ((_x) >> (_shft))
#endif
#define DCT_SCALE (ONE << LG2_DCT_SCALE)
#define LG2_OVERSCALE 2
#define OVERSCALE (ONE << LG2_OVERSCALE)
#define FIX(x) ((INT32) ((x) * DCT_SCALE + 0.5))
#define FIXO(x) ((INT32) ((x) * DCT_SCALE / OVERSCALE + 0.5))
#define UNFIX(x) RIGHT_SHIFT((x) + (ONE << (LG2_DCT_SCALE-1)), LG2_DCT_SCALE)
#define UNFIXH(x) RIGHT_SHIFT((x) + (ONE << LG2_DCT_SCALE), LG2_DCT_SCALE+1)
#define UNFIXO(x) RIGHT_SHIFT((x) + (ONE << (LG2_DCT_SCALE-1-LG2_OVERSCALE)), LG2_DCT_SCALE-LG2_OVERSCALE)
#define OVERSH(x) ((x) << LG2_OVERSCALE)
#define SIN_1_4 FIX(0.7071067811856476)
#define COS_1_4 SIN_1_4
#define SIN_1_8 FIX(0.3826834323650898)
#define COS_1_8 FIX(0.9238795325112870)
#define SIN_3_8 COS_1_8
#define COS_3_8 SIN_1_8
#define SIN_1_16 FIX(0.1950903220161282)
#define COS_1_16 FIX(0.9807852804032300)
#define SIN_7_16 COS_1_16
#define COS_7_16 SIN_1_16
#define SIN_3_16 FIX(0.5555702330196022)
#define COS_3_16 FIX(0.8314696123025450)
#define SIN_5_16 COS_3_16
#define COS_5_16 SIN_3_16
#define OSIN_1_4 FIXO(0.707106781185647)
#define OCOS_1_4 OSIN_1_4
#define OSIN_1_8 FIXO(0.3826834323650898)
#define OCOS_1_8 FIXO(0.9238795325112870)
#define OSIN_3_8 OCOS_1_8
#define OCOS_3_8 OSIN_1_8
#define OSIN_1_16 FIXO(0.1950903220161282)
#define OCOS_1_16 FIXO(0.9807852804032300)
#define OSIN_7_16 OCOS_1_16
#define OCOS_7_16 OSIN_1_16
#define OSIN_3_16 FIXO(0.5555702330196022)
#define OCOS_3_16 FIXO(0.8314696123025450)
#define OSIN_5_16 OCOS_3_16
#define OCOS_5_16 OSIN_3_16
/* INLINE SYSVR3 + gcc -traditional trips on this */
LOCAL void
fast_idct_8 (in, stride)
DCTELEM *in;
int stride;
{
/* tmp1x are new values of tmpx -- flashy register colourers
* should be able to do this lot very well
*/
INT32 tmp10, tmp11, tmp12, tmp13;
INT32 tmp20, tmp21, tmp22, tmp23;
INT32 tmp30, tmp31;
INT32 tmp40, tmp41, tmp42, tmp43;
INT32 tmp50, tmp51, tmp52, tmp53;
INT32 in0, in1, in2, in3, in4, in5, in6, in7;
in0 = in[ 0];
in1 = in[stride ];
in2 = in[stride*2];
in3 = in[stride*3];
in4 = in[stride*4];
in5 = in[stride*5];
in6 = in[stride*6];
in7 = in[stride*7];
tmp10 = (in0 + in4) * COS_1_4;
tmp11 = (in0 - in4) * COS_1_4;
tmp12 = in2 * SIN_1_8 - in6 * COS_1_8;
tmp13 = in6 * SIN_1_8 + in2 * COS_1_8;
tmp20 = tmp10 + tmp13;
tmp21 = tmp11 + tmp12;
tmp22 = tmp11 - tmp12;
tmp23 = tmp10 - tmp13;
tmp30 = UNFIXO((in3 + in5) * COS_1_4);
tmp31 = UNFIXO((in3 - in5) * COS_1_4);
tmp40 = OVERSH(in1) + tmp30;
tmp41 = OVERSH(in7) + tmp31;
tmp42 = OVERSH(in1) - tmp30;
tmp43 = OVERSH(in7) - tmp31;
tmp50 = tmp40 * OCOS_1_16 + tmp41 * OSIN_1_16;
tmp51 = tmp40 * OSIN_1_16 - tmp41 * OCOS_1_16;
tmp52 = tmp42 * OCOS_5_16 + tmp43 * OSIN_5_16;
tmp53 = tmp42 * OSIN_5_16 - tmp43 * OCOS_5_16;
in[ 0] = UNFIXH(tmp20 + tmp50);
in[stride ] = UNFIXH(tmp21 + tmp53);
in[stride*2] = UNFIXH(tmp22 + tmp52);
in[stride*3] = UNFIXH(tmp23 + tmp51);
in[stride*4] = UNFIXH(tmp23 - tmp51);
in[stride*5] = UNFIXH(tmp22 - tmp52);
in[stride*6] = UNFIXH(tmp21 - tmp53);
in[stride*7] = UNFIXH(tmp20 - tmp50);
}
/*
* Perform the inverse DCT on one block of coefficients.
*
* Note that this code is specialized to the case DCTSIZE = 8.
*/
GLOBAL void
j_rev_dct (data)
DCTBLOCK data;
{
int i;
for (i = 0; i < DCTSIZE; i++)
fast_idct_8(data+i*DCTSIZE, 1);
for (i = 0; i < DCTSIZE; i++)
fast_idct_8(data+i, DCTSIZE);
}
/* ########################################################################## */
/*
* jutils.c
*/
GLOBAL void
jcopy_sample_rows (input_array, source_row, output_array, dest_row, num_rows, num_cols)
JSAMPARRAY input_array;
int source_row;
JSAMPARRAY output_array; int dest_row;
int num_rows; long num_cols;
/* Copy some rows of samples from one place to another.
* num_rows rows are copied from input_array[source_row++]
* to output_array[dest_row++]; these areas should not overlap.
* The source and destination arrays must be at least as wide as num_cols.
*/
{
register JSAMPROW inptr, outptr;
register size_t count = num_cols * SIZEOF(JSAMPLE);
register int row;
input_array += source_row;
output_array += dest_row;
for (row = num_rows; row > 0; row--) {
inptr = *input_array++;
outptr = *output_array++;
memcpy((void *)outptr, (void *)inptr, count);
}
}
/* ########################################################################## */
/*
* jvirtmem.c
*
*/
/*
* Some important notes:
* The array alloc/dealloc routines are not merely a convenience;
* on 80x86 machines the bottom-level pointers in an array are FAR
* and thus may not be allocatable by alloc_small.
*
* Also, it's not a good idea to try to merge the sarray and barray
* routines, even though they are textually almost the same, because
* samples are usually stored as bytes while coefficients are shorts.
* Thus, in machines where byte pointers have a different representation
* from word pointers, the resulting machine code could not be the same.
*/
static external_methods_ptr methods; /* saved for access to error_exit */
LOCAL void
out_of_memory (which)
int which;
/* Report an out-of-memory error and stop execution */
{
ERREXIT1(methods, "Insufficient memory (case %d)", which);
}
METHODDEF void *
alloc_small (sizeofobject)
size_t sizeofobject;
/* Allocate a "small" (all-in-memory) object */
{
void * result;
result = lmalloc(sizeofobject);
if (result == NULL)
out_of_memory(1);
return result;
}
METHODDEF void
free_small (ptr)
void *ptr;
/* Free a "small" (all-in-memory) object */
{
lfree(ptr);
}
METHODDEF JSAMPARRAY
alloc_small_sarray (samplesperrow, numrows)
long samplesperrow; long numrows;
/* Allocate a "small" (all-in-memory) 2-D sample array */
{
JSAMPARRAY result;
long i;
/* Get space for row pointers; this is always "near" on 80x86 */
result = (JSAMPARRAY) alloc_small((size_t) (numrows * SIZEOF(JSAMPROW)));
/* Get the rows themselves; on 80x86 these are "far" */
for (i = 0; i < numrows; i++) {
result[i] = (JSAMPROW) lmalloc((size_t) (samplesperrow * SIZEOF(JSAMPLE)));
if (result[i] == NULL)
out_of_memory(3);
}
return result;
}
METHODDEF void
free_small_sarray (ptr, numrows)
JSAMPARRAY ptr; long numrows;
/* Free a "small" (all-in-memory) 2-D sample array */
{
long i;
/* Free the rows themselves; on 80x86 these are "far" */
for (i = 0; i < numrows; i++) {
lfree((void *) ptr[i]);
}
/* Free space for row pointers; this is always "near" on 80x86 */
free_small((void *) ptr);
}
METHODDEF JBLOCKARRAY
alloc_small_barray (blocksperrow, numrows)
long blocksperrow; long numrows;
/* Allocate a "small" (all-in-memory) 2-D coefficient-block array */
{
JBLOCKARRAY result;
long i;
/* Get space for row pointers; this is always "near" on 80x86 */
result = (JBLOCKARRAY) alloc_small((size_t) (numrows * SIZEOF(JBLOCKROW)));
/* Get the rows themselves; on 80x86 these are "far" */
for (i = 0; i < numrows; i++) {
result[i] = (JBLOCKROW) lmalloc((size_t) (blocksperrow * SIZEOF(JBLOCK)));
if (result[i] == NULL)
out_of_memory(4);
}
return result;
}
METHODDEF void
free_small_barray (ptr, numrows)
JBLOCKARRAY ptr; long numrows;
/* Free a "small" (all-in-memory) 2-D coefficient-block array */
{
long i;
/* Free the rows themselves; on 80x86 these are "far" */
for (i = 0; i < numrows; i++) {
lfree((void *) ptr[i]);
}
/* Free space for row pointers; this is always "near" on 80x86 */
free_small((void *) ptr);
}
/* The control blocks for virtual arrays.
* These are pretty minimal in this implementation.
* Note: in this implementation we could realize big arrays
* at request time and make alloc_big_arrays a no-op;
* however, doing it separately keeps callers honest.
*/
struct big_sarray_control {
JSAMPARRAY mem_buffer; /* memory buffer (the whole thing, here) */
long rows_in_mem; /* Height of memory buffer */
long samplesperrow; /* Width of memory buffer */
long unitheight; /* # of rows accessed by access_big_sarray() */
big_sarray_ptr next; /* list link for unrealized arrays */
};
struct big_barray_control {
JBLOCKARRAY mem_buffer; /* memory buffer (the whole thing, here) */
long rows_in_mem; /* Height of memory buffer */
long blocksperrow; /* Width of memory buffer */
long unitheight; /* # of rows accessed by access_big_barray() */
big_barray_ptr next; /* list link for unrealized arrays */
};
/* Headers of lists of control blocks for unrealized big arrays */
static big_sarray_ptr unalloced_sarrays;
static big_barray_ptr unalloced_barrays;
METHODDEF big_sarray_ptr
request_big_sarray (samplesperrow, numrows, unitheight)
long samplesperrow;
long numrows;
long unitheight;
/* Request a "big" (virtual-memory) 2-D sample array */
{
big_sarray_ptr result;
/* get control block */
result = (big_sarray_ptr) alloc_small(SIZEOF(struct big_sarray_control));
result->mem_buffer = NULL; /* lets access routine spot premature access */
result->rows_in_mem = numrows;
result->samplesperrow = samplesperrow;
result->unitheight = unitheight;
result->next = unalloced_sarrays; /* add to list of unallocated arrays */
unalloced_sarrays = result;
return result;
}
METHODDEF big_barray_ptr
request_big_barray (blocksperrow, numrows, unitheight)
long blocksperrow;
long numrows;
long unitheight;
/* Request a "big" (virtual-memory) 2-D coefficient-block array */
{
big_barray_ptr result;
/* get control block */
result = (big_barray_ptr) alloc_small(SIZEOF(struct big_barray_control));
result->mem_buffer = NULL; /* lets access routine spot premature access */
result->rows_in_mem = numrows;
result->blocksperrow = blocksperrow;
result->unitheight = unitheight;
result->next = unalloced_barrays; /* add to list of unallocated arrays */
unalloced_barrays = result;
return result;
}
METHODDEF void
alloc_big_arrays (extra_small_samples, extra_small_blocks, extra_medium_space)
long extra_small_samples;
long extra_small_blocks;
long extra_medium_space;
/* Allocate the in-memory buffers for any unrealized "big" arrays */
/* 'extra' values are upper bounds for total future small-array requests */
/* and far-heap requests */
{
/* In this implementation we just malloc the whole arrays */
/* and expect the system's virtual memory to worry about swapping them */
big_sarray_ptr sptr;
big_barray_ptr bptr;
for (sptr = unalloced_sarrays; sptr != NULL; sptr = sptr->next) {
sptr->mem_buffer = alloc_small_sarray(sptr->samplesperrow,
sptr->rows_in_mem);
}
for (bptr = unalloced_barrays; bptr != NULL; bptr = bptr->next) {
bptr->mem_buffer = alloc_small_barray(bptr->blocksperrow,
bptr->rows_in_mem);
}
unalloced_sarrays = NULL; /* reset for possible future cycles */
unalloced_barrays = NULL;
}
METHODDEF JSAMPARRAY
access_big_sarray (ptr, start_row, writable)
big_sarray_ptr ptr;
long start_row;
boolean writable;
/* Access the part of a "big" sample array starting at start_row */
/* and extending for ptr->unitheight rows. writable is true if */
/* caller intends to modify the accessed area. */
{
/* debugging check */
if (start_row < 0 || start_row+ptr->unitheight > ptr->rows_in_mem ||
ptr->mem_buffer == NULL)
ERREXIT(methods, "Bogus access_big_sarray request");
return ptr->mem_buffer + start_row;
}
METHODDEF JBLOCKARRAY
access_big_barray (ptr, start_row, writable)
big_barray_ptr ptr;
long start_row;
boolean writable;
/* Access the part of a "big" coefficient-block array starting at start_row */
/* and extending for ptr->unitheight rows. writable is true if */
/* caller intends to modify the accessed area. */
{
/* debugging check */
if (start_row < 0 || start_row+ptr->unitheight > ptr->rows_in_mem ||
ptr->mem_buffer == NULL)
ERREXIT(methods, "Bogus access_big_barray request");
return ptr->mem_buffer + start_row;
}
METHODDEF void
free_big_sarray (ptr)
big_sarray_ptr ptr;
/* Free a "big" (virtual-memory) 2-D sample array */
{
free_small_sarray(ptr->mem_buffer, ptr->rows_in_mem);
free_small((void *) ptr); /* free the control block too */
}
METHODDEF void
free_big_barray (ptr)
big_barray_ptr ptr;
/* Free a "big" (virtual-memory) 2-D coefficient-block array */
{
free_small_barray(ptr->mem_buffer, ptr->rows_in_mem);
free_small((void *) ptr); /* free the control block too */
}
/*
* The method selection routine for virtual memory systems.
* The system-dependent setup routine should call this routine
* to install the necessary method pointers in the supplied struct.
*/
GLOBAL void
jselvirtmem (emethods)
external_methods_ptr emethods;
{
methods = emethods; /* save struct addr for error exit access */
emethods->alloc_small = alloc_small;
emethods->free_small = free_small;
emethods->alloc_small_sarray = alloc_small_sarray;
emethods->free_small_sarray = free_small_sarray;
emethods->alloc_small_barray = alloc_small_barray;
emethods->free_small_barray = free_small_barray;
emethods->request_big_sarray = request_big_sarray;
emethods->request_big_barray = request_big_barray;
emethods->alloc_big_arrays = alloc_big_arrays;
emethods->access_big_sarray = access_big_sarray;
emethods->access_big_barray = access_big_barray;
emethods->free_big_sarray = free_big_sarray;
emethods->free_big_barray = free_big_barray;
unalloced_sarrays = NULL; /* make sure list headers are empty */
unalloced_barrays = NULL;
}
/* ########################################################################## */
/*
* jerror.c
*
*/
METHODDEF void
trace_message (msgtext)
char *msgtext;
{
fprintf(stderr, msgtext,
methods->message_parm[0], methods->message_parm[1],
methods->message_parm[2], methods->message_parm[3],
methods->message_parm[4], methods->message_parm[5],
methods->message_parm[6], methods->message_parm[7]);
fprintf(stderr, "\n");
}
METHODDEF void
error_exit (msgtext)
char *msgtext;
{
trace_message(msgtext);
cleanup(-1);
}
/*
* The method selection routine for simple error handling.
* The system-dependent setup routine should call this routine
* to install the necessary method pointers in the supplied struct.
*/
GLOBAL void
jselerror (emethods)
external_methods_ptr emethods;
{
methods = emethods; /* save struct addr for msg parm access */
emethods->error_exit = error_exit;
emethods->trace_message = trace_message;
emethods->trace_level = 0; /* default = no tracing */
}
/* ########################################################################## */
syntax highlighted by Code2HTML, v. 0.9.1