Path: blob/master/thirdparty/libjpeg-turbo/src/jcprepct.c
9904 views
/*1* jcprepct.c2*3* This file was part of the Independent JPEG Group's software:4* Copyright (C) 1994-1996, Thomas G. Lane.5* Lossless JPEG Modifications:6* Copyright (C) 1999, Ken Murchison.7* libjpeg-turbo Modifications:8* Copyright (C) 2022, 2024, D. R. Commander.9* For conditions of distribution and use, see the accompanying README.ijg10* file.11*12* This file contains the compression preprocessing controller.13* This controller manages the color conversion, downsampling,14* and edge expansion steps.15*16* Most of the complexity here is associated with buffering input rows17* as required by the downsampler. See the comments at the head of18* jcsample.c for the downsampler's needs.19*/2021#define JPEG_INTERNALS22#include "jinclude.h"23#include "jpeglib.h"24#include "jsamplecomp.h"252627#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)2829/* At present, jcsample.c can request context rows only for smoothing.30* In the future, we might also need context rows for CCIR601 sampling31* or other more-complex downsampling procedures. The code to support32* context rows should be compiled only if needed.33*/34#ifdef INPUT_SMOOTHING_SUPPORTED35#define CONTEXT_ROWS_SUPPORTED36#endif373839/*40* For the simple (no-context-row) case, we just need to buffer one41* row group's worth of pixels for the downsampling step. At the bottom of42* the image, we pad to a full row group by replicating the last pixel row.43* The downsampler's last output row is then replicated if needed to pad44* out to a full iMCU row.45*46* When providing context rows, we must buffer three row groups' worth of47* pixels. Three row groups are physically allocated, but the row pointer48* arrays are made five row groups high, with the extra pointers above and49* below "wrapping around" to point to the last and first real row groups.50* This allows the downsampler to access the proper context rows.51* At the top and bottom of the image, we create dummy context rows by52* copying the first or last real pixel row. This copying could be avoided53* by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the54* trouble on the compression side.55*/565758/* Private buffer controller object */5960typedef struct {61struct jpeg_c_prep_controller pub; /* public fields */6263/* Downsampling input buffer. This buffer holds color-converted data64* until we have enough to do a downsample step.65*/66_JSAMPARRAY color_buf[MAX_COMPONENTS];6768JDIMENSION rows_to_go; /* counts rows remaining in source image */69int next_buf_row; /* index of next row to store in color_buf */7071#ifdef CONTEXT_ROWS_SUPPORTED /* only needed for context case */72int this_row_group; /* starting row index of group to process */73int next_buf_stop; /* downsample when we reach this index */74#endif75} my_prep_controller;7677typedef my_prep_controller *my_prep_ptr;787980/*81* Initialize for a processing pass.82*/8384METHODDEF(void)85start_pass_prep(j_compress_ptr cinfo, J_BUF_MODE pass_mode)86{87my_prep_ptr prep = (my_prep_ptr)cinfo->prep;8889if (pass_mode != JBUF_PASS_THRU)90ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);9192/* Initialize total-height counter for detecting bottom of image */93prep->rows_to_go = cinfo->image_height;94/* Mark the conversion buffer empty */95prep->next_buf_row = 0;96#ifdef CONTEXT_ROWS_SUPPORTED97/* Preset additional state variables for context mode.98* These aren't used in non-context mode, so we needn't test which mode.99*/100prep->this_row_group = 0;101/* Set next_buf_stop to stop after two row groups have been read in. */102prep->next_buf_stop = 2 * cinfo->max_v_samp_factor;103#endif104}105106107/*108* Expand an image vertically from height input_rows to height output_rows,109* by duplicating the bottom row.110*/111112LOCAL(void)113expand_bottom_edge(_JSAMPARRAY image_data, JDIMENSION num_cols, int input_rows,114int output_rows)115{116register int row;117118for (row = input_rows; row < output_rows; row++) {119_jcopy_sample_rows(image_data, input_rows - 1, image_data, row, 1,120num_cols);121}122}123124125/*126* Process some data in the simple no-context case.127*128* Preprocessor output data is counted in "row groups". A row group129* is defined to be v_samp_factor sample rows of each component.130* Downsampling will produce this much data from each max_v_samp_factor131* input rows.132*/133134METHODDEF(void)135pre_process_data(j_compress_ptr cinfo, _JSAMPARRAY input_buf,136JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail,137_JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,138JDIMENSION out_row_groups_avail)139{140my_prep_ptr prep = (my_prep_ptr)cinfo->prep;141int numrows, ci;142JDIMENSION inrows;143jpeg_component_info *compptr;144int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;145146while (*in_row_ctr < in_rows_avail &&147*out_row_group_ctr < out_row_groups_avail) {148/* Do color conversion to fill the conversion buffer. */149inrows = in_rows_avail - *in_row_ctr;150numrows = cinfo->max_v_samp_factor - prep->next_buf_row;151numrows = (int)MIN((JDIMENSION)numrows, inrows);152(*cinfo->cconvert->_color_convert) (cinfo, input_buf + *in_row_ctr,153prep->color_buf,154(JDIMENSION)prep->next_buf_row,155numrows);156*in_row_ctr += numrows;157prep->next_buf_row += numrows;158prep->rows_to_go -= numrows;159/* If at bottom of image, pad to fill the conversion buffer. */160if (prep->rows_to_go == 0 &&161prep->next_buf_row < cinfo->max_v_samp_factor) {162for (ci = 0; ci < cinfo->num_components; ci++) {163expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,164prep->next_buf_row, cinfo->max_v_samp_factor);165}166prep->next_buf_row = cinfo->max_v_samp_factor;167}168/* If we've filled the conversion buffer, empty it. */169if (prep->next_buf_row == cinfo->max_v_samp_factor) {170(*cinfo->downsample->_downsample) (cinfo,171prep->color_buf, (JDIMENSION)0,172output_buf, *out_row_group_ctr);173prep->next_buf_row = 0;174(*out_row_group_ctr)++;175}176/* If at bottom of image, pad the output to a full iMCU height.177* Note we assume the caller is providing a one-iMCU-height output buffer!178*/179if (prep->rows_to_go == 0 && *out_row_group_ctr < out_row_groups_avail) {180for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;181ci++, compptr++) {182expand_bottom_edge(output_buf[ci],183compptr->width_in_blocks * data_unit,184(int)(*out_row_group_ctr * compptr->v_samp_factor),185(int)(out_row_groups_avail * compptr->v_samp_factor));186}187*out_row_group_ctr = out_row_groups_avail;188break; /* can exit outer loop without test */189}190}191}192193194#ifdef CONTEXT_ROWS_SUPPORTED195196/*197* Process some data in the context case.198*/199200METHODDEF(void)201pre_process_context(j_compress_ptr cinfo, _JSAMPARRAY input_buf,202JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail,203_JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,204JDIMENSION out_row_groups_avail)205{206my_prep_ptr prep = (my_prep_ptr)cinfo->prep;207int numrows, ci;208int buf_height = cinfo->max_v_samp_factor * 3;209JDIMENSION inrows;210211while (*out_row_group_ctr < out_row_groups_avail) {212if (*in_row_ctr < in_rows_avail) {213/* Do color conversion to fill the conversion buffer. */214inrows = in_rows_avail - *in_row_ctr;215numrows = prep->next_buf_stop - prep->next_buf_row;216numrows = (int)MIN((JDIMENSION)numrows, inrows);217(*cinfo->cconvert->_color_convert) (cinfo, input_buf + *in_row_ctr,218prep->color_buf,219(JDIMENSION)prep->next_buf_row,220numrows);221/* Pad at top of image, if first time through */222if (prep->rows_to_go == cinfo->image_height) {223for (ci = 0; ci < cinfo->num_components; ci++) {224int row;225for (row = 1; row <= cinfo->max_v_samp_factor; row++) {226_jcopy_sample_rows(prep->color_buf[ci], 0, prep->color_buf[ci],227-row, 1, cinfo->image_width);228}229}230}231*in_row_ctr += numrows;232prep->next_buf_row += numrows;233prep->rows_to_go -= numrows;234} else {235/* Return for more data, unless we are at the bottom of the image. */236if (prep->rows_to_go != 0)237break;238/* When at bottom of image, pad to fill the conversion buffer. */239if (prep->next_buf_row < prep->next_buf_stop) {240for (ci = 0; ci < cinfo->num_components; ci++) {241expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,242prep->next_buf_row, prep->next_buf_stop);243}244prep->next_buf_row = prep->next_buf_stop;245}246}247/* If we've gotten enough data, downsample a row group. */248if (prep->next_buf_row == prep->next_buf_stop) {249(*cinfo->downsample->_downsample) (cinfo, prep->color_buf,250(JDIMENSION)prep->this_row_group,251output_buf, *out_row_group_ctr);252(*out_row_group_ctr)++;253/* Advance pointers with wraparound as necessary. */254prep->this_row_group += cinfo->max_v_samp_factor;255if (prep->this_row_group >= buf_height)256prep->this_row_group = 0;257if (prep->next_buf_row >= buf_height)258prep->next_buf_row = 0;259prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor;260}261}262}263264265/*266* Create the wrapped-around downsampling input buffer needed for context mode.267*/268269LOCAL(void)270create_context_buffer(j_compress_ptr cinfo)271{272my_prep_ptr prep = (my_prep_ptr)cinfo->prep;273int rgroup_height = cinfo->max_v_samp_factor;274int ci, i;275jpeg_component_info *compptr;276_JSAMPARRAY true_buffer, fake_buffer;277int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;278279/* Grab enough space for fake row pointers for all the components;280* we need five row groups' worth of pointers for each component.281*/282fake_buffer = (_JSAMPARRAY)283(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,284(cinfo->num_components * 5 * rgroup_height) *285sizeof(_JSAMPROW));286287for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;288ci++, compptr++) {289/* Allocate the actual buffer space (3 row groups) for this component.290* We make the buffer wide enough to allow the downsampler to edge-expand291* horizontally within the buffer, if it so chooses.292*/293true_buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)294((j_common_ptr)cinfo, JPOOL_IMAGE,295(JDIMENSION)(((long)compptr->width_in_blocks * data_unit *296cinfo->max_h_samp_factor) / compptr->h_samp_factor),297(JDIMENSION)(3 * rgroup_height));298/* Copy true buffer row pointers into the middle of the fake row array */299memcpy(fake_buffer + rgroup_height, true_buffer,3003 * rgroup_height * sizeof(_JSAMPROW));301/* Fill in the above and below wraparound pointers */302for (i = 0; i < rgroup_height; i++) {303fake_buffer[i] = true_buffer[2 * rgroup_height + i];304fake_buffer[4 * rgroup_height + i] = true_buffer[i];305}306prep->color_buf[ci] = fake_buffer + rgroup_height;307fake_buffer += 5 * rgroup_height; /* point to space for next component */308}309}310311#endif /* CONTEXT_ROWS_SUPPORTED */312313314/*315* Initialize preprocessing controller.316*/317318GLOBAL(void)319_jinit_c_prep_controller(j_compress_ptr cinfo, boolean need_full_buffer)320{321my_prep_ptr prep;322int ci;323jpeg_component_info *compptr;324int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;325326#ifdef C_LOSSLESS_SUPPORTED327if (cinfo->master->lossless) {328#if BITS_IN_JSAMPLE == 8329if (cinfo->data_precision > BITS_IN_JSAMPLE || cinfo->data_precision < 2)330#else331if (cinfo->data_precision > BITS_IN_JSAMPLE ||332cinfo->data_precision < BITS_IN_JSAMPLE - 3)333#endif334ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);335} else336#endif337{338if (cinfo->data_precision != BITS_IN_JSAMPLE)339ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);340}341342if (need_full_buffer) /* safety check */343ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);344345prep = (my_prep_ptr)346(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,347sizeof(my_prep_controller));348cinfo->prep = (struct jpeg_c_prep_controller *)prep;349prep->pub.start_pass = start_pass_prep;350351/* Allocate the color conversion buffer.352* We make the buffer wide enough to allow the downsampler to edge-expand353* horizontally within the buffer, if it so chooses.354*/355if (cinfo->downsample->need_context_rows) {356/* Set up to provide context rows */357#ifdef CONTEXT_ROWS_SUPPORTED358prep->pub._pre_process_data = pre_process_context;359create_context_buffer(cinfo);360#else361ERREXIT(cinfo, JERR_NOT_COMPILED);362#endif363} else {364/* No context, just make it tall enough for one row group */365prep->pub._pre_process_data = pre_process_data;366for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;367ci++, compptr++) {368prep->color_buf[ci] = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)369((j_common_ptr)cinfo, JPOOL_IMAGE,370(JDIMENSION)(((long)compptr->width_in_blocks * data_unit *371cinfo->max_h_samp_factor) / compptr->h_samp_factor),372(JDIMENSION)cinfo->max_v_samp_factor);373}374}375}376377#endif /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */378379380