PHP read_exif_data and Adjust Orientation

PhpOrientationExif

Php Problem Overview


I am using the following code to rotate an uploaded jpeg image if the orientation is off. I am only having problems with images uploaded from iPhones and Android.

if(move_uploaded_file($_FILES['photo']['tmp_name'], $upload_path . $newfilename)){
			chmod($upload_path . $newfilename, 0755);
			$exif = exif_read_data($upload_path . $newfilename);
			$ort = $exif['IFD0']['Orientation'];
			switch($ort)
			{
			
				case 3: // 180 rotate left
					$image->imagerotate($upload_path . $newfilename, 180, -1);
					break;
			
			
				case 6: // 90 rotate right
					$image->imagerotate($upload_path . $newfilename, -90, -1);
					break;
			
				case 8:    // 90 rotate left
					$image->imagerotate($upload_path . $newfilename, 90, -1);
					break;
			}
			imagejpeg($image, $upload_path . $newfilename, 100);
			$success_message = 'Photo Successfully Uploaded';
		}else{
			$error_count++;
			$error_message = 'Error: Upload Unsuccessful<br />Please Try Again';
		}

Am I doing something wrong with the way I am reading the EXIF data from the jpeg? It is not rotating the images as it is supposed to.

This is what happens when I run a var_dump($exif);

array(41) {
	["FileName"]=> string(36) "126e7c0efcac2b76b3320e6187d03cfd.JPG"
	["FileDateTime"]=> int(1316545667)
	["FileSize"]=> int(1312472)
	["FileType"]=> int(2)
	["MimeType"]=> string(10) "image/jpeg"
	["SectionsFound"]=> string(30) "ANY_TAG, IFD0, THUMBNAIL, EXIF"
	["COMPUTED"]=> array(8) {
		["html"]=> string(26) "width="2048" height="1536""
		["Height"]=> int(1536)
		["Width"]=> int(2048)
		["IsColor"]=> int(1)
		["ByteOrderMotorola"]=> int(1)
		["ApertureFNumber"]=> string(5) "f/2.8"
		["Thumbnail.FileType"]=> int(2)
		["Thumbnail.MimeType"]=> string(10) "image/jpeg" }
		["Make"]=> string(5) "Apple"
		["Model"]=> string(10) "iPhone 3GS"
		["Orientation"]=> int(6)
		["XResolution"]=> string(4) "72/1"
            ["YResolution"]=> string(4) "72/1" ["ResolutionUnit"]=> int(2) ["Software"]=> string(5) "4.3.5" ["DateTime"]=> string(19) "2011:09:16 21:18:46" ["YCbCrPositioning"]=> int(1) ["Exif_IFD_Pointer"]=> int(194) ["THUMBNAIL"]=> array(6) { ["Compression"]=> int(6) ["XResolution"]=> string(4) "72/1" ["YResolution"]=> string(4) "72/1" ["ResolutionUnit"]=> int(2) ["JPEGInterchangeFormat"]=> int(658) ["JPEGInterchangeFormatLength"]=> int(8231) } ["ExposureTime"]=> string(4) "1/15" ["FNumber"]=> string(4) "14/5" ["ExposureProgram"]=> int(2) ["ISOSpeedRatings"]=> int(200) ["ExifVersion"]=> string(4) "0221" ["DateTimeOriginal"]=> string(19) "2011:09:16 21:18:46" ["DateTimeDigitized"]=> string(19) "2011:09:16 21:18:46" ["ComponentsConfiguration"]=> string(4) "" ["ShutterSpeedValue"]=> string(8) "3711/949" ["ApertureValue"]=> string(9) "4281/1441" ["MeteringMode"]=> int(1) ["Flash"]=> int(32) ["FocalLength"]=> string(5) "77/20" ["SubjectLocation"]=> array(4) { [0]=> int(1023) [1]=> int(767) [2]=> int(614) [3]=> int(614) } ["FlashPixVersion"]=> string(4) "0100" ["ColorSpace"]=> int(1) ["ExifImageWidth"]=> int(2048) ["ExifImageLength"]=> int(1536) ["SensingMethod"]=> int(2) ["ExposureMode"]=> int(0) ["WhiteBalance"]=> int(0) ["SceneCaptureType"]=> int(0) ["Sharpness"]=> int(1) }

Php Solutions


Solution 1 - Php

Based on Daniel's code I wrote a function that simply rotates an image if necessary, without resampling.

GD

function image_fix_orientation(&$image, $filename) {
	$exif = exif_read_data($filename);
	
	if (!empty($exif['Orientation'])) {
		switch ($exif['Orientation']) {
			case 3:
				$image = imagerotate($image, 180, 0);
				break;
			
			case 6:
				$image = imagerotate($image, 90, 0);
				break;
			
			case 8:
				$image = imagerotate($image, -90, 0);
				break;
		}
	}
}

One line version (GD)

