📄 transupp.c
字号:
* *strptr is advanced over the digit string, and *result is set to its value.
*/
LOCAL(boolean)
jt_read_integer (const char ** strptr, JDIMENSION * result)
{
const char * ptr = *strptr;
JDIMENSION val = 0;
for (; isdigit(*ptr); ptr++) {
val = val * 10 + (JDIMENSION) (*ptr - '0');
}
*result = val;
if (ptr == *strptr)
return FALSE; /* oops, no digits */
*strptr = ptr;
return TRUE;
}
/* Parse a crop specification (written in X11 geometry style).
* The routine returns TRUE if the spec string is valid, FALSE if not.
*
* The crop spec string should have the format
* <width>x<height>{+-}<xoffset>{+-}<yoffset>
* where width, height, xoffset, and yoffset are unsigned integers.
* Each of the elements can be omitted to indicate a default value.
* (A weakness of this style is that it is not possible to omit xoffset
* while specifying yoffset, since they look alike.)
*
* This code is loosely based on XParseGeometry from the X11 distribution.
*/
GLOBAL(boolean)
jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec)
{
info->crop = FALSE;
info->crop_width_set = JCROP_UNSET;
info->crop_height_set = JCROP_UNSET;
info->crop_xoffset_set = JCROP_UNSET;
info->crop_yoffset_set = JCROP_UNSET;
if (isdigit(*spec)) {
/* fetch width */
if (! jt_read_integer(&spec, &info->crop_width))
return FALSE;
info->crop_width_set = JCROP_POS;
}
if (*spec == 'x' || *spec == 'X') {
/* fetch height */
spec++;
if (! jt_read_integer(&spec, &info->crop_height))
return FALSE;
info->crop_height_set = JCROP_POS;
}
if (*spec == '+' || *spec == '-') {
/* fetch xoffset */
info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
spec++;
if (! jt_read_integer(&spec, &info->crop_xoffset))
return FALSE;
}
if (*spec == '+' || *spec == '-') {
/* fetch yoffset */
info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
spec++;
if (! jt_read_integer(&spec, &info->crop_yoffset))
return FALSE;
}
/* We had better have gotten to the end of the string. */
if (*spec != '\0')
return FALSE;
info->crop = TRUE;
return TRUE;
}
/* Trim off any partial iMCUs on the indicated destination edge */
LOCAL(void)
trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width)
{
JDIMENSION MCU_cols;
MCU_cols = info->output_width / (info->max_h_samp_factor * DCTSIZE);
if (MCU_cols > 0 && info->x_crop_offset + MCU_cols ==
full_width / (info->max_h_samp_factor * DCTSIZE))
info->output_width = MCU_cols * (info->max_h_samp_factor * DCTSIZE);
}
LOCAL(void)
trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height)
{
JDIMENSION MCU_rows;
MCU_rows = info->output_height / (info->max_v_samp_factor * DCTSIZE);
if (MCU_rows > 0 && info->y_crop_offset + MCU_rows ==
full_height / (info->max_v_samp_factor * DCTSIZE))
info->output_height = MCU_rows * (info->max_v_samp_factor * DCTSIZE);
}
/* Request any required workspace.
*
* This routine figures out the size that the output image will be
* (which implies that all the transform parameters must be set before
* it is called).
*
* We allocate the workspace virtual arrays from the source decompression
* object, so that all the arrays (both the original data and the workspace)
* will be taken into account while making memory management decisions.
* Hence, this routine must be called after jpeg_read_header (which reads
* the image dimensions) and before jpeg_read_coefficients (which realizes
* the source's virtual arrays).
*/
GLOBAL(void)
jtransform_request_workspace (j_decompress_ptr srcinfo,
jpeg_transform_info *info)
{
jvirt_barray_ptr *coef_arrays = NULL;
boolean need_workspace, transpose_it;
jpeg_component_info *compptr;
JDIMENSION xoffset, yoffset, width_in_iMCUs, height_in_iMCUs;
JDIMENSION width_in_blocks, height_in_blocks;
int ci, h_samp_factor, v_samp_factor;
/* Determine number of components in output image */
if (info->force_grayscale &&
srcinfo->jpeg_color_space == JCS_YCbCr &&
srcinfo->num_components == 3) {
/* We'll only process the first component */
info->num_components = 1;
} else {
/* Process all the components */
info->num_components = srcinfo->num_components;
}
/* If there is only one output component, force the iMCU size to be 1;
* else use the source iMCU size. (This allows us to do the right thing
* when reducing color to grayscale, and also provides a handy way of
* cleaning up "funny" grayscale images whose sampling factors are not 1x1.)
*/
switch (info->transform) {
case JXFORM_TRANSPOSE:
case JXFORM_TRANSVERSE:
case JXFORM_ROT_90:
case JXFORM_ROT_270:
info->output_width = srcinfo->image_height;
info->output_height = srcinfo->image_width;
if (info->num_components == 1) {
info->max_h_samp_factor = 1;
info->max_v_samp_factor = 1;
} else {
info->max_h_samp_factor = srcinfo->max_v_samp_factor;
info->max_v_samp_factor = srcinfo->max_h_samp_factor;
}
break;
default:
info->output_width = srcinfo->image_width;
info->output_height = srcinfo->image_height;
if (info->num_components == 1) {
info->max_h_samp_factor = 1;
info->max_v_samp_factor = 1;
} else {
info->max_h_samp_factor = srcinfo->max_h_samp_factor;
info->max_v_samp_factor = srcinfo->max_v_samp_factor;
}
break;
}
/* If cropping has been requested, compute the crop area's position and
* dimensions, ensuring that its upper left corner falls at an iMCU boundary.
*/
if (info->crop) {
/* Insert default values for unset crop parameters */
if (info->crop_xoffset_set == JCROP_UNSET)
info->crop_xoffset = 0; /* default to +0 */
if (info->crop_yoffset_set == JCROP_UNSET)
info->crop_yoffset = 0; /* default to +0 */
if (info->crop_xoffset >= info->output_width ||
info->crop_yoffset >= info->output_height)
ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
if (info->crop_width_set == JCROP_UNSET)
info->crop_width = info->output_width - info->crop_xoffset;
if (info->crop_height_set == JCROP_UNSET)
info->crop_height = info->output_height - info->crop_yoffset;
/* Ensure parameters are valid */
if (info->crop_width <= 0 || info->crop_width > info->output_width ||
info->crop_height <= 0 || info->crop_height > info->output_height ||
info->crop_xoffset > info->output_width - info->crop_width ||
info->crop_yoffset > info->output_height - info->crop_height)
ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
/* Convert negative crop offsets into regular offsets */
if (info->crop_xoffset_set == JCROP_NEG)
xoffset = info->output_width - info->crop_width - info->crop_xoffset;
else
xoffset = info->crop_xoffset;
if (info->crop_yoffset_set == JCROP_NEG)
yoffset = info->output_height - info->crop_height - info->crop_yoffset;
else
yoffset = info->crop_yoffset;
/* Now adjust so that upper left corner falls at an iMCU boundary */
info->output_width =
info->crop_width + (xoffset % (info->max_h_samp_factor * DCTSIZE));
info->output_height =
info->crop_height + (yoffset % (info->max_v_samp_factor * DCTSIZE));
/* Save x/y offsets measured in iMCUs */
info->x_crop_offset = xoffset / (info->max_h_samp_factor * DCTSIZE);
info->y_crop_offset = yoffset / (info->max_v_samp_factor * DCTSIZE);
} else {
info->x_crop_offset = 0;
info->y_crop_offset = 0;
}
/* Figure out whether we need workspace arrays,
* and if so whether they are transposed relative to the source.
*/
need_workspace = FALSE;
transpose_it = FALSE;
switch (info->transform) {
case JXFORM_NONE:
if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
need_workspace = TRUE;
/* No workspace needed if neither cropping nor transforming */
break;
case JXFORM_FLIP_H:
if (info->trim)
trim_right_edge(info, srcinfo->image_width);
if (info->y_crop_offset != 0)
need_workspace = TRUE;
/* do_flip_h_no_crop doesn't need a workspace array */
break;
case JXFORM_FLIP_V:
if (info->trim)
trim_bottom_edge(info, srcinfo->image_height);
/* Need workspace arrays having same dimensions as source image. */
need_workspace = TRUE;
break;
case JXFORM_TRANSPOSE:
/* transpose does NOT have to trim anything */
/* Need workspace arrays having transposed dimensions. */
need_workspace = TRUE;
transpose_it = TRUE;
break;
case JXFORM_TRANSVERSE:
if (info->trim) {
trim_right_edge(info, srcinfo->image_height);
trim_bottom_edge(info, srcinfo->image_width);
}
/* Need workspace arrays having transposed dimensions. */
need_workspace = TRUE;
transpose_it = TRUE;
break;
case JXFORM_ROT_90:
if (info->trim)
trim_right_edge(info, srcinfo->image_height);
/* Need workspace arrays having transposed dimensions. */
need_workspace = TRUE;
transpose_it = TRUE;
break;
case JXFORM_ROT_180:
if (info->trim) {
trim_right_edge(info, srcinfo->image_width);
trim_bottom_edge(info, srcinfo->image_height);
}
/* Need workspace arrays having same dimensions as source image. */
need_workspace = TRUE;
break;
case JXFORM_ROT_270:
if (info->trim)
trim_bottom_edge(info, srcinfo->image_width);
/* Need workspace arrays having transposed dimensions. */
need_workspace = TRUE;
transpose_it = TRUE;
break;
}
/* Allocate workspace if needed.
* Note that we allocate arrays padded out to the next iMCU boundary,
* so that transform routines need not worry about missing edge blocks.
*/
if (need_workspace) {
coef_arrays = (jvirt_barray_ptr *)
(*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
SIZEOF(jvirt_barray_ptr) * info->num_components);
width_in_iMCUs = (JDIMENSION)
jdiv_round_up((long) info->output_width,
(long) (info->max_h_samp_factor * DCTSIZE));
height_in_iMCUs = (JDIMENSION)
jdiv_round_up((long) info->output_height,
(long) (info->max_v_samp_factor * DCTSIZE));
for (ci = 0; ci < info->num_components; ci++) {
compptr = srcinfo->comp_info + ci;
if (info->num_components == 1) {
/* we're going to force samp factors to 1x1 in this case */
h_samp_factor = v_samp_factor = 1;
} else if (transpose_it) {
h_samp_factor = compptr->v_samp_factor;
v_samp_factor = compptr->h_samp_factor;
} else {
h_samp_factor = compptr->h_samp_factor;
v_samp_factor = compptr->v_samp_factor;
}
width_in_blocks = width_in_iMCUs * h_samp_factor;
height_in_blocks = height_in_iMCUs * v_samp_factor;
coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor);
}
}
info->workspace_coef_arrays = coef_arrays;
}
/* Transpose destination image parameters */
LOCAL(void)
transpose_critical_parameters (j_compress_ptr dstinfo)
{
int tblno, i, j, ci, itemp;
jpeg_component_info *compptr;
JQUANT_TBL *qtblptr;
UINT16 qtemp;
/* Transpose sampling factors */
for (ci = 0; ci < dstinfo->num_components; ci++) {
compptr = dstinfo->comp_info + ci;
itemp = compptr->h_samp_factor;
compptr->h_samp_factor = compptr->v_samp_factor;
compptr->v_samp_factor = itemp;
}
/* Transpose quantization tables */
for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
qtblptr = dstinfo->quant_tbl_ptrs[tblno];
if (qtblptr != NULL) {
for (i = 0; i < DCTSIZE; i++) {
for (j = 0; j < i; j++) {
qtemp = qtblptr->quantval[i*DCTSIZE+j];
qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i];
qtblptr->quantval[j*DCTSIZE+i] = qtemp;
}
}
}
}
}
/* Adjust Exif image parameters.
*
* We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.
*/
LOCAL(void)
adjust_exif_parameters (JOCTET FAR * data, unsigned int length,
JDIMENSION new_width, JDIMENSION new_height)
{
boolean is_motorola; /* Flag for byte order */
unsigned int number_of_tags, tagnum;
unsigned int firstoffset, offset;
JDIMENSION new_value;
if (length < 12) return; /* Length of an IFD entry */
/* Discover byte order */
if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49)
is_motorola = FALSE;
else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -