[vlc-devel] [PATCH] Automatically orient JPEG image based on orientation flag, if set
Wayne McDougall
waynemcdougall at gmail.com
Fri Apr 15 01:50:02 CEST 2016
---
modules/codec/jpeg.c | 1263
+++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 1257 insertions(+), 6 deletions(-)
diff --git a/modules/codec/jpeg.c b/modules/codec/jpeg.c
index cc7a58b..77233a7 100644
--- a/modules/codec/jpeg.c
+++ b/modules/codec/jpeg.c
@@ -1,9 +1,10 @@
/*****************************************************************************
* jpeg.c: jpeg decoder module making use of libjpeg.
*****************************************************************************
- * Copyright (C) 2013-2014 VLC authors and VideoLAN
+ * Copyright (C) 2013-2014,2016 VLC authors and VideoLAN
*
* Authors: Maxim Bublis <b at codemonkey.ru>
+ * Wayne McDougall <waynemcdougall at gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
@@ -27,6 +28,11 @@
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_codec.h>
+
+/* 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 <jpeglib.h>
#include <setjmp.h>
@@ -50,6 +56,27 @@
#define ENC_QUALITY_LONGTEXT N_( "Quality level " \
"for encoding (this can enlarge or reduce
output image size)." )
+#define DEC_CFG_PREFIX "jpeg-"
+#define DEC_AUTOORIENT_TEXT N_( "Automatic Orientation" )
+#define DEC_AUTOORIENT_LONGTEXT N_( "Automatic rotation based on EXIF
orientation flag. " \
+ "Lossless, but will crop if JPEG has
unusual dimensions. Uses more RAM." )
+
+const char leth[] = {
+ 0x49, 0x49, 0x2a, 0x00
+}; /* Little endian TIFF
header */
+const char beth[] = {
+ 0x4d, 0x4d, 0x00, 0x2a
+}; /* Big endian TIFF header
*/
+const char types[] = {
+ 0x00, 0x01, 0x01, 0x02, 0x04, 0x08, 0x00,
+ 0x08, 0x00, 0x04, 0x08
+}; /* size in bytes for EXIF
types */
+
+#define G_LITTLE_ENDIAN 1234
+#define G_BIG_ENDIAN 4321
+
+#define EXIF_JPEG_MARKER 0xE1
+#define EXIF_IDENT_STRING "Exif\000\000"
/*
* jpeg common descriptor
@@ -86,6 +113,33 @@ struct encoder_sys_t {
int i_quality;
};
+/*
+ * Codes for supported types of image transformations.
+ */
+
+typedef enum {
+ JXFORM_FLIP_H, /* horizontal flip */
+ JXFORM_FLIP_V, /* vertical flip */
+ JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */
+ JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */
+ JXFORM_ROT_90, /* 90-degree clockwise rotation */
+ JXFORM_ROT_180, /* 180-degree rotation */
+ JXFORM_ROT_270, /* 270-degree clockwise (or 90 ccw) */
+} JXFORM_CODE;
+
+typedef struct {
+ /* Options: set by caller */
+ JXFORM_CODE transform; /* image transform operator */
+
+ /* Internal workspace: caller should not touch these */
+ int num_components; /* # of components in workspace */
+ jvirt_barray_ptr * workspace_coef_arrays; /* workspace for
transformations */
+ JDIMENSION output_width; /* cropped destination dimensions */
+ JDIMENSION output_height;
+ int iMCU_sample_width; /* destination iMCU size */
+ int iMCU_sample_height;
+} jpeg_transform_info;
+
static const char * const ppsz_enc_options[] = {
"quality",
NULL
@@ -107,6 +161,8 @@ set_description( N_( "JPEG image decoder" ) )
set_capability( "decoder", 1000 )
set_callbacks( OpenDecoder, CloseDecoder )
add_shortcut( "jpeg" )
+add_bool( DEC_CFG_PREFIX "autoorient", true,
+ DEC_AUTOORIENT_TEXT, DEC_AUTOORIENT_LONGTEXT, true )
/* encoder submodule */
add_submodule()
@@ -178,6 +234,1120 @@ static int OpenDecoder ( vlc_object_t * p_this )
return VLC_SUCCESS;
}
+/* Start of code used to Auto Orient JPEG */
+
+LOCAL( unsigned short )
+de_get16( void * ptr, uint endian ) {
+ unsigned short val;
+
+ memcpy( &val, ptr, sizeof( val ) );
+ if ( endian == G_BIG_ENDIAN )
+ {
+ #ifndef WORDS_BIGENDIAN
+ val = bswap16( val );
+ #endif
+ }
+ else
+ {
+ #ifdef WORDS_BIGENDIAN
+ val = bswap16( val );
+ #endif
+ }
+ return val;
+}
+
+LOCAL( unsigned int )
+de_get32( void * ptr, uint endian ) {
+ unsigned int val;
+
+ memcpy( &val, ptr, sizeof( val ) );
+ if ( endian == G_BIG_ENDIAN )
+ {
+ #ifndef WORDS_BIGENDIAN
+ val = bswap32( val );
+ #endif
+ }
+ else
+ {
+ #ifdef WORDS_BIGENDIAN
+ val = bswap32( val );
+ #endif
+ }
+ return val;
+}
+
+/* jpeg_GetOrientation function based on code from GdkPixbuf library -
JPEG image loader
+ *
http://src.gnu-darwin.org/ports/x11-toolkits/gtk20/work/gtk+-2.12.3/gdk-pixbuf/io-jpeg.c
+ *
+ * Copyright (C) 1999 Michael Zucchi
+ * Copyright (C) 1999 The Free Software Foundation
+ */
+
+LOCAL( int )
+jpeg_GetOrientation( j_decompress_ptr cinfo ) {
+ /* This function looks through the meta data in the libjpeg decompress
structure to
+ determine if an EXIF Orientation tag is present and if so return
its value (1-8).
+ If no EXIF Orientation tag is found 0 (zero) is returned. */
+
+ uint i; /* index into working buffer */
+ ushort tag_type; /* endianed tag type extracted from tiff
header */
+ uint ret; /* Return value */
+ uint offset; /* de-endianed offset in various situations
*/
+ uint tags; /* number of tags in current ifd */
+ uint type; /* de-endianed type of tag used as index
into types[] */
+ uint count; /* de-endianed count of elements in a tag */
+ uint tiff = 0; /* offset to active tiff header */
+ uint endian = 0; /* detected endian of data */
+
+ jpeg_saved_marker_ptr exif_marker; /* Location of the Exif APP1
marker */
+ jpeg_saved_marker_ptr cmarker; /* Location to check for Exif
APP1 marker */
+
+ /* check for Exif marker (also called the APP1 marker) */
+ exif_marker = NULL;
+ cmarker = cinfo->marker_list;
+
+
+
+ while ( cmarker )
+ {
+ if ( cmarker->marker == EXIF_JPEG_MARKER )
+ {
+ /* The Exif APP1 marker should contain a unique
+ identification string ("Exif\0\0"). Check for it. */
+ if ( !memcmp( cmarker->data, EXIF_IDENT_STRING, 6 ) )
+ {
+ exif_marker = cmarker;
+ }
+ }
+ cmarker = cmarker->next;
+ }
+
+ /* Did we find the Exif APP1 marker? */
+ if ( exif_marker == NULL )
+ return 0;
+
+ /* Do we have enough data? */
+ if ( exif_marker->data_length < 32 )
+ return 0;
+
+ /* Check for TIFF header and catch endianess */
+ i = 0;
+
+ /* Just skip data until TIFF header - it should be within 16 bytes
from marker start.
+ Normal structure relative to APP1 marker -
+ 0x0000: APP1 marker entry = 2 bytes
+ 0x0002: APP1 length entry = 2 bytes
+ 0x0004: Exif Identifier entry = 6 bytes
+ 0x000A: Start of TIFF header (Byte order entry) - 4 bytes
+ - This is what we look for, to determine endianess.
+ 0x000E: 0th IFD offset pointer - 4 bytes
+
+ exif_marker->data points to the first data after the APP1
marker
+ and length entries, which is the exif identification string.
+ The TIFF header should thus normally be found at i=6, below,
+ and the pointer to IFD0 will be at 6+4 = 10.
+ */
+
+ while ( i < 16 )
+ {
+ /* Little endian TIFF header */
+ if ( memcmp( &exif_marker->data[i], leth, 4 ) == 0 )
+ {
+ endian = G_LITTLE_ENDIAN;
+ }
+ /* Big endian TIFF header */
+ else
+ if ( memcmp( &exif_marker->data[i], beth, 4 ) == 0 )
+ {
+ endian = G_BIG_ENDIAN;
+ }
+ /* Keep looking through buffer */
+ else
+ {
+ i++;
+ continue;
+ }
+ /* We have found either big or little endian TIFF header */
+ tiff = i;
+ break;
+ }
+
+ /* So did we find a TIFF header or did we just hit end of buffer? */
+ if ( tiff == 0 )
+ return 0;
+
+ /* Read out the offset pointer to IFD0 */
+ offset = de_get32( &exif_marker->data[i] + 4, endian );
+ i = i + offset;
+
+ /* Check that we still are within the buffer and can read the tag
count */
+
+ if ( ( i + 2 ) > exif_marker->data_length )
+ return 0;
+
+ /* Find out how many tags we have in IFD0. As per the TIFF spec, the
first
+ two bytes of the IFD contain a count of the number of tags. */
+ tags = de_get16( &exif_marker->data[i], endian );
+ i = i + 2;
+
+ /* Check that we still have enough data for all tags to check. The tags
+ are listed in consecutive 12-byte blocks. The tag ID, type, size,
and
+ a pointer to the actual value, are packed into these 12 byte
entries. */
+ if ( ( i + tags * 12 ) > exif_marker->data_length )
+ return 0;
+
+ /* Check through IFD0 for tags of interest */
+ while ( tags-- )
+ {
+ tag_type = de_get16( &exif_marker->data[i], endian );
+ /* Is this the orientation tag? */
+ if ( tag_type == 0x112 )
+ {
+ type = de_get16( &exif_marker->data[i + 2], endian );
+ count = de_get32( &exif_marker->data[i + 4], endian );
+
+ /* Check that type and count fields are OK. The orientation
field
+ will consist of a single (count=1) 2-byte integer (type=3).
*/
+ if ( type != 3 || count != 1 )
+ return 0;
+
+ /* Return the orientation value. Within the 12-byte block, the
+ pointer to the actual data is at offset 8. */
+ ret = de_get16( &exif_marker->data[i + 8], endian );
+ return ret <= 8 ? ret : 0;
+ }
+ /* move the pointer to the next 12-byte tag field. */
+ i = i + 12;
+ }
+
+ return 0; /* No EXIF Orientation tag found */
+}
+
+/* Following Auto Orient code heavily based on code from transupp.c by the
IJG */
+
+/* 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->iMCU_sample_width;
+ if ( MCU_cols > 0 && MCU_cols ==
+ full_width / info->iMCU_sample_width )
+ info->output_width = MCU_cols * info->iMCU_sample_width;
+}
+
+LOCAL( void )
+trim_bottom_edge( jpeg_transform_info * info, JDIMENSION full_height ) {
+ JDIMENSION MCU_rows;
+
+ MCU_rows = info->output_height / info->iMCU_sample_height;
+ if ( MCU_rows > 0 && MCU_rows ==
+ full_height / info->iMCU_sample_height )
+ info->output_height = MCU_rows * info->iMCU_sample_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).
+ *
+ */
+
+LOCAL( boolean )
+jtransform_request_workspace( j_decompress_ptr srcinfo,
+ jpeg_transform_info * info ) {
+ jvirt_barray_ptr * coef_arrays;
+ boolean need_workspace, transpose_it;
+ jpeg_component_info * compptr;
+ JDIMENSION width_in_iMCUs, height_in_iMCUs;
+ JDIMENSION width_in_blocks, height_in_blocks;
+ int ci, h_samp_factor, v_samp_factor;
+
+ /* Process all the components */
+ info->num_components = srcinfo->num_components;
+
+ /* Compute output image dimensions and related values. */
+ jpeg_core_output_dimensions( srcinfo );
+
+ /* If there is only one output component, force the iMCU size to be 1;
+ * else use the source iMCU size.
+ */
+ switch ( info->transform )
+ {
+ case JXFORM_TRANSPOSE:
+ case JXFORM_TRANSVERSE:
+ case JXFORM_ROT_90:
+ case JXFORM_ROT_270:
+ info->output_width = srcinfo->output_height;
+ info->output_height = srcinfo->output_width;
+ if ( info->num_components == 1 )
+ {
+ info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size;
+ info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size;
+ }
+ else
+ {
+ info->iMCU_sample_width =
+ srcinfo->max_v_samp_factor *
srcinfo->min_DCT_v_scaled_size;
+ info->iMCU_sample_height =
+ srcinfo->max_h_samp_factor *
srcinfo->min_DCT_h_scaled_size;
+ }
+ break;
+ default:
+ info->output_width = srcinfo->output_width;
+ info->output_height = srcinfo->output_height;
+ if ( info->num_components == 1 )
+ {
+ info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size;
+ info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size;
+ }
+ else
+ {
+ info->iMCU_sample_width =
+ srcinfo->max_h_samp_factor *
srcinfo->min_DCT_h_scaled_size;
+ info->iMCU_sample_height =
+ srcinfo->max_v_samp_factor *
srcinfo->min_DCT_v_scaled_size;
+ }
+ break;
+ }
+
+ /* 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_FLIP_H:
+ trim_right_edge( info, srcinfo->output_width );
+ /* do_flip_h doesn't need a workspace array */
+ break;
+ case JXFORM_FLIP_V:
+ trim_bottom_edge( info, srcinfo->output_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:
+ trim_right_edge( info, srcinfo->output_height );
+ trim_bottom_edge( info, srcinfo->output_width );
+ /* Need workspace arrays having transposed dimensions. */
+ need_workspace = TRUE;
+ transpose_it = TRUE;
+ break;
+ case JXFORM_ROT_90:
+ trim_right_edge( info, srcinfo->output_height );
+ /* Need workspace arrays having transposed dimensions. */
+ need_workspace = TRUE;
+ transpose_it = TRUE;
+ break;
+ case JXFORM_ROT_180:
+ trim_right_edge( info, srcinfo->output_width );
+ trim_bottom_edge( info, srcinfo->output_height );
+ /* Need workspace arrays having same dimensions as source image. */
+ need_workspace = TRUE;
+ break;
+ case JXFORM_ROT_270:
+ trim_bottom_edge( info, srcinfo->output_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->iMCU_sample_width );
+ height_in_iMCUs = (JDIMENSION)
+ jdiv_round_up( (long)info->output_height,
+ (long)info->iMCU_sample_height );
+ 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;
+ }
+ else
+ info->workspace_coef_arrays = NULL;
+
+ return TRUE;
+}
+
+/* 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;
+ JDIMENSION jtemp;
+ UINT16 qtemp;
+
+ /* Transpose image dimensions */
+ jtemp = dstinfo->image_width;
+ dstinfo->image_width = dstinfo->image_height;
+ dstinfo->image_height = jtemp;
+ itemp = dstinfo->min_DCT_h_scaled_size;
+ dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size;
+
+ dstinfo->min_DCT_v_scaled_size = itemp;
+
+ /* 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 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().
+ */
+
+LOCAL( jvirt_barray_ptr * )
+jtransform_adjust_parameters( j_compress_ptr dstinfo,
+ jvirt_barray_ptr * src_coef_arrays,
+ jpeg_transform_info * info ) {
+ /* Correct the destination's image dimensions as necessary
+ * for rotate/flip operations.
+ */
+ dstinfo->jpeg_width = info->output_width;
+ dstinfo->jpeg_height = info->output_height;
+
+ if ( info->transform == JXFORM_ROT_270 )
+ {
+ transpose_critical_parameters( dstinfo );
+ }
+
+ /* Return the appropriate output data set */
+ if ( info->workspace_coef_arrays != NULL )
+ return info->workspace_coef_arrays;
+ return src_coef_arrays;
+}
+
+LOCAL( void )
+do_flip_h( j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
jvirt_barray_ptr * src_coef_arrays ) {
+/* Horizontal flip; done in-place, so no separate dest array is required.
+ */
+ JDIMENSION MCU_cols, comp_width, blk_x, blk_y;
+ int ci, k, offset_y;
+ JBLOCKARRAY buffer;
+ JCOEFPTR ptr1, ptr2;
+ JCOEF temp1, temp2;
+ jpeg_component_info * compptr;
+
+ /* Horizontal mirroring of DCT blocks is accomplished by swapping
+ * pairs of blocks in-place. Within a DCT block, we perform horizontal
+ * mirroring by changing the signs of odd-numbered columns.
+ * Partial iMCUs at the right edge are left untouched.
+ */
+ MCU_cols = srcinfo->output_width /
+ ( dstinfo->max_h_samp_factor *
dstinfo->min_DCT_h_scaled_size );
+
+ for ( ci = 0; ci < dstinfo->num_components; ci++ )
+ {
+ compptr = dstinfo->comp_info + ci;
+ comp_width = MCU_cols * compptr->h_samp_factor;
+ for ( blk_y = 0; blk_y < compptr->height_in_blocks;
+ blk_y += compptr->v_samp_factor )
+ {
+ buffer = ( *srcinfo->mem->access_virt_barray )
+ ( (j_common_ptr)srcinfo, src_coef_arrays[ci],
blk_y,
+ (JDIMENSION)compptr->v_samp_factor, TRUE );
+ for ( offset_y = 0; offset_y < compptr->v_samp_factor;
offset_y++ )
+ {
+ /* Do the mirroring */
+ for ( blk_x = 0; blk_x * 2 < comp_width; blk_x++ )
+ {
+ ptr1 = buffer[offset_y][blk_x];
+ ptr2 = buffer[offset_y][comp_width - blk_x - 1];
+ /* this unrolled loop doesn't need to know which row
it's on... */
+ for ( k = 0; k < DCTSIZE2; k += 2 )
+ {
+ temp1 = *ptr1; /* swap even column */
+ temp2 = *ptr2;
+ *ptr1++ = temp2;
+ *ptr2++ = temp1;
+ temp1 = *ptr1; /* swap odd column with sign change
*/
+ temp2 = *ptr2;
+ *ptr1++ = -temp2;
+ *ptr2++ = -temp1;
+ }
+ }
+ }
+ }
+ }
+}
+
+LOCAL( void )
+do_flip_v( j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ jvirt_barray_ptr * src_coef_arrays,
+ jvirt_barray_ptr * dst_coef_arrays ) {
+/* Vertical flip */
+ JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
+ int ci, i, j, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ JBLOCKROW src_row_ptr, dst_row_ptr;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info * compptr;
+
+ /* We output into a separate array because we can't touch different
+ * rows of the source virtual array simultaneously. Otherwise, this
+ * is a pretty straightforward analog of horizontal flip.
+ * Within a DCT block, vertical mirroring is done by changing the signs
+ * of odd-numbered rows.
+ * Partial iMCUs at the bottom edge are copied verbatim.
+ */
+ 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_height = MCU_rows * 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 ( dst_blk_y < comp_height )
+ {
+ /* Row is within the mirrorable area. */
+ src_buffer = ( *srcinfo->mem->access_virt_barray )
+ ( (j_common_ptr)srcinfo,
src_coef_arrays[ci],
+ comp_height - dst_blk_y -
+ (JDIMENSION)compptr->v_samp_factor,
+ (JDIMENSION)compptr->v_samp_factor, FALSE
);
+ }
+ else
+ {
+ /* Bottom-edge blocks will be copied verbatim. */
+ src_buffer = ( *srcinfo->mem->access_virt_barray )
+ ( (j_common_ptr)srcinfo,
src_coef_arrays[ci],
+ dst_blk_y,
+ (JDIMENSION)compptr->v_samp_factor, FALSE
);
+ }
+ for ( offset_y = 0; offset_y < compptr->v_samp_factor;
offset_y++ )
+ {
+ if ( dst_blk_y < comp_height )
+ {
+ /* Row is within the mirrorable area. */
+ dst_row_ptr = dst_buffer[offset_y];
+ src_row_ptr = src_buffer[compptr->v_samp_factor -
offset_y - 1];
+ for ( dst_blk_x = 0; dst_blk_x <
compptr->width_in_blocks;
+ dst_blk_x++ )
+ {
+ dst_ptr = dst_row_ptr[dst_blk_x];
+ src_ptr = src_row_ptr[dst_blk_x];
+ for ( i = 0; i < DCTSIZE; i += 2 )
+ {
+ /* copy even row */
+ for ( j = 0; j < DCTSIZE; j++ )
+ *dst_ptr++ = *src_ptr++;
+ /* copy odd row with sign change */
+ for ( j = 0; j < DCTSIZE; j++ )
+ *dst_ptr++ = -*src_ptr++;
+ }
+ }
+ }
+ else
+ {
+ /* Just copy row verbatim. */
+ jcopy_block_row( src_buffer[offset_y],
+ dst_buffer[offset_y],
+ compptr->width_in_blocks );
+ }
+ }
+ }
+ }
+}
+
+LOCAL( void )
+do_transpose( j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ jvirt_barray_ptr * src_coef_arrays,
+ jvirt_barray_ptr * dst_coef_arrays ) {
+/* Transpose source into destination */
+ JDIMENSION dst_blk_x, dst_blk_y;
+ int ci, i, j, offset_x, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info * compptr;
+
+ /* Transposing pixels within a block just requires transposing the
+ * DCT coefficients.
+ * Partial iMCUs at the edges require no special treatment; we simply
+ * process all the available DCT blocks for every component.
+ */
+ for ( ci = 0; ci < dstinfo->num_components; ci++ )
+ {
+ compptr = dstinfo->comp_info + ci;
+ 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 );
+ for ( offset_y = 0; offset_y < compptr->v_samp_factor;
offset_y++ )
+ {
+ for ( dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+ dst_blk_x += compptr->h_samp_factor )
+ {
+ src_buffer = ( *srcinfo->mem->access_virt_barray )
+ ( (j_common_ptr)srcinfo,
src_coef_arrays[ci],
+ dst_blk_x,
+ (JDIMENSION)compptr->h_samp_factor,
FALSE );
+ for ( offset_x = 0; offset_x < compptr->h_samp_factor;
offset_x++ )
+ {
+ dst_ptr = dst_buffer[offset_y][dst_blk_x +
offset_x];
+ src_ptr = src_buffer[offset_x][dst_blk_y +
offset_y];
+ for ( i = 0; i < DCTSIZE; i++ )
+ for ( j = 0; j < DCTSIZE; j++ )
+ dst_ptr[j * DCTSIZE + i] = src_ptr[i *
DCTSIZE + j];
+ }
+ }
+ }
+ }
+ }
+}
+
+LOCAL( void )
+do_rot_90( j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ 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.
+ */
+ JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
+ int ci, i, j, offset_x, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info * compptr;
+
+ /* Because of the horizontal mirror step, we can't process partial
iMCUs
+ * at the (output) right edge properly. They just get transposed and
+ * not mirrored.
+ */
+ MCU_cols = srcinfo->output_height /
+ ( dstinfo->max_h_samp_factor *
dstinfo->min_DCT_h_scaled_size );
+
+ for ( ci = 0; ci < dstinfo->num_components; ci++ )
+ {
+ compptr = dstinfo->comp_info + ci;
+ comp_width = MCU_cols * compptr->h_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 );
+ for ( offset_y = 0; offset_y < compptr->v_samp_factor;
offset_y++ )
+ {
+ for ( dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+ dst_blk_x += compptr->h_samp_factor )
+ {
+ if ( dst_blk_x < comp_width )
+ {
+ /* Block is within the mirrorable area. */
+ src_buffer = ( *srcinfo->mem->access_virt_barray )
+ ( (j_common_ptr)srcinfo,
src_coef_arrays[ci],
+ comp_width - dst_blk_x -
+
(JDIMENSION)compptr->h_samp_factor,
+
(JDIMENSION)compptr->h_samp_factor, FALSE );
+ }
+ else
+ {
+ /* Edge blocks are transposed but not mirrored. */
+ src_buffer = ( *srcinfo->mem->access_virt_barray )
+ ( (j_common_ptr)srcinfo,
src_coef_arrays[ci],
+ dst_blk_x,
+
(JDIMENSION)compptr->h_samp_factor, FALSE );
+ }
+ for ( offset_x = 0; offset_x < compptr->h_samp_factor;
offset_x++ )
+ {
+ dst_ptr = dst_buffer[offset_y][dst_blk_x +
offset_x];
+ if ( dst_blk_x < comp_width )
+ {
+ /* Block is within the mirrorable area. */
+ src_ptr = src_buffer[compptr->h_samp_factor -
offset_x - 1]
+ [dst_blk_y + offset_y];
+ for ( i = 0; i < DCTSIZE; i++ )
+ {
+ for ( j = 0; j < DCTSIZE; j++ )
+ dst_ptr[j * DCTSIZE + i] = src_ptr[i *
DCTSIZE + j];
+ i++;
+ for ( j = 0; j < DCTSIZE; j++ )
+ dst_ptr[j * DCTSIZE + i] = -src_ptr[i
* DCTSIZE + j];
+ }
+ }
+ else
+ {
+ /* Edge blocks are transposed but not
mirrored. */
+ src_ptr = src_buffer[offset_x]
+ [dst_blk_y + offset_y];
+ for ( i = 0; i < DCTSIZE; i++ )
+ for ( j = 0; j < DCTSIZE; j++ )
+ dst_ptr[j * DCTSIZE + i] = src_ptr[i *
DCTSIZE + j];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+LOCAL( void )
+do_rot_270( j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ 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.
+ */
+ JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
+ int ci, i, j, offset_x, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info * compptr;
+
+ /* Because of the horizontal mirror step, we can't process partial
iMCUs
+ * at the (output) bottom edge properly. They just get transposed and
+ * not mirrored.
+ */
+ MCU_rows = srcinfo->output_width /
+ ( 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_height = MCU_rows * 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 );
+ for ( offset_y = 0; offset_y < compptr->v_samp_factor;
offset_y++ )
+ {
+ for ( dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+ dst_blk_x += compptr->h_samp_factor )
+ {
+ src_buffer = ( *srcinfo->mem->access_virt_barray )
+ ( (j_common_ptr)srcinfo,
src_coef_arrays[ci],
+ dst_blk_x,
+ (JDIMENSION)compptr->h_samp_factor,
FALSE );
+ for ( offset_x = 0; offset_x < compptr->h_samp_factor;
offset_x++ )
+ {
+ dst_ptr = dst_buffer[offset_y][dst_blk_x +
offset_x];
+ if ( dst_blk_y < comp_height )
+ {
+ /* Block is within the mirrorable area. */
+ src_ptr = src_buffer[offset_x]
+ [comp_height - dst_blk_y - offset_y
- 1];
+ for ( i = 0; i < DCTSIZE; i++ )
+ {
+ for ( j = 0; j < DCTSIZE; j++ )
+ {
+ dst_ptr[j * DCTSIZE + i] = src_ptr[i *
DCTSIZE + j];
+ j++;
+ dst_ptr[j * DCTSIZE + i] = -src_ptr[i
* DCTSIZE + j];
+ }
+ }
+ }
+ else
+ {
+ /* Edge blocks are transposed but not
mirrored. */
+ src_ptr = src_buffer[offset_x]
+ [dst_blk_y + offset_y];
+ for ( i = 0; i < DCTSIZE; i++ )
+ for ( j = 0; j < DCTSIZE; j++ )
+ dst_ptr[j * DCTSIZE + i] = src_ptr[i *
DCTSIZE + j];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+LOCAL( void )
+do_rot_180( j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ 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.
+ */
+ JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x,
dst_blk_y;
+ int ci, i, j, 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;
+ 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 ( dst_blk_y < comp_height )
+ {
+ /* Row is within the vertically mirrorable area. */
+ src_buffer = ( *srcinfo->mem->access_virt_barray )
+ ( (j_common_ptr)srcinfo,
src_coef_arrays[ci],
+ comp_height - dst_blk_y -
+ (JDIMENSION)compptr->v_samp_factor,
+ (JDIMENSION)compptr->v_samp_factor, FALSE
);
+ }
+ else
+ {
+ /* Bottom-edge rows are only mirrored horizontally. */
+ src_buffer = ( *srcinfo->mem->access_virt_barray )
+ ( (j_common_ptr)srcinfo,
src_coef_arrays[ci],
+ dst_blk_y,
+ (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];
+ if ( dst_blk_y < comp_height )
+ {
+ /* Row is within the mirrorable area. */
+ src_row_ptr = src_buffer[compptr->v_samp_factor -
offset_y - 1];
+ for ( dst_blk_x = 0; dst_blk_x <
compptr->width_in_blocks; dst_blk_x++ )
+ {
+ dst_ptr = dst_row_ptr[dst_blk_x];
+ if ( dst_blk_x < comp_width )
+ {
+ /* Process the blocks that can be mirrored
both ways. */
+ src_ptr = src_row_ptr[comp_width - dst_blk_x -
1];
+ for ( i = 0; i < DCTSIZE; i += 2 )
+ {
+ /* For even row, negate every odd column.
*/
+ for ( j = 0; j < DCTSIZE; j += 2 )
+ {
+ *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++;
+ }
+ }
+ }
+ else
+ {
+ /* Any remaining right-edge blocks are only
mirrored vertically. */
+ src_ptr = src_row_ptr[dst_blk_x];
+ for ( i = 0; i < DCTSIZE; i += 2 )
+ {
+ for ( j = 0; j < DCTSIZE; j++ )
+ *dst_ptr++ = *src_ptr++;
+ for ( j = 0; j < DCTSIZE; j++ )
+ *dst_ptr++ = -*src_ptr++;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Remaining rows are just mirrored horizontally. */
+ src_row_ptr = src_buffer[offset_y];
+ for ( dst_blk_x = 0; dst_blk_x <
compptr->width_in_blocks; dst_blk_x++ )
+ {
+ if ( dst_blk_x < comp_width )
+ {
+ /* Process the blocks that can be mirrored. */
+ dst_ptr = dst_row_ptr[dst_blk_x];
+ src_ptr = src_row_ptr[comp_width - dst_blk_x -
1];
+ for ( i = 0; i < DCTSIZE2; i += 2 )
+ {
+ *dst_ptr++ = *src_ptr++;
+ *dst_ptr++ = -*src_ptr++;
+ }
+ }
+ else
+ {
+ /* Any remaining right-edge blocks are only
copied. */
+ jcopy_block_row( src_row_ptr + dst_blk_x,
+ dst_row_ptr + dst_blk_x,
+ (JDIMENSION)1 );
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+LOCAL( void )
+do_transverse( j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ 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.
+ */
+ JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x,
dst_blk_y;
+ int ci, i, j, offset_x, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info * compptr;
+
+ MCU_cols = srcinfo->output_height /
+ ( dstinfo->max_h_samp_factor *
dstinfo->min_DCT_h_scaled_size );
+ MCU_rows = srcinfo->output_width /
+ ( 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;
+ 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 );
+ for ( offset_y = 0; offset_y < compptr->v_samp_factor;
offset_y++ )
+ {
+ for ( dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+ dst_blk_x += compptr->h_samp_factor )
+ {
+ if ( dst_blk_x < comp_width )
+ {
+ /* Block is within the mirrorable area. */
+ src_buffer = ( *srcinfo->mem->access_virt_barray )
+ ( (j_common_ptr)srcinfo,
src_coef_arrays[ci],
+ comp_width - dst_blk_x -
+
(JDIMENSION)compptr->h_samp_factor,
+
(JDIMENSION)compptr->h_samp_factor, FALSE );
+ }
+ else
+ {
+ src_buffer = ( *srcinfo->mem->access_virt_barray )
+ ( (j_common_ptr)srcinfo,
src_coef_arrays[ci],
+ dst_blk_x,
+
(JDIMENSION)compptr->h_samp_factor, FALSE );
+ }
+ for ( offset_x = 0; offset_x < compptr->h_samp_factor;
offset_x++ )
+ {
+ dst_ptr = dst_buffer[offset_y][dst_blk_x +
offset_x];
+ if ( dst_blk_y < comp_height )
+ {
+ if ( dst_blk_x < comp_width )
+ {
+ /* Block is within the mirrorable area. */
+ src_ptr =
src_buffer[compptr->h_samp_factor - offset_x - 1]
+ [comp_height - dst_blk_y -
offset_y - 1];
+ for ( i = 0; i < DCTSIZE; i++ )
+ {
+ for ( j = 0; j < DCTSIZE; j++ )
+ {
+ dst_ptr[j * DCTSIZE + i] =
src_ptr[i * DCTSIZE + j];
+ j++;
+ dst_ptr[j * DCTSIZE + i] =
-src_ptr[i * DCTSIZE + j];
+ }
+ i++;
+ for ( j = 0; j < DCTSIZE; j++ )
+ {
+ dst_ptr[j * DCTSIZE + i] =
-src_ptr[i * DCTSIZE + j];
+ j++;
+ dst_ptr[j * DCTSIZE + i] =
src_ptr[i * DCTSIZE + j];
+ }
+ }
+ }
+ else
+ {
+ /* Right-edge blocks are mirrored in y
only */
+ src_ptr = src_buffer[offset_x]
+ [comp_height - dst_blk_y -
offset_y - 1];
+ for ( i = 0; i < DCTSIZE; i++ )
+ {
+ for ( j = 0; j < DCTSIZE; j++ )
+ {
+ dst_ptr[j * DCTSIZE + i] =
src_ptr[i * DCTSIZE + j];
+ j++;
+ dst_ptr[j * DCTSIZE + i] =
-src_ptr[i * DCTSIZE + j];
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( dst_blk_x < comp_width )
+ {
+ /* Bottom-edge blocks are mirrored in x
only */
+ src_ptr =
src_buffer[compptr->h_samp_factor - offset_x - 1]
+ [dst_blk_y + offset_y];
+ for ( i = 0; i < DCTSIZE; i++ )
+ {
+ for ( j = 0; j < DCTSIZE; j++ )
+ dst_ptr[j * DCTSIZE + i] =
src_ptr[i * DCTSIZE + j];
+ i++;
+ for ( j = 0; j < DCTSIZE; j++ )
+ dst_ptr[j * DCTSIZE + i] =
-src_ptr[i * DCTSIZE + j];
+ }
+ }
+ else
+ {
+ /* At lower right corner, just transpose,
no mirroring */
+ src_ptr = src_buffer[offset_x]
+ [dst_blk_y + offset_y];
+ for ( i = 0; i < DCTSIZE; i++ )
+ for ( j = 0; j < DCTSIZE; j++ )
+ dst_ptr[j * DCTSIZE + i] =
src_ptr[i * DCTSIZE + j];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* 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!
+ */
+
+LOCAL( void )
+jtransform_execute_transform( j_decompress_ptr srcinfo,
+ j_compress_ptr dstinfo,
+ jvirt_barray_ptr * src_coef_arrays,
+ jpeg_transform_info * info ) {
+ jvirt_barray_ptr * dst_coef_arrays = info->workspace_coef_arrays;
+
+ /* Note: conditions tested here should match those in switch statement
+ * in jtransform_request_workspace()
+ */
+ switch ( info->transform )
+ {
+ case JXFORM_FLIP_H:
+ do_flip_h( srcinfo, dstinfo, src_coef_arrays );
+ break;
+ case JXFORM_FLIP_V:
+ do_flip_v( srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays );
+ break;
+ case JXFORM_TRANSPOSE:
+ do_transpose( srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays );
+ break;
+ case JXFORM_TRANSVERSE:
+ do_transverse( srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays
);
+ break;
+ case JXFORM_ROT_90:
+ do_rot_90( srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays );
+ break;
+ case JXFORM_ROT_180:
+ do_rot_180( srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays );
+ break;
+ case JXFORM_ROT_270:
+ do_rot_270( srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays );
+ break;
+ }
+}
+
+/* End of code to handle Auto Orient */
+
/*
* This function must be fed with a complete compressed frame.
*/
@@ -186,8 +1356,15 @@ static picture_t * DecodeBlock ( decoder_t * p_dec,
block_t * * pp_block )
decoder_sys_t * p_sys = p_dec->p_sys;
block_t * p_block;
picture_t * p_pic = 0;
-
+ bool b_autoorient;
+ int i_otag;
JSAMPARRAY p_row_pointers = NULL;
+ jpeg_transform_info transformoption;
+ struct jpeg_compress_struct dinfo = { 0 };
+ unsigned char * p_dmem = NULL;
+ unsigned long l_dmem_size = 0;
+ jvirt_barray_ptr * src_coef_arrays;
+ jvirt_barray_ptr * dst_coef_arrays;
if ( !pp_block || !*pp_block )
{
@@ -209,12 +1386,77 @@ static picture_t * DecodeBlock ( decoder_t * p_dec,
block_t * * pp_block )
goto error;
}
+ /*
+ We only initialise dinfo if we need to rotate a jpeg.
+ Make sure we don't try to destroy an uninitialised structure
+ if an error occurs
+ */
+ dinfo.mem = NULL;
+
jpeg_create_decompress( &p_sys->p_jpeg );
jpeg_mem_src( &p_sys->p_jpeg, p_block->p_buffer, p_block->i_buffer );
- jpeg_read_header( &p_sys->p_jpeg, TRUE );
+ b_autoorient = var_CreateGetBool( p_dec, "jpeg-autoorient" );
+
+ if ( b_autoorient )
+ {
+ jpeg_save_markers( &p_sys->p_jpeg, EXIF_JPEG_MARKER, 0xffff );
+ }
+ jpeg_read_header( &p_sys->p_jpeg, TRUE );
p_sys->p_jpeg.out_color_space = JCS_RGB;
+ if ( b_autoorient )
+ {
+ i_otag = jpeg_GetOrientation( &p_sys->p_jpeg );
+ if ( i_otag > 1 ) /* Do we need to orient the image? */
+ {
+ msg_Info( p_dec, "Orientation is %d", i_otag );
+ switch ( i_otag )
+ {
+ case 2:
+ transformoption.transform = JXFORM_FLIP_H;
+ break;
+ case 3:
+ transformoption.transform = JXFORM_ROT_180;
+ break;
+ case 4:
+ transformoption.transform = JXFORM_FLIP_V;
+ break;
+ case 5:
+ transformoption.transform = JXFORM_TRANSPOSE;
+ break;
+ case 6:
+ transformoption.transform = JXFORM_ROT_90;
+ break;
+ case 7:
+ transformoption.transform = JXFORM_TRANSVERSE;
+ break;
+ case 8:
+ default:
+ transformoption.transform = JXFORM_ROT_270;
+ }
+ dinfo.err = jpeg_std_error( &p_sys->err );
+ jpeg_create_compress( &dinfo );
+ jpeg_copy_critical_parameters( &p_sys->p_jpeg, &dinfo );
+ jtransform_request_workspace( &p_sys->p_jpeg, &transformoption
);
+ src_coef_arrays = jpeg_read_coefficients( &p_sys->p_jpeg );
+ dst_coef_arrays = jtransform_adjust_parameters( &dinfo,
src_coef_arrays, &transformoption );
+ jpeg_mem_dest( &dinfo, &p_dmem, &l_dmem_size );
+ jpeg_write_coefficients( &dinfo, dst_coef_arrays );
+ jtransform_execute_transform( &p_sys->p_jpeg, &dinfo,
src_coef_arrays, &transformoption );
+ jpeg_finish_compress( &dinfo );
+ jpeg_abort_decompress( &p_sys->p_jpeg );
+
+ /* Assign any change in height/width */
+ p_sys->p_jpeg.image_width = dinfo.image_width;
+ p_sys->p_jpeg.image_height = dinfo.image_height;
+
+ /* Restart processing with orientated image data */
+ jpeg_mem_src( &p_sys->p_jpeg, p_dmem, l_dmem_size );
+ jpeg_read_header( &p_sys->p_jpeg, TRUE );
+ }
+ }
+
jpeg_start_decompress( &p_sys->p_jpeg );
/* Set output properties */
@@ -236,10 +1478,12 @@ static picture_t * DecodeBlock ( decoder_t * p_dec,
block_t * * pp_block )
/* Decode picture */
p_row_pointers = malloc( sizeof( JSAMPROW ) *
p_sys->p_jpeg.output_height );
+
if ( !p_row_pointers )
{
goto error;
}
+
for ( unsigned i = 0; i < p_sys->p_jpeg.output_height; i++ )
{
p_row_pointers[i] = p_pic->p->p_pixels + p_pic->p->i_pitch * i;
@@ -253,19 +1497,26 @@ static picture_t * DecodeBlock ( decoder_t * p_dec,
block_t * * pp_block )
}
jpeg_finish_decompress( &p_sys->p_jpeg );
+ jpeg_destroy_compress( &dinfo );
jpeg_destroy_decompress( &p_sys->p_jpeg );
+ if ( l_dmem_size )
+ {
+ free( p_dmem );
+ }
free( p_row_pointers );
-
p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts :
p_block->i_dts;
-
block_Release( p_block );
return p_pic;
error:
+ jpeg_destroy_compress( &dinfo );
jpeg_destroy_decompress( &p_sys->p_jpeg );
+ if ( l_dmem_size )
+ {
+ free( p_dmem );
+ }
free( p_row_pointers );
-
block_Release( p_block );
return NULL;
}
--
2.7.4
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20160415/740fa074/attachment-0001.html>
More information about the vlc-devel
mailing list