function image_fix_orientation(&$image, $filename) {
	$image = imagerotate($image, array_values([0, 0, 0, 180, 0, 0, -90, 0, 90])[@exif_read_data($filename)['Orientation'] ?: 0], 0);
}

ImageMagick

function image_fix_orientation($image) {
	if (method_exists($image, 'getImageProperty')) {
		$orientation = $image->getImageProperty('exif:Orientation');
	} else {
		$filename = $image->getImageFilename();
		
		if (empty($filename)) {
			$filename = 'data://image/jpeg;base64,' . base64_encode($image->getImageBlob());
		}
		
		$exif = exif_read_data($filename);
		$orientation = isset($exif['Orientation']) ? $exif['Orientation'] : null;
	}
	
	if (!empty($orientation)) {
		switch ($orientation) {
			case 3:
				$image->rotateImage('#000000', 180);
				break;
			
			case 6:
				$image->rotateImage('#000000', 90);
				break;
			
			case 8:
				$image->rotateImage('#000000', -90);
				break;
		}
	}
}

Solution 2 - Php

The documentation for imagerotate refers to a different type for the first parameter than you use:

> An image resource, returned by one of the image creation functions, > such as imagecreatetruecolor().

Here is a small example for using this function:

function resample($jpgFile, $thumbFile, $width, $orientation) {
    // Get new dimensions
    list($width_orig, $height_orig) = getimagesize($jpgFile);
    $height = (int) (($width / $width_orig) * $height_orig);
    // Resample
    $image_p = imagecreatetruecolor($width, $height);
    $image   = imagecreatefromjpeg($jpgFile);
    imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);
    // Fix Orientation
    switch($orientation) {
		case 3:
			$image_p = imagerotate($image_p, 180, 0);
			break;
		case 6:
			$image_p = imagerotate($image_p, 90, 0);
			break;
		case 8:
			$image_p = imagerotate($image_p, -90, 0);
			break;
	}
    // Output
    imagejpeg($image_p, $thumbFile, 90);
}

Solution 3 - Php

Simpler function for those uploading an image, it just autorotates if necessary.

function image_fix_orientation($filename) {
    $exif = exif_read_data($filename);
    if (!empty($exif['Orientation'])) {
		$image = imagecreatefromjpeg($filename);
		switch ($exif['Orientation']) {
			case 3:
				$image = imagerotate($image, 180, 0);
				break;

			case 6:
				$image = imagerotate($image, 90, 0);
				break;

			case 8:
				$image = imagerotate($image, -90, 0);
				break;
		}

		imagejpeg($image, $filename, 90);
    }
}

Solution 4 - Php

Why is nobody considering mirrored cases 2,4,5,7? There are 4 more cases in exif orientation land:

enter image description here

Here is a complete solution taking a filename:

function __image_orientate($source, $quality = 90, $destination = null)
{
    if ($destination === null) {
        $destination = $source;
    }
    $info = getimagesize($source);
    if ($info['mime'] === 'image/jpeg') {
        $exif = exif_read_data($source);
        if (!empty($exif['Orientation']) && in_array($exif['Orientation'], [2, 3, 4, 5, 6, 7, 8])) {
            $image = imagecreatefromjpeg($source);
            if (in_array($exif['Orientation'], [3, 4])) {
                $image = imagerotate($image, 180, 0);
            }
            if (in_array($exif['Orientation'], [5, 6])) {
                $image = imagerotate($image, -90, 0);
            }
            if (in_array($exif['Orientation'], [7, 8])) {
                $image = imagerotate($image, 90, 0);
            }
            if (in_array($exif['Orientation'], [2, 5, 7, 4])) {
                imageflip($image, IMG_FLIP_HORIZONTAL);
            }
            imagejpeg($image, $destination, $quality);
        }
    }
    return true;
}

Solution 5 - Php

Just in case someone comes across this. From what I can make out some of the switch statements above are wrong.

Based on information here, it should be:

switch ($exif['Orientation']) {
    case 3:
        $image = imagerotate($image, -180, 0);
        break;
    case 6:
        $image = imagerotate($image, 90, 0);
        break;
    case 8:
        $image = imagerotate($image, -90, 0);
        break;
} 

Solution 6 - Php

It's probably worthwhile to mention that if you are using ImageMagick from command line, you can use the -auto-orient option which will auto rotate the image based on the existing EXIF orientation data.

convert -auto-orient /tmp/uploadedImage.jpg /save/to/path/image.jpg

Please note: If the EXIF data was stripped before the process, it will not work as described.

Solution 7 - Php

I hate to chime in with yet another set of orientation values, but in my experience using any of the values listed above, I always ended up with upside down images when uploading portrait orientation shots directly from an iPhone. Here's the switch statement I ended up with.

switch ($exif['Orientation']) {
        case 3:
			$image = imagerotate($image, -180, 0);
			break;

        case 6:
            $image = imagerotate($image, -90, 0);
            break;

        case 8:
            $image = imagerotate($image, 90, 0);
            break;
    }

