/* * transupp.c * * This file was part of the Independent JPEG Group's software: * Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding. * libjpeg-turbo Modifications: * Copyright (C) 2010, 2017, 2021-2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * * This file contains image transformation routines and other utility code * used by the jpegtran sample application. These are NOT part of the core * JPEG library. But we keep these routines separate from jpegtran.c to * ease the task of maintaining jpegtran-like programs that have other user * interfaces. */ /* Although this file really shouldn't have access to the library internals, * it's helpful to let it call jround_up() and jcopy_block_row(). */ #define JPEG_INTERNALS #include "jinclude.h" #include "jpeglib.h" #include "transupp.h" /* My own external interface */ #include "jpegcomp.h" #include <ctype.h> /* to declare isdigit() */ #if JPEG_LIB_VERSION >= 70 #define dstinfo_min_DCT_h_scaled_size … #define dstinfo_min_DCT_v_scaled_size … #else #define dstinfo_min_DCT_h_scaled_size … #define dstinfo_min_DCT_v_scaled_size … #endif #if TRANSFORMS_SUPPORTED /* * Lossless image transformation routines. These routines work on DCT * coefficient arrays and thus do not require any lossy decompression * or recompression of the image. * Thanks to Guido Vollbeding for the initial design and code of this feature, * and to Ben Jackson for introducing the cropping feature. * * Horizontal flipping is done in-place, using a single top-to-bottom * pass through the virtual source array. It will thus be much the * fastest option for images larger than main memory. * * The other routines require a set of destination virtual arrays, so they * need twice as much memory as jpegtran normally does. The destination * arrays are always written in normal scan order (top to bottom) because * the virtual array manager expects this. The source arrays will be scanned * in the corresponding order, which means multiple passes through the source * arrays for most of the transforms. That could result in much thrashing * if the image is larger than main memory. * * If cropping or trimming is involved, the destination arrays may be smaller * than the source arrays. Note it is not possible to do horizontal flip * in-place when a nonzero Y crop offset is specified, since we'd have to move * data from one block row to another but the virtual array manager doesn't * guarantee we can touch more than one row at a time. So in that case, * we have to use a separate destination array. * * Some notes about the operating environment of the individual transform * routines: * 1. Both the source and destination virtual arrays are allocated from the * source JPEG object, and therefore should be manipulated by calling the * source's memory manager. * 2. The destination's component count should be used. It may be smaller * than the source's when forcing to grayscale. * 3. Likewise the destination's sampling factors should be used. When * forcing to grayscale the destination's sampling factors will be all 1, * and we may as well take that as the effective iMCU size. * 4. When "trim" is in effect, the destination's dimensions will be the * trimmed values but the source's will be untrimmed. * 5. When "crop" is in effect, the destination's dimensions will be the * cropped values but the source's will be uncropped. Each transform * routine is responsible for picking up source data starting at the * correct X and Y offset for the crop region. (The X and Y offsets * passed to the transform routines are measured in iMCU blocks of the * destination.) * 6. All the routines assume that the source and destination buffers are * padded out to a full iMCU boundary. This is true, although for the * source buffer it is an undocumented property of jdcoefct.c. */ LOCAL(void) dequant_comp(j_decompress_ptr cinfo, jpeg_component_info *compptr, jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1) { … } LOCAL(void) requant_comp(j_decompress_ptr cinfo, jpeg_component_info *compptr, jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1) { … } /* * Calculate largest common denominator using Euclid's algorithm. */ LOCAL(JCOEF) largest_common_denominator(JCOEF a, JCOEF b) { … } LOCAL(void) adjust_quant(j_decompress_ptr srcinfo, jvirt_barray_ptr *src_coef_arrays, j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays, boolean trim, j_compress_ptr dstinfo) { … } LOCAL(void) do_drop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays, JDIMENSION drop_width, JDIMENSION drop_height) /* Drop (insert) the contents of another image into the source image. If the * number of components in the drop image is smaller than the number of * components in the destination image, then we fill in the remaining * components with zero. This allows for dropping the contents of grayscale * images into (arbitrarily sampled) color images. */ { … } LOCAL(void) do_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Crop. This is only used when no rotate/flip is requested with the crop. */ { … } LOCAL(void) do_crop_ext_zero(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Crop. This is only used when no rotate/flip is requested with the crop. * Extension: If the destination size is larger than the source, we fill in the * expanded region with zero (neutral gray). Note that we also have to zero * partial iMCUs at the right and bottom edge of the source image area in this * case. */ { … } LOCAL(void) do_crop_ext_flat(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Crop. This is only used when no rotate/flip is requested with the crop. * Extension: The destination width is larger than the source, and we fill in * the expanded region with the DC coefficient of the adjacent block. Note * that we also have to fill partial iMCUs at the right and bottom edge of the * source image area in this case. */ { … } LOCAL(void) do_crop_ext_reflect(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Crop. This is only used when no rotate/flip is requested with the crop. * Extension: The destination width is larger than the source, and we fill in * the expanded region with repeated reflections of the source image. Note * that we also have to fill partial iMCUs at the right and bottom edge of the * source image area in this case. */ { … } LOCAL(void) do_wipe(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, JDIMENSION drop_width, JDIMENSION drop_height) /* Wipe - discard image contents of specified region and fill with zero * (neutral gray) */ { … } LOCAL(void) do_flatten(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, JDIMENSION drop_width, JDIMENSION drop_height) /* Flatten - discard image contents of specified region, similarly to wipe, * but fill with the average of adjacent blocks instead of zero. */ { … } LOCAL(void) do_reflect(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays, JDIMENSION drop_width, JDIMENSION drop_height) /* Reflect - discard image contents of specified region, similarly to wipe, * but fill with repeated reflections of the outside region instead of zero. * NB: y_crop_offset is assumed to be zero. */ { … } LOCAL(void) do_flip_h_no_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays) /* Horizontal flip; done in-place, so no separate dest array is required. * NB: this only works when y_crop_offset is zero. */ { … } LOCAL(void) do_flip_h(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Horizontal flip in general cropping case */ { … } LOCAL(void) do_flip_v(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Vertical flip */ { … } LOCAL(void) do_transpose(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Transpose source into destination */ { … } LOCAL(void) do_rot_90(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 90 degree rotation is equivalent to * 1. Transposing the image; * 2. Horizontal mirroring. * These two steps are merged into a single processing routine. */ { … } LOCAL(void) do_rot_270(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 270 degree rotation is equivalent to * 1. Horizontal mirroring; * 2. Transposing the image. * These two steps are merged into a single processing routine. */ { … } LOCAL(void) do_rot_180(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 180 degree rotation is equivalent to * 1. Vertical mirroring; * 2. Horizontal mirroring. * These two steps are merged into a single processing routine. */ { … } LOCAL(void) do_transverse(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Transverse transpose is equivalent to * 1. 180 degree rotation; * 2. Transposition; * or * 1. Horizontal mirroring; * 2. Transposition; * 3. Horizontal mirroring. * These steps are merged into a single processing routine. */ { … } /* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec. * Returns TRUE if valid integer found, FALSE if not. * *strptr is advanced over the digit string, and *result is set to its value. */ LOCAL(boolean) jt_read_integer(const char **strptr, JDIMENSION *result) { … } /* 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>[{fr}]x<height>[{fr}]{+-}<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) { … } /* Trim off any partial iMCUs on the indicated destination edge */ LOCAL(void) trim_right_edge(jpeg_transform_info *info, JDIMENSION full_width) { … } LOCAL(void) trim_bottom_edge(jpeg_transform_info *info, JDIMENSION full_height) { … } /* 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). * * This function returns FALSE right away if -perfect is given * and transformation is not perfect. Otherwise returns TRUE. */ GLOBAL(boolean) jtransform_request_workspace(j_decompress_ptr srcinfo, jpeg_transform_info *info) { … } /* Transpose destination image parameters */ LOCAL(void) transpose_critical_parameters(j_compress_ptr dstinfo) { … } /* Adjust Exif image parameters. * * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. */ LOCAL(void) adjust_exif_parameters(JOCTET *data, unsigned int length, JDIMENSION new_width, JDIMENSION new_height) { … } /* Adjust output image parameters as needed. * * This must be called after jpeg_copy_critical_parameters() * and before jpeg_write_coefficients(). * * The return value is the set of virtual coefficient arrays to be written * (either the ones allocated by jtransform_request_workspace, or the * original source data arrays). The caller will need to pass this value * to jpeg_write_coefficients(). */ GLOBAL(jvirt_barray_ptr *) jtransform_adjust_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info) { … } /* Execute the actual transformation, if any. * * This must be called *after* jpeg_write_coefficients, because it depends * on jpeg_write_coefficients to have computed subsidiary values such as * the per-component width and height fields in the destination object. * * Note that some transformations will modify the source data arrays! */ GLOBAL(void) jtransform_execute_transform(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info) { … } /* jtransform_perfect_transform * * Determine whether lossless transformation is perfectly * possible for a specified image and transformation. * * Inputs: * image_width, image_height: source image dimensions. * MCU_width, MCU_height: pixel dimensions of MCU. * transform: transformation identifier. * Parameter sources from initialized jpeg_struct * (after reading source header): * image_width = cinfo.image_width * image_height = cinfo.image_height * MCU_width = cinfo.max_h_samp_factor * cinfo.block_size * MCU_height = cinfo.max_v_samp_factor * cinfo.block_size * Result: * TRUE = perfect transformation possible * FALSE = perfect transformation not possible * (may use custom action then) */ GLOBAL(boolean) jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height, int MCU_width, int MCU_height, JXFORM_CODE transform) { … } #endif /* TRANSFORMS_SUPPORTED */ /* Setup decompression object to save desired markers in memory. * This must be called before jpeg_read_header() to have the desired effect. */ GLOBAL(void) jcopy_markers_setup(j_decompress_ptr srcinfo, JCOPY_OPTION option) { … } /* Copy markers saved in the given source object to the destination object. * This should be called just after jpeg_start_compress() or * jpeg_write_coefficients(). * Note that those routines will have written the SOI, and also the * JFIF APP0 or Adobe APP14 markers if selected. */ GLOBAL(void) jcopy_markers_execute(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JCOPY_OPTION option) { … }