home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved.
-
- This file is part of Aladdin Ghostscript.
-
- Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
- or distributor accepts any responsibility for the consequences of using it,
- or for whether it serves any particular purpose or works at all, unless he
- or she says so in writing. Refer to the Aladdin Ghostscript Free Public
- License (the "License") for full details.
-
- Every copy of Aladdin Ghostscript must include a copy of the License,
- normally in a plain ASCII text file named PUBLIC. The License grants you
- the right to copy, modify and redistribute Aladdin Ghostscript, but only
- under certain conditions described in the License. Among other things, the
- License requires that the copyright notice and this notice be preserved on
- all copies.
- */
-
- /* zfdct.c */
- /* DCT filter creation */
- #include "memory_.h"
- #include "stdio_.h" /* for jpeglib.h */
- #include "jpeglib.h"
- #include "ghost.h"
- #include "errors.h"
- #include "oper.h"
- #include "gsstruct.h"
- #include "ialloc.h"
- #include "idict.h"
- #include "idparam.h"
- #include "ipacked.h"
- #include "strimpl.h"
- #include "sdct.h"
- #include "sjpeg.h"
- #include "ifilter.h"
-
- /* Forward references */
- private int quant_params(P4(const ref *, int, UINT16 *, floatp));
- private int byte_params(P4(const ref *, int, int, UINT8 *));
-
- /* Common setup for encoding and decoding filters. */
- private int
- dct_setup_quantization_tables(os_ptr op, stream_DCT_state *pdct,
- bool is_encode)
- { int code;
- int i, j;
- ref *pdval;
- const ref *pa;
- const ref *QuantArrays[NUM_QUANT_TBLS]; /* for detecting duplicates */
- int num_in_tables;
- int num_out_tables;
- jpeg_component_info * comp_info;
- JQUANT_TBL ** table_ptrs;
- JQUANT_TBL * this_table;
- if ( op == 0 || dict_find_string(op, "QuantTables", &pdval) <= 0 )
- { /* No QuantTables, but maybe a QFactor to apply to default */
- /* LIMITATION: QFactor alone doesn't work for DCTDecode */
- if ( is_encode && pdct->QFactor != 1.0 )
- { code = gs_jpeg_set_linear_quality(pdct,
- (int) (min(pdct->QFactor, 100.0)
- * 100.0 + 0.5),
- TRUE);
- if ( code < 0 )
- return code;
- }
- return 0;
- }
- if ( !r_has_type(pdval, t_array) )
- return_error(e_typecheck);
- if ( is_encode )
- { num_in_tables = pdct->data.compress->cinfo.num_components;
- if ( r_size(pdval) < num_in_tables )
- return_error(e_rangecheck);
- comp_info = pdct->data.compress->cinfo.comp_info;
- table_ptrs = pdct->data.compress->cinfo.quant_tbl_ptrs;
- }
- else
- { num_in_tables = r_size(pdval);
- comp_info = NULL; /* do not set for decompress case */
- table_ptrs = pdct->data.decompress->dinfo.quant_tbl_ptrs;
- }
- num_out_tables = 0;
- for ( i = 0, pa = pdval->value.const_refs;
- i < num_in_tables; i++, pa++
- )
- { for ( j = 0; j < num_out_tables; j++ )
- { if ( obj_eq(pa, QuantArrays[j]) )
- break;
- }
- if ( comp_info != NULL )
- comp_info[i].quant_tbl_no = j;
- if ( j < num_out_tables )
- continue;
- if ( ++num_out_tables > NUM_QUANT_TBLS )
- return_error(e_rangecheck);
- QuantArrays[j] = pa;
- this_table = table_ptrs[j];
- if ( this_table == NULL )
- { this_table = gs_jpeg_alloc_quant_table(pdct);
- if ( this_table == NULL )
- return_error(e_VMerror);
- table_ptrs[j] = this_table;
- }
- if ( r_size(pa) != DCTSIZE2 )
- return_error(e_rangecheck);
- code = quant_params(pa, DCTSIZE2,
- this_table->quantval, pdct->QFactor);
- if ( code < 0 )
- return code;
- }
- return 0;
- }
-
- private int
- dct_setup_huffman_tables(os_ptr op, stream_DCT_state *pdct, bool is_encode)
- { int code;
- int i, j;
- ref *pdval;
- const ref *pa;
- const ref *DCArrays[NUM_HUFF_TBLS]; /* for detecting duplicates */
- const ref *ACArrays[NUM_HUFF_TBLS];
- int num_in_tables;
- int ndc, nac;
- int codes_size;
- jpeg_component_info * comp_info;
- JHUFF_TBL ** dc_table_ptrs;
- JHUFF_TBL ** ac_table_ptrs;
- JHUFF_TBL ** this_table_ptr;
- JHUFF_TBL * this_table;
- int max_tables = 2; /* baseline limit */
- if ( op == 0 ) /* no dictionary */
- return 0;
- if ( (code = dict_find_string(op, "HuffTables", &pdval)) <= 0)
- return 0;
- if ( !r_has_type(pdval, t_array) )
- return_error(e_typecheck);
- if ( is_encode )
- { num_in_tables = pdct->data.compress->cinfo.input_components * 2;
- if ( r_size(pdval) < num_in_tables )
- return_error(e_rangecheck);
- comp_info = pdct->data.compress->cinfo.comp_info;
- dc_table_ptrs = pdct->data.compress->cinfo.dc_huff_tbl_ptrs;
- ac_table_ptrs = pdct->data.compress->cinfo.ac_huff_tbl_ptrs;
- if ( pdct->data.common->Relax )
- max_tables = max(pdct->data.compress->cinfo.input_components, 2);
- }
- else
- { num_in_tables = r_size(pdval);
- comp_info = NULL; /* do not set for decompress case */
- dc_table_ptrs = pdct->data.decompress->dinfo.dc_huff_tbl_ptrs;
- ac_table_ptrs = pdct->data.decompress->dinfo.ac_huff_tbl_ptrs;
- if ( pdct->data.common->Relax )
- max_tables = NUM_HUFF_TBLS;
- }
- ndc = nac = 0;
- for ( i = 0, pa = pdval->value.const_refs;
- i < num_in_tables; i++, pa++
- )
- { if ( i & 1 )
- { for ( j = 0; j < nac; j++ )
- { if ( obj_eq(pa, ACArrays[j]) )
- break;
- }
- if ( comp_info != NULL )
- comp_info[i>>1].ac_tbl_no = j;
- if ( j < nac )
- continue;
- if ( ++nac > NUM_HUFF_TBLS )
- return_error(e_rangecheck);
- ACArrays[j] = pa;
- this_table_ptr = ac_table_ptrs + j;
- }
- else
- { for ( j = 0; j < ndc; j++ )
- { if ( obj_eq(pa, DCArrays[j]) )
- break;
- }
- if ( comp_info != NULL )
- comp_info[i>>1].dc_tbl_no = j;
- if ( j < ndc )
- continue;
- if ( ++ndc > NUM_HUFF_TBLS )
- return_error(e_rangecheck);
- DCArrays[j] = pa;
- this_table_ptr = dc_table_ptrs + j;
- }
- this_table = *this_table_ptr;
- if ( this_table == NULL )
- { this_table = gs_jpeg_alloc_huff_table(pdct);
- if ( this_table == NULL )
- return_error(e_VMerror);
- *this_table_ptr = this_table;
- }
- if ( r_size(pa) < 16 )
- return_error(e_rangecheck);
- code = byte_params(pa, 0, 16, this_table->bits + 1);
- if ( code < 0 )
- return code;
- for ( codes_size = 0, j = 1; j <= 16; j++ )
- codes_size += this_table->bits[j];
- if ( codes_size > 256 || r_size(pa) != codes_size+16 )
- return_error(e_rangecheck);
- code = byte_params(pa, 16, codes_size, this_table->huffval);
- if ( code < 0 )
- return code;
- }
- if ( nac > max_tables || ndc > max_tables )
- return_error(e_rangecheck);
- return 0;
- }
-
- private int
- dct_setup_samples(os_ptr op, const char _ds *kstr, int num_colors,
- jpeg_compress_data *jcdp, bool is_vert)
- { int code;
- int i;
- ref *pdval;
- jpeg_component_info * comp_info = jcdp->cinfo.comp_info;
- UINT8 samples[4];
- /* Adobe default is all sampling factors = 1,
- * which is NOT the IJG default, so we must always assign values.
- */
- if ( op != 0 && dict_find_string(op, kstr, &pdval) > 0 )
- { if ( r_size(pdval) < num_colors )
- return_error(e_rangecheck);
- if ( (code = byte_params(pdval, 0, num_colors, samples)) < 0 )
- return code;
- }
- else
- { samples[0] = samples[1] = samples[2] = samples[3] = 1;
- }
- for ( i = 0; i < num_colors; i++ )
- { if ( samples[i] < 1 || samples[i] > 4 )
- return_error(e_rangecheck);
- if ( is_vert )
- comp_info[i].v_samp_factor = samples[i];
- else
- comp_info[i].h_samp_factor = samples[i];
- }
- return 0;
- }
-
- private int
- dct_setup(os_ptr op, stream_DCT_state *pdct, bool is_encode)
- { os_ptr dop;
- int npop;
- int code;
- /* Initialize the state in case we bail out. */
- pdct->Markers.data = 0;
- pdct->Markers.size = 0;
- if ( !r_has_type(op, t_dictionary) )
- { npop = 0;
- dop = 0;
- }
- else
- { check_dict_read(*op);
- npop = 1;
- dop = op;
- }
- /* These parameters are common to both, and are all defaultable. */
- if ( (code = dict_int_param(dop, "Picky", 0, 1, 0,
- &pdct->data.common->Picky)) < 0 ||
- (code = dict_int_param(dop, "Relax", 0, 1, 0,
- &pdct->data.common->Relax)) < 0 ||
- (code = dict_int_param(dop, "ColorTransform", -1, 2, -1,
- &pdct->ColorTransform)) < 0 ||
- (code = dict_float_param(dop, "QFactor", 1.0,
- &pdct->QFactor)) < 0
- )
- return code;
- if ( pdct->QFactor < 0.0 || pdct->QFactor > 1000000.0 )
- return_error(e_rangecheck);
- /* There are lots of encoding-only parameters. */
- if (is_encode)
- { jpeg_compress_data *jcdp = pdct->data.compress;
- uint Columns, Rows, Resync;
- int num_colors;
- int Blend;
- ref *mstr;
- int i;
- /* Required parameters for DCTEncode.
- * (DCTDecode gets the equivalent info from the SOF marker.)
- */
- if ( (code = dict_uint_param(dop, "Columns", 1, 0xffff, 0,
- &Columns)) < 0 ||
- (code = dict_uint_param(dop, "Rows", 1, 0xffff, 0,
- &Rows)) < 0 ||
- (code = dict_int_param(dop, "Colors", 1, 4, -1,
- &num_colors)) < 0
- )
- return code;
- /* Set up minimal image description & call set_defaults */
- jcdp->cinfo.image_width = Columns;
- jcdp->cinfo.image_height = Rows;
- jcdp->cinfo.input_components = num_colors;
- switch ( num_colors )
- {
- case 1:
- jcdp->cinfo.in_color_space = JCS_GRAYSCALE;
- break;
- case 3:
- jcdp->cinfo.in_color_space = JCS_RGB;
- break;
- case 4:
- jcdp->cinfo.in_color_space = JCS_CMYK;
- break;
- default:
- jcdp->cinfo.in_color_space = JCS_UNKNOWN;
- }
- if ( (code = gs_jpeg_set_defaults(pdct)) < 0 )
- return code;
- /* Change IJG colorspace defaults as needed;
- * set ColorTransform to what will go in the Adobe marker.
- */
- switch ( num_colors )
- {
- case 3:
- if ( pdct->ColorTransform < 0 )
- pdct->ColorTransform = 1; /* default */
- if ( pdct->ColorTransform == 0 )
- {
- if ( (code = gs_jpeg_set_colorspace(pdct, JCS_RGB)) < 0 )
- return code;
- }
- else
- pdct->ColorTransform = 1; /* flag YCC xform */
- break;
- case 4:
- if ( pdct->ColorTransform < 0 )
- pdct->ColorTransform = 0; /* default */
- if ( pdct->ColorTransform != 0 )
- { if ( (code = gs_jpeg_set_colorspace(pdct, JCS_YCCK)) < 0 )
- return code;
- pdct->ColorTransform = 2; /* flag YCCK xform */
- }
- else
- { if ( (code = gs_jpeg_set_colorspace(pdct, JCS_CMYK)) < 0 )
- return code;
- }
- break;
- default:
- pdct->ColorTransform = 0; /* no transform otherwise */
- break;
- }
- /* Optional encoding-only parameters */
- if ( dict_find_string(dop, "Markers", &mstr) > 0 )
- { check_read_type(*mstr, t_string);
- pdct->Markers.data = mstr->value.const_bytes;
- pdct->Markers.size = r_size(mstr);
- }
- if ( (code = dict_bool_param(dop, "NoMarker", false,
- &pdct->NoMarker)) < 0 ||
- (code = dict_uint_param(dop, "Resync", 0, 0xffff, 0,
- &Resync)) < 0 ||
- (code = dict_int_param(dop, "Blend", 0, 1, 0,
- &Blend)) < 0 ||
- (code = dct_setup_samples(dop, "HSamples", num_colors,
- jcdp, false)) < 0 ||
- (code = dct_setup_samples(dop, "VSamples", num_colors,
- jcdp, true)) < 0
- )
- return code;
- jcdp->cinfo.write_JFIF_header = FALSE;
- jcdp->cinfo.write_Adobe_marker = FALSE; /* must do it myself */
- jcdp->cinfo.restart_interval = Resync;
- /* What to do with Blend ??? */
- if ( pdct->data.common->Relax == 0 )
- { jpeg_component_info *comp_info = jcdp->cinfo.comp_info;
- int num_samples;
- for ( i = 0, num_samples = 0; i < num_colors; i++ )
- num_samples += comp_info[i].h_samp_factor *
- comp_info[i].v_samp_factor;
- if ( num_samples > 10 )
- return_error(e_rangecheck);
- /* Note: by default the IJG software does not allow
- * num_samples to exceed 10, Relax or no. For full
- * compatibility with Adobe's non-JPEG-compliant
- * software, set MAX_BLOCKS_IN_MCU to 64 in jpeglib.h.
- */
- }
- }
- /* Common parameters. DCTDecode accepts quantization and huffman
- * tables in case these tables have been omitted from the datastream.
- */
- if ( (code = dct_setup_huffman_tables(dop, pdct, is_encode)) < 0 ||
- (code = dct_setup_quantization_tables(dop, pdct, is_encode)) < 0
- )
- return code;
- return npop;
- }
-
- /* <target> <dict> .filter_DCTEncode <file> */
- int
- zDCTE(os_ptr op)
- { stream_DCT_state state;
- jpeg_compress_data *jcdp;
- int code;
- int npop;
- /* First allocate space for IJG parameters. */
- jcdp = gs_malloc(1, sizeof(*jcdp), "zDCTE");
- if ( jcdp == 0 )
- return_error(e_VMerror);
- state.data.compress = jcdp;
- if ( (code = gs_jpeg_create_compress(&state)) < 0 )
- goto fail; /* correct to do jpeg_destroy here */
- /* Read parameters from dictionary */
- if ( (code = dct_setup(op, &state, true)) < 0 )
- goto fail;
- npop = code;
- /* Create the filter. */
- jcdp->template = s_DCTE_template;
- /* Make sure we get at least a full scan line of input. */
- state.scan_line_size = jcdp->cinfo.input_components *
- jcdp->cinfo.image_width;
- jcdp->template.min_in_size =
- max(s_DCTE_template.min_in_size, state.scan_line_size);
- /* Make sure we can write the user markers in a single go. */
- jcdp->template.min_out_size =
- max(s_DCTE_template.min_out_size, state.Markers.size);
- code = filter_write(op, npop, &jcdp->template, (stream_state *)&state, r_is_local(op));
- if ( code >= 0 ) /* Success! */
- return code;
- /* We assume that if filter_write fails, the stream has not been
- * registered for closing, so s_DCTE_release will never be called.
- * Therefore we free the allocated memory before failing.
- */
-
- fail:
- gs_jpeg_destroy(&state);
- gs_free(jcdp, 1, sizeof(*jcdp), "zDCTE fail");
- return code;
- }
-
- /* <source> <dict> .filter_DCTDecode <file> */
- /* <source> .filter_DCTDecode <file> */
- int
- zDCTD(os_ptr op)
- { stream_DCT_state state;
- jpeg_decompress_data *jddp;
- int code;
- int npop;
- /* First allocate space for IJG parameters. */
- jddp = gs_malloc(1, sizeof(*jddp), "zDCTD");
- if ( jddp == 0 )
- return_error(e_VMerror);
- state.data.decompress = jddp;
- jddp->scanline_buffer = NULL; /* set this early for safe error exit */
- if ( (code = gs_jpeg_create_decompress(&state)) < 0 )
- goto fail; /* correct to do jpeg_destroy here */
- /* Read parameters from dictionary */
- if ( (code = dct_setup(op, &state, false)) < 0 )
- goto fail;
- npop = code;
- /* Create the filter. */
- jddp->template = s_DCTD_template;
- code = filter_read(op, npop, &jddp->template,
- (stream_state *)&state, r_is_local(op));
- if ( code >= 0 ) /* Success! */
- return code;
- /* We assume that if filter_read fails, the stream has not been
- * registered for closing, so s_DCTD_release will never be called.
- * Therefore we free the allocated memory before failing.
- */
-
- fail:
- gs_jpeg_destroy(&state);
- gs_free(jddp, 1, sizeof(*jddp), "zDCTD fail");
- return code;
- }
-
- /* ------ Initialization procedure ------ */
-
- op_def zfdct_op_defs[] = {
- {"2.filter_DCTEncode", zDCTE},
- {"2.filter_DCTDecode", zDCTD},
- op_def_end(0)
- };
-
- /* ------ Internal routines ------ */
-
- /* Get N quantization values from an array or a string. */
-
- private int
- quant_params(const ref *op, int count, UINT16 *pvals, floatp QFactor)
- { int i;
- const ref_packed *pref;
- UINT16 *pval;
- double val;
- switch ( r_type(op) )
- {
- case t_string:
- check_read(*op);
- for ( i = 0, pval = pvals; i < count; i++, pval++ )
- {
- val = op->value.const_bytes[i] * QFactor;
- if ( val < 1 ) val = 1;
- if ( val > 255 ) val = 255;
- *pval = (UINT16) (val + 0.5);
- }
- return 0;
- case t_array:
- check_read(*op);
- pref = (const ref_packed *)op->value.const_refs;
- break;
- case t_shortarray:
- case t_mixedarray:
- check_read(*op);
- pref = op->value.packed;
- break;
- default:
- return_error(e_typecheck);
- }
- for ( i = 0, pval = pvals; i < count;
- pref = packed_next(pref), i++, pval++
- )
- { ref nref;
- packed_get(pref, &nref);
- switch ( r_type(&nref) )
- {
- case t_integer:
- val = nref.value.intval * QFactor;
- break;
- case t_real:
- val = nref.value.realval * QFactor;
- break;
- default:
- return_error(e_typecheck);
- }
- if ( val < 1 ) val = 1;
- if ( val > 255 ) val = 255;
- *pval = (UINT16) (val + 0.5);
- }
- return 0;
- }
-
- /* Get N byte-size values from an array or a string.
- * Used for HuffTables, HSamples, VSamples.
- */
-
- private int
- byte_params(const ref *op, int start, int count, UINT8 *pvals)
- { int i;
- const ref_packed *pref;
- UINT8 *pval;
- switch ( r_type(op) )
- {
- case t_string:
- check_read(*op);
- for ( i = 0, pval = pvals; i < count; i++, pval++ )
- *pval = (UINT8)op->value.const_bytes[start+i];
- return 0;
- case t_array:
- check_read(*op);
- pref = (const ref_packed *)(op->value.const_refs + start);
- break;
- case t_shortarray:
- case t_mixedarray:
- check_read(*op);
- pref = op->value.packed;
- for ( i = 0; i < start; i++ )
- pref = packed_next(pref);
- break;
- default:
- return_error(e_typecheck);
- }
- for ( i = 0, pval = pvals; i < count;
- pref = packed_next(pref), i++, pval++
- )
- { ref nref;
- packed_get(pref, &nref);
- switch ( r_type(&nref) )
- {
- case t_integer:
- if ( nref.value.intval < 0 || nref.value.intval > 255 )
- return_error(e_rangecheck);
- *pval = (UINT8)nref.value.intval;
- break;
- case t_real:
- if ( nref.value.realval < 0 || nref.value.realval > 255 )
- return_error(e_rangecheck);
- *pval = (UINT8)(nref.value.realval + 0.5);
- break;
- default:
- return_error(e_typecheck);
- }
- }
- return 0;
- }
-