Solution 8 - Php

Here I'am explaining the whole thing, I use Laravel and use the Image Intervention Package.

First of all, I get my image and send it to my another function for resizing and some other functionality, if we do not need this, you can skip...

Grab the file with a method in my controller,

 public  function getImageFile(Request $request){
    $image = $request->image;
    $this->imageUpload($image);
}

Now, I send it to resize and getting the image name and extension...

public function  imageUpload($file){
    ini_set('memory_limit', '-1');
    $directory = 'uploads/';
    $name = str_replace([" ", "."], "_", $file->getClientOriginalName()) . "_";
    $file_name = $name . time() . rand(1111, 9999) . '.' . $file->getClientOriginalExtension();
    //path set
    $img_url = $directory.$file_name;
    list($width, $height) = getimagesize($file);
    $h = ($height/$width)*600;
    Image::make($file)->resize(600, $h)->save(public_path($img_url));
    $this->image_fix_orientation($file,$img_url);
    return $img_url;
}

Now I call my image orientation function,

 public function image_fix_orientation($file,$img_url ) {
    $data = Image::make($file)->exif();
    if (!empty($data['Orientation'])) {
        $image = imagecreatefromjpeg($file);
        switch ($data['Orientation']) {
            case 3:
                $image = imagerotate($image, 180, 0);
                break;

            case 6:
                $image = imagerotate($image, -90, 0);
                break;

            case 8:
                $image = imagerotate($image, 90, 0);
                break;
        }

        imagejpeg($image, $img_url, 90);
    }

}

And That's all...

Solution 9 - Php

Here is my PHP 7 function inspired by @user462990:

/**
 * @param string $filePath
 *
 * @return resource|null
 */
function rotateImageByExifOrientation(string $filePath)
{
    $result = null;

    $exif = exif_read_data($filePath);
    if (!empty($exif['Orientation'])) {
        $image = imagecreatefromjpeg($filePath);
        if (is_resource($image)) {
            switch ($exif['Orientation']) {
                case 3:
                    $result = imagerotate($image, 180, 0);
                    break;

                case 6:
                    $result = imagerotate($image, -90, 0);
                    break;

                case 8:
                    $result = imagerotate($image, 90, 0);
                    break;
            }
        }
    }

    return $result;
}

usage:

    $rotatedFile = rotateImageByExifOrientation($absoluteFilePath);
    if (is_resource($rotatedFile)) {
        imagejpeg($rotatedFile, $absoluteFilePath, 100);
    }

Solution 10 - Php

jhead -autorot jpegfile.jpg

Is also a useful way to approach this.

jhead is a standard program in Linux (use 'sudo apt-get install jhead' to install), this option looks at the orientation and rotates the image correctly and losslessly only if it requires. It then also updates the EXIF data correctly.

In this way you can process a jpeg (or multiple jpegs in a folder) in a simple one-pass way that fixes rotation issues permanently.

E.g: jhead -autorot *.jpg will fix a whole folder of jpeg images in just the manner the OP requires in the initial question.

While it's not technically PHP I did read this thread and then used my jhead suggestion instead, called from a PHP system() call to achieve the results I was after which were coincident with the OPs: to rotate images so any software (like 'fbi' in Raspbian) could display them correctly.

In light of this I thought others may benefit from knowing how easily jhead solves this problem and posted the information here only for informative purposes - because no one had mentioned it previously.

Solution 11 - Php

I've also used orientate() form Intervention, and it works flawlessly.

    $image_resize = Image::make($request->file('photo'));
    $image_resize->resize(1600, null,function ($constraint)
    {
        $constraint->aspectRatio();
    });
    $filename = $this->checkFilename();

    $image_resize->orientate()->save($this->photo_path.$filename,80);

Solution 12 - Php

Intervention Image has a method orientate().

$img = Image::make('foo.jpg')->orientate();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJeff ThomasView Question on Stackoverflow
Solution 1 - PhpJonathanView Answer on Stackoverflow
Solution 2 - PhpDaniel BleisteinerView Answer on Stackoverflow
Solution 3 - Phpuser462990View Answer on Stackoverflow
Solution 4 - PhpDavid VielhuberView Answer on Stackoverflow
Solution 5 - Phpmr_crazy_pantsView Answer on Stackoverflow
Solution 6 - PhpCatView Answer on Stackoverflow
Solution 7 - PhpBrad RootView Answer on Stackoverflow
Solution 8 - PhpMD. ABU TALHAView Answer on Stackoverflow
Solution 9 - PhpSebastian ViereckView Answer on Stackoverflow
Solution 10 - PhpG.P.W.View Answer on Stackoverflow
Solution 11 - Phpc0ldView Answer on Stackoverflow
Solution 12 - PhpDamien BezborodowView Answer on Stackoverflow