Referring to https://github.com/libjpeg-turbo/libjpeg-turbo/issues/402#issuecomment-768348440 and https://github.com/libjpeg-turbo/libjpeg-turbo/issues/402#issuecomment-770221584 Ken Murchison clarified that it was his intent to release the lossless JPEG patch under the IJG License and that adding his name to the copyright headers would be sufficient to acknowledge that any derivatives are based on his work.
231 lines
7.2 KiB
C
231 lines
7.2 KiB
C
/*
|
|
* jdlossy.c
|
|
*
|
|
* This file was part of the Independent JPEG Group's software:
|
|
* Copyright (C) 1998, Thomas G. Lane.
|
|
* Lossless JPEG Modifications:
|
|
* Copyright (C) 1999, Ken Murchison.
|
|
* For conditions of distribution and use, see the accompanying README file.
|
|
*
|
|
* This file contains the control logic for the lossy JPEG decompressor.
|
|
*/
|
|
|
|
#define JPEG_INTERNALS
|
|
#include "jinclude.h"
|
|
#include "jpeglib.h"
|
|
#include "jlossy.h"
|
|
|
|
|
|
/*
|
|
* Compute output image dimensions and related values.
|
|
*/
|
|
|
|
METHODDEF(void)
|
|
calc_output_dimensions (j_decompress_ptr cinfo)
|
|
{
|
|
#ifdef IDCT_SCALING_SUPPORTED
|
|
int ci;
|
|
jpeg_component_info *compptr;
|
|
|
|
/* Compute actual output image dimensions and DCT scaling choices. */
|
|
if (cinfo->scale_num * 8 <= cinfo->scale_denom) {
|
|
/* Provide 1/8 scaling */
|
|
cinfo->output_width = (JDIMENSION)
|
|
jdiv_round_up((long) cinfo->image_width, 8L);
|
|
cinfo->output_height = (JDIMENSION)
|
|
jdiv_round_up((long) cinfo->image_height, 8L);
|
|
cinfo->min_codec_data_unit = 1;
|
|
} else if (cinfo->scale_num * 4 <= cinfo->scale_denom) {
|
|
/* Provide 1/4 scaling */
|
|
cinfo->output_width = (JDIMENSION)
|
|
jdiv_round_up((long) cinfo->image_width, 4L);
|
|
cinfo->output_height = (JDIMENSION)
|
|
jdiv_round_up((long) cinfo->image_height, 4L);
|
|
cinfo->min_codec_data_unit = 2;
|
|
} else if (cinfo->scale_num * 2 <= cinfo->scale_denom) {
|
|
/* Provide 1/2 scaling */
|
|
cinfo->output_width = (JDIMENSION)
|
|
jdiv_round_up((long) cinfo->image_width, 2L);
|
|
cinfo->output_height = (JDIMENSION)
|
|
jdiv_round_up((long) cinfo->image_height, 2L);
|
|
cinfo->min_codec_data_unit = 4;
|
|
} else {
|
|
/* Provide 1/1 scaling */
|
|
cinfo->output_width = cinfo->image_width;
|
|
cinfo->output_height = cinfo->image_height;
|
|
cinfo->min_codec_data_unit = DCTSIZE;
|
|
}
|
|
/* In selecting the actual DCT scaling for each component, we try to
|
|
* scale up the chroma components via IDCT scaling rather than upsampling.
|
|
* This saves time if the upsampler gets to use 1:1 scaling.
|
|
* Note this code assumes that the supported DCT scalings are powers of 2.
|
|
*/
|
|
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
|
|
ci++, compptr++) {
|
|
int ssize = cinfo->min_codec_data_unit;
|
|
while (ssize < DCTSIZE &&
|
|
(compptr->h_samp_factor * ssize * 2 <=
|
|
cinfo->max_h_samp_factor * cinfo->min_codec_data_unit) &&
|
|
(compptr->v_samp_factor * ssize * 2 <=
|
|
cinfo->max_v_samp_factor * cinfo->min_codec_data_unit)) {
|
|
ssize = ssize * 2;
|
|
}
|
|
compptr->codec_data_unit = ssize;
|
|
}
|
|
|
|
/* Recompute downsampled dimensions of components;
|
|
* application needs to know these if using raw downsampled data.
|
|
*/
|
|
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
|
|
ci++, compptr++) {
|
|
/* Size in samples, after IDCT scaling */
|
|
compptr->downsampled_width = (JDIMENSION)
|
|
jdiv_round_up((long) cinfo->image_width *
|
|
(long) (compptr->h_samp_factor * compptr->codec_data_unit),
|
|
(long) (cinfo->max_h_samp_factor * DCTSIZE));
|
|
compptr->downsampled_height = (JDIMENSION)
|
|
jdiv_round_up((long) cinfo->image_height *
|
|
(long) (compptr->v_samp_factor * compptr->codec_data_unit),
|
|
(long) (cinfo->max_v_samp_factor * DCTSIZE));
|
|
}
|
|
|
|
#else /* !IDCT_SCALING_SUPPORTED */
|
|
|
|
/* Hardwire it to "no scaling" */
|
|
cinfo->output_width = cinfo->image_width;
|
|
cinfo->output_height = cinfo->image_height;
|
|
/* jdinput.c has already initialized codec_data_unit to DCTSIZE,
|
|
* and has computed unscaled downsampled_width and downsampled_height.
|
|
*/
|
|
|
|
#endif /* IDCT_SCALING_SUPPORTED */
|
|
}
|
|
|
|
|
|
/*
|
|
* Save away a copy of the Q-table referenced by each component present
|
|
* in the current scan, unless already saved during a prior scan.
|
|
*
|
|
* In a multiple-scan JPEG file, the encoder could assign different components
|
|
* the same Q-table slot number, but change table definitions between scans
|
|
* so that each component uses a different Q-table. (The IJG encoder is not
|
|
* currently capable of doing this, but other encoders might.) Since we want
|
|
* to be able to dequantize all the components at the end of the file, this
|
|
* means that we have to save away the table actually used for each component.
|
|
* We do this by copying the table at the start of the first scan containing
|
|
* the component.
|
|
* The JPEG spec prohibits the encoder from changing the contents of a Q-table
|
|
* slot between scans of a component using that slot. If the encoder does so
|
|
* anyway, this decoder will simply use the Q-table values that were current
|
|
* at the start of the first scan for the component.
|
|
*
|
|
* The decompressor output side looks only at the saved quant tables,
|
|
* not at the current Q-table slots.
|
|
*/
|
|
|
|
LOCAL(void)
|
|
latch_quant_tables (j_decompress_ptr cinfo)
|
|
{
|
|
int ci, qtblno;
|
|
jpeg_component_info *compptr;
|
|
JQUANT_TBL * qtbl;
|
|
|
|
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
|
|
compptr = cinfo->cur_comp_info[ci];
|
|
/* No work if we already saved Q-table for this component */
|
|
if (compptr->quant_table != NULL)
|
|
continue;
|
|
/* Make sure specified quantization table is present */
|
|
qtblno = compptr->quant_tbl_no;
|
|
if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
|
|
cinfo->quant_tbl_ptrs[qtblno] == NULL)
|
|
ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
|
|
/* OK, save away the quantization table */
|
|
qtbl = (JQUANT_TBL *)
|
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
|
SIZEOF(JQUANT_TBL));
|
|
MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL));
|
|
compptr->quant_table = qtbl;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Initialize for an input processing pass.
|
|
*/
|
|
|
|
METHODDEF(void)
|
|
start_input_pass (j_decompress_ptr cinfo)
|
|
{
|
|
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec;
|
|
|
|
latch_quant_tables(cinfo);
|
|
(*lossyd->entropy_start_pass) (cinfo);
|
|
(*lossyd->coef_start_input_pass) (cinfo);
|
|
}
|
|
|
|
|
|
/*
|
|
* Initialize for an output processing pass.
|
|
*/
|
|
|
|
METHODDEF(void)
|
|
start_output_pass (j_decompress_ptr cinfo)
|
|
{
|
|
j_lossy_d_ptr lossyd = (j_lossy_d_ptr) cinfo->codec;
|
|
|
|
(*lossyd->idct_start_pass) (cinfo);
|
|
(*lossyd->coef_start_output_pass) (cinfo);
|
|
}
|
|
|
|
/*
|
|
* Initialize the lossy decompression codec.
|
|
* This is called only once, during master selection.
|
|
*/
|
|
|
|
GLOBAL(void)
|
|
jinit_lossy_d_codec (j_decompress_ptr cinfo)
|
|
{
|
|
j_lossy_d_ptr lossyd;
|
|
boolean use_c_buffer;
|
|
|
|
/* Create subobject in permanent pool */
|
|
lossyd = (j_lossy_d_ptr)
|
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
|
SIZEOF(jpeg_lossy_d_codec));
|
|
cinfo->codec = (struct jpeg_d_codec *) lossyd;
|
|
|
|
/* Initialize sub-modules */
|
|
|
|
/* Inverse DCT */
|
|
jinit_inverse_dct(cinfo);
|
|
/* Entropy decoding: either Huffman or arithmetic coding. */
|
|
if (cinfo->arith_code) {
|
|
ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
|
|
} else {
|
|
if (cinfo->process == JPROC_PROGRESSIVE) {
|
|
#ifdef D_PROGRESSIVE_SUPPORTED
|
|
jinit_phuff_decoder(cinfo);
|
|
#else
|
|
ERREXIT(cinfo, JERR_NOT_COMPILED);
|
|
#endif
|
|
} else
|
|
jinit_shuff_decoder(cinfo);
|
|
}
|
|
|
|
use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image;
|
|
jinit_d_coef_controller(cinfo, use_c_buffer);
|
|
|
|
/* Initialize method pointers.
|
|
*
|
|
* Note: consume_data and decompress_data are assigned in jdcoefct.c.
|
|
*/
|
|
lossyd->pub.calc_output_dimensions = calc_output_dimensions;
|
|
lossyd->pub.start_input_pass = start_input_pass;
|
|
lossyd->pub.start_output_pass = start_output_pass;
|
|
}
|
|
|
|
|
|
|
|
|