[vlc-devel] [PATCH] Automatically orient JPEG image based on orientation flag, if set
Jean-Baptiste Kempf
jb at videolan.org
Sun Apr 17 07:44:42 CEST 2016
On 17 Apr, Wayne McDougall wrote :
> +#define DEC_CFG_PREFIX "jpeg-"
> +#define DEC_AUTOORIENT_TEXT N_( "Automatic Orientation" )
> +#define DEC_AUTOORIENT_LONGTEXT N_( "Automatic orientation based on EXIF
> orientation flag." )
In what case don't we want it automatic, tbh?
> +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;
> +}
I'm surprised we don't have the right function in vlc_common.h
(GetWBE/GetWLE)
> +/* 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 */
> +}
> +
> /*
> * This function must be fed with a complete compressed frame.
> */
> @@ -186,8 +389,9 @@ 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;
> -
> JSAMPARRAY p_row_pointers = NULL;
> + bool b_autoorient;
> + int i_otag;
>
> if ( !pp_block || !*pp_block )
> {
> @@ -211,10 +415,49 @@ static picture_t * DecodeBlock ( decoder_t * p_dec,
> block_t * * pp_block )
>
> 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" );
var_InheritBool
> + if ( b_autoorient )
> + {
> + i_otag = jpeg_GetOrientation( &p_sys->p_jpeg );
> + if ( i_otag > 1 )
> + {
> + msg_Info( p_dec, "Orientation is %d", i_otag );
> + switch ( i_otag )
> + {
> + case 2:
> + p_dec->fmt_out.video.orientation = ORIENT_TOP_RIGHT;
> + break;
> + case 3:
> + p_dec->fmt_out.video.orientation = ORIENT_BOTTOM_RIGHT;
> + break;
> + case 4:
> + p_dec->fmt_out.video.orientation = ORIENT_BOTTOM_LEFT;
> + break;
> + case 5:
> + p_dec->fmt_out.video.orientation = ORIENT_LEFT_TOP;
> + break;
> + case 6:
> + p_dec->fmt_out.video.orientation = ORIENT_ROTATED_90;
> + break;
> + case 7:
> + p_dec->fmt_out.video.orientation = ORIENT_RIGHT_BOTTOM;
> + break;
> + case 8:
> + default:
> + p_dec->fmt_out.video.orientation = ORIENT_ROTATED_270;
> + }
> + }
> + }
> +
This looks good!
With my kindest regards,
--
Jean-Baptiste Kempf
http://www.jbkempf.com/ - +33 672 704 734
Sent from my Electronic Device
More information about the vlc-devel
mailing list