How to auto-rotate images based on EXIF information

Image viewers on the computer, in smartphones or cameras can today read the orientation information in the EXIF data of an image and auto-rotate an image when displaying it to you. However, you might want some images to be actually stored in the orientation specified in their EXIF data. For example, this helps to render correctly in old or simpler image viewers that ignore the EXIF orientation information. EXIFTran is a tool that can help you achieve this.

  • Installing it is easy:
$ sudo apt install exiftran
  • To do in-place auto-rotate of images based on their EXIF orientation:
$ exiftran -a -i *.JPEG

Tried with: EXIFTran 2.10 and Ubuntu 16.04

Advertisements

Orientation

Orientation is a fundamental concept in computational geometry. It is the most important predicate too. Calculating the orientation of a triangle (2D), tetrahedron (3D) or pentachoron (4D) reduces to the calculation of the sign of a determinant. The following code is in C++, but can easily be adapted to any language.

First, it is helpful to define an orientation type:

enum ORIENT_TYPE
{
	ORIENT_NEG	= -1,
	ORIENT_ZERO	= +0,
	ORIENT_POS	= +1,
};

ORIENT_ZERO indicates a degeneracy in the simplex. For example, in 2D this means that the 3 points are collinear. This is typically not preferred and symbolic perturbation techniques like Simulation of Simplicity might have to be used to handle such cases.

A helper function to convert a determinant value to orientation:

ORIENT_TYPE detToOrient( const int det )
{
	return ( det > 0 ) ? ORIENT_POS : ( ( det < 0 ) ? ORIENT_NEG : ORIENT_ZERO );
}

2D Orientation:

ORIENT_TYPE orientation2
(
	const int* p0,
	const int* p1,
	const int* p2
)
{
	// | m00 m01 |
	// | m10 m11 |

	const int m00 = p1[0] - p0[0];
	const int m01 = p1[1] - p0[1];

	const int m10 = p2[0] - p0[0];
	const int m11 = p2[1] - p0[1];

	const int det = ( m00 * m11 ) - ( m10 * m01 );

	return detToOrient( det );
}

3D Orientation:

ORIENT_TYPE orientation3
(
	const int* p0,
	const int* p1,
	const int* p2,
	const int* p3
)
{
	// | m00 m01 m02 |
	// | m10 m11 m12 |
	// | m20 m21 m22 |

	const int m00 = p1[0] - p0[0];
	const int m01 = p1[1] - p0[1];
	const int m02 = p1[2] - p0[2];

	const int m10 = p2[0] - p0[0];
	const int m11 = p2[1] - p0[1];
	const int m12 = p2[2] - p0[2];

	const int m20 = p3[0] - p0[0];
	const int m21 = p3[1] - p0[1];
	const int m22 = p3[2] - p0[2];

	const int m00Det = ( m11 * m22 ) - ( m21 * m12 );
	const int m01Det = ( m10 * m22 ) - ( m20 * m12 );
	const int m02Det = ( m10 * m21 ) - ( m20 * m11 );

	const int det = ( m00 * m00Det ) - ( m01 * m01Det ) + ( m02 * m02Det );

	return detToOrient( det );
}

4D Orientation:

ORIENT_TYPE orientation4
(
	const int* p0,
	const int* p1,
	const int* p2,
	const int* p3,
	const int* p4
)
{
	// | m00 m01 m02 m03 |
	// | m10 m11 m12 m13 |
	// | m20 m21 m22 m23 |
	// | m30 m31 m32 m33 |

	const int m00 = p1[0] - p0[0];
	const int m01 = p2[0] - p0[0];
	const int m02 = p3[0] - p0[0];
	const int m03 = p4[0] - p0[0];

	const int m10 = p1[1] - p0[1];
	const int m11 = p2[1] - p0[1];
	const int m12 = p3[1] - p0[1];
	const int m13 = p4[1] - p0[1];

	const int m20 = p1[2] - p0[2];
	const int m21 = p2[2] - p0[2];
	const int m22 = p3[2] - p0[2];
	const int m23 = p4[2] - p0[2];

	const int m30 = p1[3] - p0[3];
	const int m31 = p2[3] - p0[3];
	const int m32 = p3[3] - p0[3];
	const int m33 = p4[3] - p0[3];

	const int m00m11Det = ( m22 * m33 ) - ( m32 * m23 );
	const int m00m12Det = ( m21 * m33 ) - ( m31 * m23 );
	const int m00m13Det = ( m21 * m32 ) - ( m31 * m22 );

	const int m01m10Det = m00m11Det;
	const int m01m12Det = ( m20 * m33 ) - ( m30 * m23 );
	const int m01m13Det = ( m20 * m32 ) - ( m30 * m22 );

	const int m02m10Det = m00m12Det;
	const int m02m11Det = m01m12Det;
	const int m02m13Det = ( m20 * m31 ) - ( m30 * m21 );

	const int m03m10Det = m00m13Det;
	const int m03m11Det = m01m13Det;
	const int m03m12Det = m02m13Det;

	const int m00Det =
		+ ( m11 * m00m11Det )
		- ( m12 * m00m12Det )
		+ ( m13 * m00m13Det );

	const int m01Det =
		+ ( m10 * m01m10Det )
		- ( m12 * m01m12Det )
		+ ( m13 * m01m13Det );

	const int m02Det =
		+ ( m10 * m02m10Det )
		- ( m11 * m02m11Det )
		+ ( m13 * m02m13Det );

	const int m03Det =
		+ ( m10 * m03m10Det )
		- ( m11 * m03m11Det )
		+ ( m12 * m03m12Det );

	const int det =
		+ ( m00 * m00Det )
		- ( m01 * m01Det )
		+ ( m02 * m02Det )
		- ( m03 * m03Det );

	return detToOrient( det );
}