/* Copyright (C) 1998, 1999 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: sdeparam.c,v 1.4.2.1.2.1 2003/01/17 00:49:05 giles Exp $ */ /* DCTEncode filter parameter setting and reading */ #include "memory_.h" #include "jpeglib_.h" #include "gserror.h" #include "gserrors.h" #include "gstypes.h" #include "gsmemory.h" #include "gsparam.h" #include "strimpl.h" /* sdct.h requires this */ #include "sdct.h" #include "sdcparam.h" #include "sjpeg.h" /* Define a structure for the DCTEncode scalar parameters. */ typedef struct dcte_scalars_s { int Columns; int Rows; int Colors; gs_param_string Markers; bool NoMarker; int Resync; int Blend; } dcte_scalars_t; private const dcte_scalars_t dcte_scalars_default = { 0, 0, -1, {0, 0}, 0 /*false */ , 0, 0 }; private const gs_param_item_t s_DCTE_param_items[] = { #define dctp(key, type, memb) { key, type, offset_of(dcte_scalars_t, memb) } dctp("Columns", gs_param_type_int, Columns), dctp("Rows", gs_param_type_int, Rows), dctp("Colors", gs_param_type_int, Colors), dctp("Marker", gs_param_type_string, Markers), dctp("NoMarker", gs_param_type_bool, NoMarker), dctp("Resync", gs_param_type_int, Resync), dctp("Blend", gs_param_type_int, Blend), #undef dctp gs_param_item_end }; /* ================ Get parameters ================ */ stream_state_proc_get_params(s_DCTE_get_params, stream_DCT_state); /* check */ /* Get a set of sampling values. */ private int dcte_get_samples(gs_param_list * plist, gs_param_name key, int num_colors, const jpeg_compress_data * jcdp, gs_memory_t * mem, bool is_vert, bool all) { const jpeg_component_info *comp_info = jcdp->cinfo.comp_info; int samples[4]; bool write = all; int i; for (i = 0; i < num_colors; ++i) write |= (samples[i] = (is_vert ? comp_info[i].v_samp_factor : comp_info[i].h_samp_factor)) != 1; if (write) { int *data = (int *)gs_alloc_byte_array(mem, num_colors, sizeof(int), "dcte_get_samples"); gs_param_int_array sa; if (data == 0) return_error(gs_error_VMerror); sa.data = data; sa.size = num_colors; sa.persistent = true; memcpy(data, samples, num_colors * sizeof(samples[0])); return param_write_int_array(plist, key, &sa); } return 0; } int s_DCTE_get_params(gs_param_list * plist, const stream_DCT_state * ss, bool all) { gs_memory_t *mem = ss->memory; stream_DCT_state dcts_defaults; const stream_DCT_state *defaults = 0; dcte_scalars_t params; const jpeg_compress_data *jcdp = ss->data.compress; int code; if (!all) { jpeg_compress_data *jcdp_default = gs_alloc_struct_immovable(mem, jpeg_compress_data, &st_jpeg_compress_data, "s_DCTE_get_params"); if (jcdp_default == 0) return_error(gs_error_VMerror); defaults = &dcts_defaults; (*s_DCTE_template.set_defaults) ((stream_state *) & dcts_defaults); dcts_defaults.data.compress = jcdp_default; jcdp_default->memory = dcts_defaults.jpeg_memory = mem; if ((code = gs_jpeg_create_compress(&dcts_defaults)) < 0) goto fail; /* correct to do jpeg_destroy here */ /****** SET DEFAULTS HERE ******/ dcts_defaults.data.common->Picky = 0; dcts_defaults.data.common->Relax = 0; } params.Columns = jcdp->cinfo.image_width; params.Rows = jcdp->cinfo.image_height; params.Colors = jcdp->cinfo.input_components; params.Markers.data = ss->Markers.data; params.Markers.size = ss->Markers.size; params.Markers.persistent = false; params.NoMarker = ss->NoMarker; params.Resync = jcdp->cinfo.restart_interval; /* What about Blend?? */ if ((code = s_DCT_get_params(plist, ss, defaults)) < 0 || (code = gs_param_write_items(plist, ¶ms, &dcte_scalars_default, s_DCTE_param_items)) < 0 || (code = dcte_get_samples(plist, "HSamples", params.Colors, jcdp, mem, false, all)) < 0 || (code = dcte_get_samples(plist, "VSamples", params.Colors, jcdp, mem, true, all)) < 0 || (code = s_DCT_get_quantization_tables(plist, ss, defaults, true)) < 0 || (code = s_DCT_get_huffman_tables(plist, ss, defaults, true)) < 0 ) DO_NOTHING; /****** NYI ******/ fail:if (defaults) { gs_jpeg_destroy(&dcts_defaults); gs_free_object(mem, dcts_defaults.data.compress, "s_DCTE_get_params"); } return code; } /* ================ Put parameters ================ */ stream_state_proc_put_params(s_DCTE_put_params, stream_DCT_state); /* check */ /* Put a set of sampling values. */ private int dcte_put_samples(gs_param_list * plist, gs_param_name key, int num_colors, jpeg_compress_data * jcdp, bool is_vert) { int code; int i; 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. */ switch ((code = s_DCT_byte_params(plist, key, 0, num_colors, samples)) ) { default: /* error */ return code; case 0: break; case 1: 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(gs_error_rangecheck); if (is_vert) comp_info[i].v_samp_factor = samples[i]; else comp_info[i].h_samp_factor = samples[i]; } return 0; } /* Main procedure */ int s_DCTE_put_params(gs_param_list * plist, stream_DCT_state * pdct) { jpeg_compress_data *jcdp = pdct->data.compress; dcte_scalars_t params; int i; int code; params = dcte_scalars_default; /* * Required parameters for DCTEncode. * (DCTDecode gets the equivalent info from the SOF marker.) */ code = gs_param_read_items(plist, ¶ms, s_DCTE_param_items); if (code < 0) return code; if (params.Columns <= 0 || params.Columns > 0xffff || params.Rows <= 0 || params.Rows > 0xffff || params.Colors <= 0 || params.Colors == 2 || params.Colors > 4 || params.Resync < 0 || params.Resync > 0xffff || params.Blend < 0 || params.Blend > 1 ) return_error(gs_error_rangecheck); jcdp->Picky = 0; jcdp->Relax = 0; if ((code = s_DCT_put_params(plist, pdct)) < 0) return code; /* Set up minimal image description & call set_defaults */ jcdp->cinfo.image_width = params.Columns; jcdp->cinfo.image_height = params.Rows; jcdp->cinfo.input_components = params.Colors; switch (params.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; if ((code = s_DCT_put_huffman_tables(plist, pdct, false)) < 0) return code; switch ((code = s_DCT_put_quantization_tables(plist, pdct, false))) { case 0: break; default: return code; case 1: /* No QuantTables, but maybe a QFactor to apply to default. */ if (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; } } /* Change IJG colorspace defaults as needed; * set ColorTransform to what will go in the Adobe marker. */ switch (params.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 */ pdct->Markers.data = params.Markers.data; pdct->Markers.size = params.Markers.size; pdct->NoMarker = params.NoMarker; if ((code = dcte_put_samples(plist, "HSamples", params.Colors, jcdp, false)) < 0 || (code = dcte_put_samples(plist, "VSamples", params.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 = params.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 < params.Colors; i++) num_samples += comp_info[i].h_samp_factor * comp_info[i].v_samp_factor; if (num_samples > 10) return_error(gs_error_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. */ } return 0; }