/* * 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 */ } /* ########################################################################## */