summaryrefslogtreecommitdiff
path: root/transupp.c
diff options
context:
space:
mode:
authorJonathan Wright <jonathan.wright@arm.com>2020-11-25 13:36:43 +0000
committerJonathan Wright <jonathan.wright@arm.com>2020-11-30 12:08:32 +0000
commitbbb828223e9c8f83f0e84db1e98b116029e62765 (patch)
treed2467975e2bf1442216d2c779054102ee37f599c /transupp.c
parentd5148db386ceb4a608058320071cbed890bd6ad2 (diff)
Update libjpeg-turbo to v2.0.90 (2.1 beta1)
Update Chromium's copy of libjpeg-turbo to the latest upstream release (v2.0.90) and re-apply our local changes documented in README.chromium. Cherry-pick two additional changes from upstream to fix bugs found by fuzzers: 1) https://github.com/libjpeg-turbo/libjpeg-turbo/commit/ccaba5d7894ecfb5a8f11e48d3f86e1f14d5a469 2) https://github.com/libjpeg-turbo/libjpeg-turbo/commit/c7ca521bc85b57d41d3ad4963c13fc0100481084 Significant changes provided by this update: 1) A large performance boost to JPEG encoding due to an improved Huffman encoding implementation. 2) The complete removal of Arm Neon assembly code. This allows Arm's control-flow integrity security features (Armv8.3-A Pointer Authentication and Armv8.5-A Branch Target Identification) to be switched on with the appropriate compiler flags. Bug: 922430 Bug: b/135180511 Bug: 919548, 1145581 Change-Id: I319fcdc55b3fd5b219425c07a4e4a03587f4e06d
Diffstat (limited to 'transupp.c')
-rw-r--r--transupp.c943
1 files changed, 841 insertions, 102 deletions
diff --git a/transupp.c b/transupp.c
index f3370ac..6e86077 100644
--- a/transupp.c
+++ b/transupp.c
@@ -2,7 +2,7 @@
* transupp.c
*
* This file was part of the Independent JPEG Group's software:
- * Copyright (C) 1997-2011, Thomas G. Lane, Guido Vollbeding.
+ * Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright (C) 2010, 2017, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
@@ -89,6 +89,189 @@
LOCAL(void)
+dequant_comp(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1)
+{
+ JDIMENSION blk_x, blk_y;
+ int offset_y, k;
+ JQUANT_TBL *qtblptr;
+ JBLOCKARRAY buffer;
+ JBLOCKROW block;
+ JCOEFPTR ptr;
+
+ qtblptr = compptr->quant_table;
+ for (blk_y = 0; blk_y < compptr->height_in_blocks;
+ blk_y += compptr->v_samp_factor) {
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr)cinfo, coef_array, blk_y,
+ (JDIMENSION)compptr->v_samp_factor, TRUE);
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ block = buffer[offset_y];
+ for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
+ ptr = block[blk_x];
+ for (k = 0; k < DCTSIZE2; k++)
+ if (qtblptr->quantval[k] != qtblptr1->quantval[k])
+ ptr[k] *= qtblptr->quantval[k] / qtblptr1->quantval[k];
+ }
+ }
+ }
+}
+
+
+LOCAL(void)
+requant_comp(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1)
+{
+ JDIMENSION blk_x, blk_y;
+ int offset_y, k;
+ JQUANT_TBL *qtblptr;
+ JBLOCKARRAY buffer;
+ JBLOCKROW block;
+ JCOEFPTR ptr;
+ JCOEF temp, qval;
+
+ qtblptr = compptr->quant_table;
+ for (blk_y = 0; blk_y < compptr->height_in_blocks;
+ blk_y += compptr->v_samp_factor) {
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr)cinfo, coef_array, blk_y,
+ (JDIMENSION)compptr->v_samp_factor, TRUE);
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ block = buffer[offset_y];
+ for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
+ ptr = block[blk_x];
+ for (k = 0; k < DCTSIZE2; k++) {
+ temp = qtblptr->quantval[k];
+ qval = qtblptr1->quantval[k];
+ if (temp != qval) {
+ temp *= ptr[k];
+ /* The following quantization code is copied from jcdctmgr.c */
+#ifdef FAST_DIVIDE
+#define DIVIDE_BY(a, b) a /= b
+#else
+#define DIVIDE_BY(a, b) if (a >= b) a /= b; else a = 0
+#endif
+ if (temp < 0) {
+ temp = -temp;
+ temp += qval >> 1; /* for rounding */
+ DIVIDE_BY(temp, qval);
+ temp = -temp;
+ } else {
+ temp += qval >> 1; /* for rounding */
+ DIVIDE_BY(temp, qval);
+ }
+ ptr[k] = temp;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * Calculate largest common denominator using Euclid's algorithm.
+ */
+LOCAL(JCOEF)
+largest_common_denominator(JCOEF a, JCOEF b)
+{
+ JCOEF c;
+
+ do {
+ c = a % b;
+ a = b;
+ b = c;
+ } while (c);
+
+ return a;
+}
+
+
+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)
+{
+ jpeg_component_info *compptr1, *compptr2;
+ JQUANT_TBL *qtblptr1, *qtblptr2, *qtblptr3;
+ int ci, k;
+
+ for (ci = 0; ci < dstinfo->num_components && ci < dropinfo->num_components;
+ ci++) {
+ compptr1 = srcinfo->comp_info + ci;
+ compptr2 = dropinfo->comp_info + ci;
+ qtblptr1 = compptr1->quant_table;
+ qtblptr2 = compptr2->quant_table;
+ for (k = 0; k < DCTSIZE2; k++) {
+ if (qtblptr1->quantval[k] != qtblptr2->quantval[k]) {
+ if (trim)
+ requant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr1);
+ else {
+ qtblptr3 = dstinfo->quant_tbl_ptrs[compptr1->quant_tbl_no];
+ for (k = 0; k < DCTSIZE2; k++)
+ if (qtblptr1->quantval[k] != qtblptr2->quantval[k])
+ qtblptr3->quantval[k] =
+ largest_common_denominator(qtblptr1->quantval[k],
+ qtblptr2->quantval[k]);
+ dequant_comp(srcinfo, compptr1, src_coef_arrays[ci], qtblptr3);
+ dequant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr3);
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+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.
+ */
+{
+ JDIMENSION comp_width, comp_height;
+ JDIMENSION blk_y, x_drop_blocks, y_drop_blocks;
+ int ci, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ jpeg_component_info *compptr;
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ comp_width = drop_width * compptr->h_samp_factor;
+ comp_height = drop_height * compptr->v_samp_factor;
+ x_drop_blocks = x_crop_offset * compptr->h_samp_factor;
+ y_drop_blocks = y_crop_offset * compptr->v_samp_factor;
+ for (blk_y = 0; blk_y < comp_height; blk_y += compptr->v_samp_factor) {
+ dst_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr)srcinfo, src_coef_arrays[ci], blk_y + y_drop_blocks,
+ (JDIMENSION)compptr->v_samp_factor, TRUE);
+ if (ci < dropinfo->num_components) {
+ src_buffer = (*dropinfo->mem->access_virt_barray)
+ ((j_common_ptr)dropinfo, drop_coef_arrays[ci], blk_y,
+ (JDIMENSION)compptr->v_samp_factor, FALSE);
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ jcopy_block_row(src_buffer[offset_y],
+ dst_buffer[offset_y] + x_drop_blocks, comp_width);
+ }
+ } else {
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ MEMZERO(dst_buffer[offset_y] + x_drop_blocks,
+ comp_width * sizeof(JBLOCK));
+ }
+ }
+ }
+ }
+}
+
+
+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,
@@ -113,13 +296,422 @@ do_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
(JDIMENSION)compptr->v_samp_factor, TRUE);
src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_y + y_crop_blocks,
+ ((j_common_ptr)srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks,
(JDIMENSION)compptr->v_samp_factor, FALSE);
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
- dst_buffer[offset_y],
- compptr->width_in_blocks);
+ dst_buffer[offset_y], compptr->width_in_blocks);
+ }
+ }
+ }
+}
+
+
+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.
+ */
+{
+ JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height;
+ JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
+ int ci, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ jpeg_component_info *compptr;
+
+ MCU_cols = srcinfo->output_width /
+ (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
+ MCU_rows = srcinfo->output_height /
+ (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ comp_width = MCU_cols * compptr->h_samp_factor;
+ comp_height = MCU_rows * compptr->v_samp_factor;
+ x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+ y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+ dst_blk_y += compptr->v_samp_factor) {
+ dst_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
+ (JDIMENSION)compptr->v_samp_factor, TRUE);
+ if (dstinfo->_jpeg_height > srcinfo->output_height) {
+ if (dst_blk_y < y_crop_blocks ||
+ dst_blk_y >= y_crop_blocks + comp_height) {
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ MEMZERO(dst_buffer[offset_y],
+ compptr->width_in_blocks * sizeof(JBLOCK));
+ }
+ continue;
+ }
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr)srcinfo, src_coef_arrays[ci],
+ dst_blk_y - y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
+ FALSE);
+ } else {
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr)srcinfo, src_coef_arrays[ci],
+ dst_blk_y + y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
+ FALSE);
+ }
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ if (dstinfo->_jpeg_width > srcinfo->output_width) {
+ if (x_crop_blocks > 0) {
+ MEMZERO(dst_buffer[offset_y], x_crop_blocks * sizeof(JBLOCK));
+ }
+ jcopy_block_row(src_buffer[offset_y],
+ dst_buffer[offset_y] + x_crop_blocks, comp_width);
+ if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
+ MEMZERO(dst_buffer[offset_y] + x_crop_blocks + comp_width,
+ (compptr->width_in_blocks - x_crop_blocks - comp_width) *
+ sizeof(JBLOCK));
+ }
+ } else {
+ jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
+ dst_buffer[offset_y], compptr->width_in_blocks);
+ }
+ }
+ }
+ }
+}
+
+
+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.
+ */
+{
+ JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height;
+ JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
+ int ci, offset_y;
+ JCOEF dc;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ jpeg_component_info *compptr;
+
+ MCU_cols = srcinfo->output_width /
+ (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
+ MCU_rows = srcinfo->output_height /
+ (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ comp_width = MCU_cols * compptr->h_samp_factor;
+ comp_height = MCU_rows * compptr->v_samp_factor;
+ x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+ y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+ dst_blk_y += compptr->v_samp_factor) {
+ dst_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
+ (JDIMENSION)compptr->v_samp_factor, TRUE);
+ if (dstinfo->_jpeg_height > srcinfo->output_height) {
+ if (dst_blk_y < y_crop_blocks ||
+ dst_blk_y >= y_crop_blocks + comp_height) {
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ MEMZERO(dst_buffer[offset_y],
+ compptr->width_in_blocks * sizeof(JBLOCK));
+ }
+ continue;
+ }
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr)srcinfo, src_coef_arrays[ci],
+ dst_blk_y - y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
+ FALSE);
+ } else {
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr)srcinfo, src_coef_arrays[ci],
+ dst_blk_y + y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
+ FALSE);
+ }
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ if (x_crop_blocks > 0) {
+ MEMZERO(dst_buffer[offset_y], x_crop_blocks * sizeof(JBLOCK));
+ dc = src_buffer[offset_y][0][0];
+ for (dst_blk_x = 0; dst_blk_x < x_crop_blocks; dst_blk_x++) {
+ dst_buffer[offset_y][dst_blk_x][0] = dc;
+ }
+ }
+ jcopy_block_row(src_buffer[offset_y],
+ dst_buffer[offset_y] + x_crop_blocks, comp_width);
+ if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
+ MEMZERO(dst_buffer[offset_y] + x_crop_blocks + comp_width,
+ (compptr->width_in_blocks - x_crop_blocks - comp_width) *
+ sizeof(JBLOCK));
+ dc = src_buffer[offset_y][comp_width - 1][0];
+ for (dst_blk_x = x_crop_blocks + comp_width;
+ dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
+ dst_buffer[offset_y][dst_blk_x][0] = dc;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+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.
+ */
+{
+ JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, src_blk_x;
+ JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
+ int ci, k, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ JBLOCKROW src_row_ptr, dst_row_ptr;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info *compptr;
+
+ MCU_cols = srcinfo->output_width /
+ (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
+ MCU_rows = srcinfo->output_height /
+ (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ comp_width = MCU_cols * compptr->h_samp_factor;
+ comp_height = MCU_rows * compptr->v_samp_factor;
+ x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+ y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+ dst_blk_y += compptr->v_samp_factor) {
+ dst_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
+ (JDIMENSION)compptr->v_samp_factor, TRUE);
+ if (dstinfo->_jpeg_height > srcinfo->output_height) {
+ if (dst_blk_y < y_crop_blocks ||
+ dst_blk_y >= y_crop_blocks + comp_height) {
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ MEMZERO(dst_buffer[offset_y],
+ compptr->width_in_blocks * sizeof(JBLOCK));
+ }
+ continue;
+ }
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr)srcinfo, src_coef_arrays[ci],
+ dst_blk_y - y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
+ FALSE);
+ } else {
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr)srcinfo, src_coef_arrays[ci],
+ dst_blk_y + y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
+ FALSE);
+ }
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ /* Copy source region */
+ jcopy_block_row(src_buffer[offset_y],
+ dst_buffer[offset_y] + x_crop_blocks, comp_width);
+ if (x_crop_blocks > 0) {
+ /* Reflect to left */
+ dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks;
+ for (dst_blk_x = x_crop_blocks; dst_blk_x > 0;) {
+ src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */
+ for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0;
+ src_blk_x--, dst_blk_x--) {
+ dst_ptr = *(--dst_row_ptr); /* destination goes left */
+ src_ptr = *src_row_ptr++; /* source goes right */
+ /* This unrolled loop doesn't need to know which row it's on. */
+ for (k = 0; k < DCTSIZE2; k += 2) {
+ *dst_ptr++ = *src_ptr++; /* copy even column */
+ *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign
+ change */
+ }
+ }
+ }
+ }
+ if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
+ /* Reflect to right */
+ dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks + comp_width;
+ for (dst_blk_x = compptr->width_in_blocks - x_crop_blocks - comp_width;
+ dst_blk_x > 0;) {
+ src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */
+ for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0;
+ src_blk_x--, dst_blk_x--) {
+ dst_ptr = *dst_row_ptr++; /* destination goes right */
+ src_ptr = *(--src_row_ptr); /* source goes left */
+ /* This unrolled loop doesn't need to know which row it's on. */
+ for (k = 0; k < DCTSIZE2; k += 2) {
+ *dst_ptr++ = *src_ptr++; /* copy even column */
+ *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign
+ change */
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+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)
+ */
+{
+ JDIMENSION x_wipe_blocks, wipe_width;
+ JDIMENSION y_wipe_blocks, wipe_bottom;
+ int ci, offset_y;
+ JBLOCKARRAY buffer;
+ jpeg_component_info *compptr;
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
+ wipe_width = drop_width * compptr->h_samp_factor;
+ y_wipe_blocks = y_crop_offset * compptr->v_samp_factor;
+ wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks;
+ for (; y_wipe_blocks < wipe_bottom;
+ y_wipe_blocks += compptr->v_samp_factor) {
+ buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
+ (JDIMENSION)compptr->v_samp_factor, TRUE);
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ MEMZERO(buffer[offset_y] + x_wipe_blocks, wipe_width * sizeof(JBLOCK));
+ }
+ }
+ }
+}
+
+
+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.
+ */
+{
+ JDIMENSION x_wipe_blocks, wipe_width, wipe_right;
+ JDIMENSION y_wipe_blocks, wipe_bottom, blk_x;
+ int ci, offset_y, dc_left_value, dc_right_value, average;
+ JBLOCKARRAY buffer;
+ jpeg_component_info *compptr;
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
+ wipe_width = drop_width * compptr->h_samp_factor;
+ wipe_right = wipe_width + x_wipe_blocks;
+ y_wipe_blocks = y_crop_offset * compptr->v_samp_factor;
+ wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks;
+ for (; y_wipe_blocks < wipe_bottom;
+ y_wipe_blocks += compptr->v_samp_factor) {
+ buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
+ (JDIMENSION)compptr->v_samp_factor, TRUE);
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ MEMZERO(buffer[offset_y] + x_wipe_blocks, wipe_width * sizeof(JBLOCK));
+ if (x_wipe_blocks > 0) {
+ dc_left_value = buffer[offset_y][x_wipe_blocks - 1][0];
+ if (wipe_right < compptr->width_in_blocks) {
+ dc_right_value = buffer[offset_y][wipe_right][0];
+ average = (dc_left_value + dc_right_value) >> 1;
+ } else {
+ average = dc_left_value;
+ }
+ } else if (wipe_right < compptr->width_in_blocks) {
+ average = buffer[offset_y][wipe_right][0];
+ } else continue;
+ for (blk_x = x_wipe_blocks; blk_x < wipe_right; blk_x++) {
+ buffer[offset_y][blk_x][0] = (JCOEF)average;
+ }
+ }
+ }
+ }
+}
+
+
+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.
+ */
+{
+ JDIMENSION x_wipe_blocks, wipe_width;
+ JDIMENSION y_wipe_blocks, wipe_bottom;
+ JDIMENSION src_blk_x, dst_blk_x;
+ int ci, k, offset_y;
+ JBLOCKARRAY buffer;
+ JBLOCKROW src_row_ptr, dst_row_ptr;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info *compptr;
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
+ wipe_width = drop_width * compptr->h_samp_factor;
+ wipe_bottom = drop_height * compptr->v_samp_factor;
+ for (y_wipe_blocks = 0; y_wipe_blocks < wipe_bottom;
+ y_wipe_blocks += compptr->v_samp_factor) {
+ buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
+ (JDIMENSION)compptr->v_samp_factor, TRUE);
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ if (x_wipe_blocks > 0) {
+ /* Reflect from left */
+ dst_row_ptr = buffer[offset_y] + x_wipe_blocks;
+ for (dst_blk_x = wipe_width; dst_blk_x > 0;) {
+ src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */
+ for (src_blk_x = x_wipe_blocks;
+ src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) {
+ dst_ptr = *dst_row_ptr++; /* destination goes right */
+ src_ptr = *(--src_row_ptr); /* source goes left */
+ /* this unrolled loop doesn't need to know which row it's on... */
+ for (k = 0; k < DCTSIZE2; k += 2) {
+ *dst_ptr++ = *src_ptr++; /* copy even column */
+ *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign change */
+ }
+ }
+ }
+ } else if (compptr->width_in_blocks > x_wipe_blocks + wipe_width) {
+ /* Reflect from right */
+ dst_row_ptr = buffer[offset_y] + x_wipe_blocks + wipe_width;
+ for (dst_blk_x = wipe_width; dst_blk_x > 0;) {
+ src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */
+ src_blk_x = compptr->width_in_blocks - x_wipe_blocks - wipe_width;
+ for (; src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) {
+ dst_ptr = *(--dst_row_ptr); /* destination goes left */
+ src_ptr = *src_row_ptr++; /* source goes right */
+ /* this unrolled loop doesn't need to know which row it's on... */
+ for (k = 0; k < DCTSIZE2; k += 2) {
+ *dst_ptr++ = *src_ptr++; /* copy even column */
+ *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign change */
+ }
+ }
+ }
+ } else {
+ MEMZERO(buffer[offset_y] + x_wipe_blocks,
+ wipe_width * sizeof(JBLOCK));
+ }
}
}
}
@@ -224,8 +816,7 @@ do_flip_h(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
(JDIMENSION)compptr->v_samp_factor, TRUE);
src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_y + y_crop_blocks,
+ ((j_common_ptr)srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks,
(JDIMENSION)compptr->v_samp_factor, FALSE);
for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
dst_row_ptr = dst_buffer[offset_y];
@@ -238,8 +829,9 @@ do_flip_h(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
/* this unrolled loop doesn't need to know which row it's on... */
for (k = 0; k < DCTSIZE2; k += 2) {
- *dst_ptr++ = *src_ptr++; /* copy even column */
- *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */
+ *dst_ptr++ = *src_ptr++; /* copy even column */
+ *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign
+ change */
}
} else {
/* Copy last partial block(s) verbatim */
@@ -318,14 +910,13 @@ do_flip_v(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
*dst_ptr++ = *src_ptr++;
/* copy odd row with sign change */
for (j = 0; j < DCTSIZE; j++)
- *dst_ptr++ = - *src_ptr++;
+ *dst_ptr++ = -(*src_ptr++);
}
}
} else {
/* Just copy row verbatim. */
jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
- dst_buffer[offset_y],
- compptr->width_in_blocks);
+ dst_buffer[offset_y], compptr->width_in_blocks);
}
}
}
@@ -599,11 +1190,11 @@ do_rot_180(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
/* For even row, negate every odd column. */
for (j = 0; j < DCTSIZE; j += 2) {
*dst_ptr++ = *src_ptr++;
- *dst_ptr++ = - *src_ptr++;
+ *dst_ptr++ = -(*src_ptr++);
}
/* For odd row, negate every even column. */
for (j = 0; j < DCTSIZE; j += 2) {
- *dst_ptr++ = - *src_ptr++;
+ *dst_ptr++ = -(*src_ptr++);
*dst_ptr++ = *src_ptr++;
}
}
@@ -614,7 +1205,7 @@ do_rot_180(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
for (j = 0; j < DCTSIZE; j++)
*dst_ptr++ = *src_ptr++;
for (j = 0; j < DCTSIZE; j++)
- *dst_ptr++ = - *src_ptr++;
+ *dst_ptr++ = -(*src_ptr++);
}
}
}
@@ -630,7 +1221,7 @@ do_rot_180(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
for (i = 0; i < DCTSIZE2; i += 2) {
*dst_ptr++ = *src_ptr++;
- *dst_ptr++ = - *src_ptr++;
+ *dst_ptr++ = -(*src_ptr++);
}
} else {
/* Any remaining right-edge blocks are only copied. */
@@ -786,7 +1377,7 @@ jt_read_integer(const char **strptr, JDIMENSION *result)
* The routine returns TRUE if the spec string is valid, FALSE if not.
*
* The crop spec string should have the format
- * <width>[f]x<height>[f]{+-}<xoffset>{+-}<yoffset>
+ * <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
@@ -811,6 +1402,9 @@ jtransform_parse_crop_spec(jpeg_transform_info *info, const char *spec)
if (*spec == 'f' || *spec == 'F') {
spec++;
info->crop_width_set = JCROP_FORCE;
+ } else if (*spec == 'r' || *spec == 'R') {
+ spec++;
+ info->crop_width_set = JCROP_REFLECT;
} else
info->crop_width_set = JCROP_POS;
}
@@ -822,6 +1416,9 @@ jtransform_parse_crop_spec(jpeg_transform_info *info, const char *spec)
if (*spec == 'f' || *spec == 'F') {
spec++;
info->crop_height_set = JCROP_FORCE;
+ } else if (*spec == 'r' || *spec == 'R') {
+ spec++;
+ info->crop_height_set = JCROP_REFLECT;
} else
info->crop_height_set = JCROP_POS;
}
@@ -896,10 +1493,10 @@ jtransform_request_workspace(j_decompress_ptr srcinfo,
jvirt_barray_ptr *coef_arrays;
boolean need_workspace, transpose_it;
jpeg_component_info *compptr;
- JDIMENSION xoffset, yoffset;
+ JDIMENSION xoffset, yoffset, dtemp;
JDIMENSION width_in_iMCUs, height_in_iMCUs;
JDIMENSION width_in_blocks, height_in_blocks;
- int ci, h_samp_factor, v_samp_factor;
+ int itemp, ci, h_samp_factor, v_samp_factor;
/* Determine number of components in output image */
if (info->force_grayscale &&
@@ -985,39 +1582,129 @@ jtransform_request_workspace(j_decompress_ptr srcinfo,
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)
+ if (info->crop_width_set == JCROP_UNSET) {
+ if (info->crop_xoffset >= info->output_width)
+ ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
info->crop_width = info->output_width - info->crop_xoffset;
- if (info->crop_height_set == JCROP_UNSET)
+ } else {
+ /* Check for crop extension */
+ if (info->crop_width > info->output_width) {
+ /* Crop extension does not work when transforming! */
+ if (info->transform != JXFORM_NONE ||
+ info->crop_xoffset >= info->crop_width ||
+ info->crop_xoffset > info->crop_width - info->output_width)
+ ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
+ } else {
+ if (info->crop_xoffset >= info->output_width ||
+ info->crop_width <= 0 ||
+ info->crop_xoffset > info->output_width - info->crop_width)
+ ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
+ }
+ }
+ if (info->crop_height_set == JCROP_UNSET) {
+ if (info->crop_yoffset >= info->output_height)
+ ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
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);
+ } else {
+ /* Check for crop extension */
+ if (info->crop_height > info->output_height) {
+ /* Crop extension does not work when transforming! */
+ if (info->transform != JXFORM_NONE ||
+ info->crop_yoffset >= info->crop_height ||
+ info->crop_yoffset > info->crop_height - info->output_height)
+ ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
+ } else {
+ if (info->crop_yoffset >= info->output_height ||
+ info->crop_height <= 0 ||
+ 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
+ if (info->crop_xoffset_set != JCROP_NEG)
xoffset = info->crop_xoffset;
- if (info->crop_yoffset_set == JCROP_NEG)
- yoffset = info->output_height - info->crop_height - info->crop_yoffset;
+ else if (info->crop_width > info->output_width) /* crop extension */
+ xoffset = info->crop_width - info->output_width - info->crop_xoffset;
else
+ xoffset = info->output_width - info->crop_width - info->crop_xoffset;
+ if (info->crop_yoffset_set != JCROP_NEG)
yoffset = info->crop_yoffset;
- /* Now adjust so that upper left corner falls at an iMCU boundary */
- if (info->crop_width_set == JCROP_FORCE)
- info->output_width = info->crop_width;
+ else if (info->crop_height > info->output_height) /* crop extension */
+ yoffset = info->crop_height - info->output_height - info->crop_yoffset;
else
- info->output_width =
- info->crop_width + (xoffset % info->iMCU_sample_width);
- if (info->crop_height_set == JCROP_FORCE)
- info->output_height = info->crop_height;
- else
- info->output_height =
- info->crop_height + (yoffset % info->iMCU_sample_height);
+ yoffset = info->output_height - info->crop_height - info->crop_yoffset;
+ /* Now adjust so that upper left corner falls at an iMCU boundary */
+ switch (info->transform) {
+ case JXFORM_DROP:
+ /* Ensure the effective drop region will not exceed the requested */
+ itemp = info->iMCU_sample_width;
+ dtemp = itemp - 1 - ((xoffset + itemp - 1) % itemp);
+ xoffset += dtemp;
+ if (info->crop_width <= dtemp)
+ info->drop_width = 0;
+ else if (xoffset + info->crop_width - dtemp == info->output_width)
+ /* Matching right edge: include partial iMCU */
+ info->drop_width = (info->crop_width - dtemp + itemp - 1) / itemp;
+ else
+ info->drop_width = (info->crop_width - dtemp) / itemp;
+ itemp = info->iMCU_sample_height;
+ dtemp = itemp - 1 - ((yoffset + itemp - 1) % itemp);
+ yoffset += dtemp;
+ if (info->crop_height <= dtemp)
+ info->drop_height = 0;
+ else if (yoffset + info->crop_height - dtemp == info->output_height)
+ /* Matching bottom edge: include partial iMCU */
+ info->drop_height = (info->crop_height - dtemp + itemp - 1) / itemp;
+ else
+ info->drop_height = (info->crop_height - dtemp) / itemp;
+ /* Check if sampling factors match for dropping */
+ if (info->drop_width != 0 && info->drop_height != 0)
+ for (ci = 0; ci < info->num_components &&
+ ci < info->drop_ptr->num_components; ci++) {
+ if (info->drop_ptr->comp_info[ci].h_samp_factor *
+ srcinfo->max_h_samp_factor !=
+ srcinfo->comp_info[ci].h_samp_factor *
+ info->drop_ptr->max_h_samp_factor)
+ ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci,
+ info->drop_ptr->comp_info[ci].h_samp_factor,
+ info->drop_ptr->max_h_samp_factor,
+ srcinfo->comp_info[ci].h_samp_factor,
+ srcinfo->max_h_samp_factor, 'h');
+ if (info->drop_ptr->comp_info[ci].v_samp_factor *
+ srcinfo->max_v_samp_factor !=
+ srcinfo->comp_info[ci].v_samp_factor *
+ info->drop_ptr->max_v_samp_factor)
+ ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci,
+ info->drop_ptr->comp_info[ci].v_samp_factor,
+ info->drop_ptr->max_v_samp_factor,
+ srcinfo->comp_info[ci].v_samp_factor,
+ srcinfo->max_v_samp_factor, 'v');
+ }
+ break;
+ case JXFORM_WIPE:
+ /* Ensure the effective wipe region will cover the requested */
+ info->drop_width = (JDIMENSION)jdiv_round_up
+ ((long)(info->crop_width + (xoffset % info->iMCU_sample_width)),
+ (long)info->iMCU_sample_width);
+ info->drop_height = (JDIMENSION)jdiv_round_up
+ ((long)(info->crop_height + (yoffset % info->iMCU_sample_height)),
+ (long)info->iMCU_sample_height);
+ break;
+ default:
+ /* Ensure the effective crop region will cover the requested */
+ if (info->crop_width_set == JCROP_FORCE ||
+ info->crop_width > info->output_width)
+ info->output_width = info->crop_width;
+ else
+ info->output_width =
+ info->crop_width + (xoffset % info->iMCU_sample_width);
+ if (info->crop_height_set == JCROP_FORCE ||
+ info->crop_height > info->output_height)
+ info->output_height = info->crop_height;
+ else
+ info->output_height =
+ info->crop_height + (yoffset % info->iMCU_sample_height);
+ }
/* Save x/y offsets measured in iMCUs */
info->x_crop_offset = xoffset / info->iMCU_sample_width;
info->y_crop_offset = yoffset / info->iMCU_sample_height;
@@ -1033,7 +1720,9 @@ jtransform_request_workspace(j_decompress_ptr srcinfo,
transpose_it = FALSE;
switch (info->transform) {
case JXFORM_NONE:
- if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
+ if (info->x_crop_offset != 0 || info->y_crop_offset != 0 ||
+ info->output_width > srcinfo->output_width ||
+ info->output_height > srcinfo->output_height)
need_workspace = TRUE;
/* No workspace needed if neither cropping nor transforming */
break;
@@ -1087,6 +1776,10 @@ jtransform_request_workspace(j_decompress_ptr srcinfo,
need_workspace = TRUE;
transpose_it = TRUE;
break;
+ case JXFORM_WIPE:
+ break;
+ case JXFORM_DROP:
+ break;
}
/* Allocate workspace if needed.
@@ -1190,47 +1883,47 @@ adjust_exif_parameters(JOCTET *data, unsigned int length, JDIMENSION new_width,
if (length < 12) return; /* Length of an IFD entry */
/* Discover byte order */
- if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49)
+ if (data[0] == 0x49 && data[1] == 0x49)
is_motorola = FALSE;
- else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D)
+ else if (data[0] == 0x4D && data[1] == 0x4D)
is_motorola = TRUE;
else
return;
/* Check Tag Mark */
if (is_motorola) {
- if (GETJOCTET(data[2]) != 0) return;
- if (GETJOCTET(data[3]) != 0x2A) return;
+ if (data[2] != 0) return;
+ if (data[3] != 0x2A) return;
} else {
- if (GETJOCTET(data[3]) != 0) return;
- if (GETJOCTET(data[2]) != 0x2A) return;
+ if (data[3] != 0) return;
+ if (data[2] != 0x2A) return;
}
/* Get first IFD offset (offset to IFD0) */
if (is_motorola) {
- if (GETJOCTET(data[4]) != 0) return;
- if (GETJOCTET(data[5]) != 0) return;
- firstoffset = GETJOCTET(data[6]);
+ if (data[4] != 0) return;
+ if (data[5] != 0) return;
+ firstoffset = data[6];
firstoffset <<= 8;
- firstoffset += GETJOCTET(data[7]);
+ firstoffset += data[7];
} else {
- if (GETJOCTET(data[7]) != 0) return;
- if (GETJOCTET(data[6]) != 0) return;
- firstoffset = GETJOCTET(data[5]);
+ if (data[7] != 0) return;
+ if (data[6] != 0) return;
+ firstoffset = data[5];
firstoffset <<= 8;
- firstoffset += GETJOCTET(data[4]);
+ firstoffset += data[4];
}
if (firstoffset > length - 2) return; /* check end of data segment */
/* Get the number of directory entries contained in this IFD */
if (is_motorola) {
- number_of_tags = GETJOCTET(data[firstoffset]);
+ number_of_tags = data[firstoffset];
number_of_tags <<= 8;
- number_of_tags += GETJOCTET(data[firstoffset + 1]);
+ number_of_tags += data[firstoffset + 1];
} else {
- number_of_tags = GETJOCTET(data[firstoffset + 1]);
+ number_of_tags = data[firstoffset + 1];
number_of_tags <<= 8;
- number_of_tags += GETJOCTET(data[firstoffset]);
+ number_of_tags += data[firstoffset];
}
if (number_of_tags == 0) return;
firstoffset += 2;
@@ -1240,13 +1933,13 @@ adjust_exif_parameters(JOCTET *data, unsigned int length, JDIMENSION new_width,
if (firstoffset > length - 12) return; /* check end of data segment */
/* Get Tag number */
if (is_motorola) {
- tagnum = GETJOCTET(data[firstoffset]);
+ tagnum = data[firstoffset];
tagnum <<= 8;
- tagnum += GETJOCTET(data[firstoffset + 1]);
+ tagnum += data[firstoffset + 1];
} else {
- tagnum = GETJOCTET(data[firstoffset + 1]);
+ tagnum = data[firstoffset + 1];
tagnum <<= 8;
- tagnum += GETJOCTET(data[firstoffset]);
+ tagnum += data[firstoffset];
}
if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */
if (--number_of_tags == 0) return;
@@ -1255,29 +1948,29 @@ adjust_exif_parameters(JOCTET *data, unsigned int length, JDIMENSION new_width,
/* Get the ExifSubIFD offset */
if (is_motorola) {
- if (GETJOCTET(data[firstoffset + 8]) != 0) return;
- if (GETJOCTET(data[firstoffset + 9]) != 0) return;
- offset = GETJOCTET(data[firstoffset + 10]);
+ if (data[firstoffset + 8] != 0) return;
+ if (data[firstoffset + 9] != 0) return;
+ offset = data[firstoffset + 10];
offset <<= 8;
- offset += GETJOCTET(data[firstoffset + 11]);
+ offset += data[firstoffset + 11];
} else {
- if (GETJOCTET(data[firstoffset + 11]) != 0) return;
- if (GETJOCTET(data[firstoffset + 10]) != 0) return;
- offset = GETJOCTET(data[firstoffset + 9]);
+ if (data[firstoffset + 11] != 0) return;
+ if (data[firstoffset + 10] != 0) return;
+ offset = data[firstoffset + 9];
offset <<= 8;
- offset += GETJOCTET(data[firstoffset + 8]);
+ offset += data[firstoffset + 8];
}
if (offset > length - 2) return; /* check end of data segment */
/* Get the number of directory entries contained in this SubIFD */
if (is_motorola) {
- number_of_tags = GETJOCTET(data[offset]);
+ number_of_tags = data[offset];
number_of_tags <<= 8;
- number_of_tags += GETJOCTET(data[offset + 1]);
+ number_of_tags += data[offset + 1];
} else {
- number_of_tags = GETJOCTET(data[offset + 1]);
+ number_of_tags = data[offset + 1];
number_of_tags <<= 8;
- number_of_tags += GETJOCTET(data[offset]);
+ number_of_tags += data[offset];
}
if (number_of_tags < 2) return;
offset += 2;
@@ -1287,13 +1980,13 @@ adjust_exif_parameters(JOCTET *data, unsigned int length, JDIMENSION new_width,
if (offset > length - 12) return; /* check end of data segment */
/* Get Tag number */
if (is_motorola) {
- tagnum = GETJOCTET(data[offset]);
+ tagnum = data[offset];
tagnum <<= 8;
- tagnum += GETJOCTET(data[offset + 1]);
+ tagnum += data[offset + 1];
} else {
- tagnum = GETJOCTET(data[offset + 1]);
+ tagnum = data[offset + 1];
tagnum <<= 8;
- tagnum += GETJOCTET(data[offset]);
+ tagnum += data[offset];
}
if (tagnum == 0xA002 || tagnum == 0xA003) {
if (tagnum == 0xA002)
@@ -1387,7 +2080,7 @@ jtransform_adjust_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
dstinfo->jpeg_height = info->output_height;
#endif
- /* Transpose destination image parameters */
+ /* Transpose destination image parameters, adjust quantization */
switch (info->transform) {
case JXFORM_TRANSPOSE:
case JXFORM_TRANSVERSE:
@@ -1399,6 +2092,12 @@ jtransform_adjust_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
#endif
transpose_critical_parameters(dstinfo);
break;
+ case JXFORM_DROP:
+ if (info->drop_width != 0 && info->drop_height != 0)
+ adjust_quant(srcinfo, src_coef_arrays,
+ info->drop_ptr, info->drop_coef_arrays,
+ info->trim, dstinfo);
+ break;
default:
#if JPEG_LIB_VERSION < 80
dstinfo->image_width = info->output_width;
@@ -1411,12 +2110,12 @@ jtransform_adjust_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
if (srcinfo->marker_list != NULL &&
srcinfo->marker_list->marker == JPEG_APP0 + 1 &&
srcinfo->marker_list->data_length >= 6 &&
- GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 &&
- GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 &&
- GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 &&
- GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 &&
- GETJOCTET(srcinfo->marker_list->data[4]) == 0 &&
- GETJOCTET(srcinfo->marker_list->data[5]) == 0) {
+ srcinfo->marker_list->data[0] == 0x45 &&
+ srcinfo->marker_list->data[1] == 0x78 &&
+ srcinfo->marker_list->data[2] == 0x69 &&
+ srcinfo->marker_list->data[3] == 0x66 &&
+ srcinfo->marker_list->data[4] == 0 &&
+ srcinfo->marker_list->data[5] == 0) {
/* Suppress output of JFIF marker */
dstinfo->write_JFIF_header = FALSE;
/* Adjust Exif image parameters */
@@ -1465,7 +2164,23 @@ jtransform_execute_transform(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
*/
switch (info->transform) {
case JXFORM_NONE:
- if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
+ if (info->output_width > srcinfo->output_width ||
+ info->output_height > srcinfo->output_height) {
+ if (info->output_width > srcinfo->output_width &&
+ info->crop_width_set == JCROP_REFLECT)
+ do_crop_ext_reflect(srcinfo, dstinfo,
+ info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, dst_coef_arrays);
+ else if (info->output_width > srcinfo->output_width &&
+ info->crop_width_set == JCROP_FORCE)
+ do_crop_ext_flat(srcinfo, dstinfo,
+ info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, dst_coef_arrays);
+ else
+ do_crop_ext_zero(srcinfo, dstinfo,
+ info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, dst_coef_arrays);
+ } else if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
src_coef_arrays, dst_coef_arrays);
break;
@@ -1501,6 +2216,30 @@ jtransform_execute_transform(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
src_coef_arrays, dst_coef_arrays);
break;
+ case JXFORM_WIPE:
+ if (info->crop_width_set == JCROP_REFLECT &&
+ info->y_crop_offset == 0 && info->drop_height ==
+ (JDIMENSION)jdiv_round_up
+ ((long)info->output_height, (long)info->iMCU_sample_height) &&
+ (info->x_crop_offset == 0 ||
+ info->x_crop_offset + info->drop_width ==
+ (JDIMENSION)jdiv_round_up
+ ((long)info->output_width, (long)info->iMCU_sample_width)))
+ do_reflect(srcinfo, dstinfo, info->x_crop_offset,
+ src_coef_arrays, info->drop_width, info->drop_height);
+ else if (info->crop_width_set == JCROP_FORCE)
+ do_flatten(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, info->drop_width, info->drop_height);
+ else
+ do_wipe(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, info->drop_width, info->drop_height);
+ break;
+ case JXFORM_DROP:
+ if (info->drop_width != 0 && info->drop_height != 0)
+ do_drop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, info->drop_ptr, info->drop_coef_arrays,
+ info->drop_width, info->drop_height);
+ break;
}
}
@@ -1607,20 +2346,20 @@ jcopy_markers_execute(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
if (dstinfo->write_JFIF_header &&
marker->marker == JPEG_APP0 &&
marker->data_length >= 5 &&
- GETJOCTET(marker->data[0]) == 0x4A &&
- GETJOCTET(marker->data[1]) == 0x46 &&
- GETJOCTET(marker->data[2]) == 0x49 &&
- GETJOCTET(marker->data[3]) == 0x46 &&
- GETJOCTET(marker->data[4]) == 0)
+ marker->data[0] == 0x4A &&
+ marker->data[1] == 0x46 &&
+ marker->data[2] == 0x49 &&
+ marker->data[3] == 0x46 &&
+ marker->data[4] == 0)
continue; /* reject duplicate JFIF */
if (dstinfo->write_Adobe_marker &&
marker->marker == JPEG_APP0 + 14 &&
marker->data_length >= 5 &&
- GETJOCTET(marker->data[0]) == 0x41 &&
- GETJOCTET(marker->data[1]) == 0x64 &&
- GETJOCTET(marker->data[2]) == 0x6F &&
- GETJOCTET(marker->data[3]) == 0x62 &&
- GETJOCTET(marker->data[4]) == 0x65)
+ marker->data[0] == 0x41 &&
+ marker->data[1] == 0x64 &&
+ marker->data[2] == 0x6F &&
+ marker->data[3] == 0x62 &&
+ marker->data[4] == 0x65)
continue; /* reject duplicate Adobe */
jpeg_write_marker(dstinfo, marker->marker,
marker->data, marker->data_length);