PHP Image Rotation Iphone Portrait EXIF Orientation GD2 and imagemagick Libraries

I was adding PHP image upload and delete functions to an application the other day – when I came upon a few problems. The iPhone 4S images that were taken in Portrait mode, and then uploaded, did not display with the appropriate portrait orientation (The orientation of the camera relative to the scene, when the image was captured.). They were saved on the iPhone, still in the Landscape mode – although they were taken as Portrait. For whatever reason, the iPhone 4S saves both Portrait and Landscape images with the same Landscape (Width greater than Height) display orientation.

The Problem:

I can’t use the standard methods to detect which image is actually portrait or landscape – as both Landscape and Portrait are saved as width=”3264″ height=”2448″.

The Portrait images uploaded were displaying as Landscape. So, I need to detect these, and then rotate them to the proper orientation. But, using a typical method of  if(width > height) == ‘landscape’ type of detection and assignment, would not work, because all of the images are saved with the Width greater than the Height on the iPhone 4S. How can I then detect if the image is Portrait and only saved as Landscape so that I can appropriately rotate that one to Portrate?

The Solution:

Read the EXIF Header Data within the image. Some cameras have an orientation / position sensor, using, possibly, a gyroscope. The position or horizontal or vertical orientation (Portrait or Landscape) of the image taken, is written to the EXIF header of the image data.

$source_image = '../images/path_to_Image_on_your_server.jpg';

$exif = exif_read_data($source_image);
print_r($exif);

if(isset($exif['Orientation'])&& $exif['Orientation'] == '6'){
	 echo "The image is rotated";// So do something with the image
}

 

orientation image camera exif data Image form http://www.impulseadventure.com/photo/exif-orientation.html
orientation image camera exif data
Image form http://www.impulseadventure.com/photo/exif-orientation.html

[SHORTCODE_Insert_Google_Adsence_Here]
The “orientation” value is relative to the camera position at the time the image was taken. In this case – the Top Left corner of the camera was at position 6. This is how iPhone orients its camera when you hold it upright. If you turn your iPhone so that the screen is facing you and the home button is to the Right – your iPhone is in position 1.

Now that I had a way to detect if the image was Landscape or Portrait – I needed a way to rotate the image to its proper Portrait orientation – so that it would display properly in the webpage.

I decided to use the GD2 Library to rotate the portrait image to its proper orientation.

The Problem:

Out of Memory Errors using the GD2 Library image rotate function.

Fatal error:Allowed memory size of 67108864 bytes exhausted (tried to allocate 9792 bytes) in /system/libraries/Image_lib.php on line 728

 // PRODUCES MEMORY ERROR
$config['image_library'] = 'gd2';
$config['source_image'] = $source_image;
$config['rotation_angle'] = '270';// << GD2 rotates counterclockwise  -_-

 

The Solution – 1:

Increase PHP Memory at run-time with: ini_set(‘memory_limit’, ‘120M’);

If you want to continue to use the GD2 library – I understand that for the rotation process, it is using up a lot of memory. I saw others suggesting and having success increasing their PHP memory for rotation functions using GD2. I had to increase my memory all the way to 120MB on the godaddy server I was working on. The iPhone 4S has huge image files sizes up to 5 MB. You can achieve memory increases with the following call:

ini_set(‘memory_limit’, ‘120M’); – On the godaddy server I was working on – the PHP setting default memory_limit was = 64M. It was not enough to perform the rotation using the GD2 library methods.

// WORKS - BUT ONLY WITH MEMORY INCREASE
ini_set('memory_limit', '120M');
$config['image_library'] = 'gd2';
$config['source_image'] = $source_image;
$config['rotation_angle'] = '270';// << GD2 rotates counterclockwise  -_-

 

The Solution – 2:

Use the ImageMagick instead

$config['image_library'] = 'imagemagick';
$config['library_path'] = '/usr/bin';
$config['source_image'] = $source_image;
$config['rotation_angle'] = '90';// << imagemagick rotates clockwise  :)

 

(from: http://php.net/manual/en/intro.image.php)

“PHP is not limited to creating just HTML output. It can also be used to create and manipulate image files in a variety of different image formats, including GIF, PNG, JPEG, WBMP, and XPM.”

 

(From: http://www.php.net/manual/en/function.exif-read-data.php)

“Exchangeable image file format (Exif) is a standard that specifies the formats for images, sound, and ancillary tags used by digital cameras (including smartphones), scanners and other systems handling image and sound files recorded by digital cameras.”

 

(From: http://www.php.net/manual/en/function.exif-read-data.php)

EXIF headers tend to be present in JPEG/TIFF images generated by digital cameras, but unfortunately each digital camera maker has a different idea of how to actually tag their images, so you can’t always rely on a specific Exif header being present.

 

 

Using the code:

$source_image = ‘../images/path_to_Image_on_your_server.jpg’;

 

I was able to extract the following  EXIF data from the uploaded iPhone image:

$exif = exif_read_data($source_image);
print_r($exif);
echo "<BR><BR><BR>";
die();

Array
(
[FileName] =&gt; some_image_file_name.jpg
[FileDateTime] =&gt; 1348469620
[FileSize] =&gt; 2164485
[FileType] =&gt; 2
[MimeType] =&gt; image/jpeg
[SectionsFound] =&gt; ANY_TAG, IFD0, THUMBNAIL, EXIF, GPS
[COMPUTED] =&gt; Array
(
[html] =&gt; width="3264" height="2448"
[Height] =&gt; 2448
[Width] =&gt; 3264
[IsColor] =&gt; 1
[ByteOrderMotorola] =&gt; 1
[ApertureFNumber] =&gt; f/2.4
[Thumbnail.FileType] =&gt; 2
[Thumbnail.MimeType] =&gt; image/jpeg
)

[Make] =&gt; Apple
[Model] =&gt; iPhone 4S
[Orientation] =&gt; 6 <<<<<<< '6' (The Top Left corner of the camera was at the right side top when the image was taken) http://www.impulseadventure.com/photo/exif-orientation.html http://sylvana.net/jpegcrop/exif_orientation.html
[XResolution] =&gt; 72/1
[YResolution] =&gt; 72/1
[ResolutionUnit] =&gt; 2
[Software] =&gt; 5.1.1
[DateTime] =&gt; 2012:09:22 23:03:32
[YCbCrPositioning] =&gt; 1
[Exif_IFD_Pointer] =&gt; 204
[GPS_IFD_Pointer] =&gt; 606
[THUMBNAIL] =&gt; Array
(
[Compression] =&gt; 6
[XResolution] =&gt; 72/1
[YResolution] =&gt; 72/1
[ResolutionUnit] =&gt; 2
[JPEGInterchangeFormat] =&gt; 902
[JPEGInterchangeFormatLength] =&gt; 2858
)

[ExposureTime] =&gt; 1/15
[FNumber] =&gt; 12/5
[ExposureProgram] =&gt; 2
[ISOSpeedRatings] =&gt; 800
[ExifVersion] =&gt; 0221
[DateTimeOriginal] =&gt; 2012:09:22 23:03:32
[DateTimeDigitized] =&gt; 2012:09:22 23:03:32
[ComponentsConfiguration] =&gt; 
[ShutterSpeedValue] =&gt; 6337/1622
[ApertureValue] =&gt; 4845/1918
[BrightnessValue] =&gt; -5636/1673
[MeteringMode] =&gt; 5
[Flash] =&gt; 16
[FocalLength] =&gt; 107/25
[SubjectLocation] =&gt; Array
(
[0] =&gt; 1631
[1] =&gt; 1223
[2] =&gt; 881
[3] =&gt; 881
)

[FlashPixVersion] =&gt; 0100
[ColorSpace] =&gt; 1
[ExifImageWidth] =&gt; 3264
[ExifImageLength] =&gt; 2448
[SensingMethod] =&gt; 2
[ExposureMode] =&gt; 0
[WhiteBalance] =&gt; 0
[FocalLengthIn35mmFilm] =&gt; 35
[SceneCaptureType] =&gt; 0
[Sharpness] =&gt; 0
[GPSLatitudeRef] =&gt; N
[GPSLatitude] =&gt; Array
(
[0] =&gt; 44/1
[1] =&gt; 4444/100
[2] =&gt; 4/1
)

[GPSLongitudeRef] =&gt; W
[GPSLongitude] =&gt; Array
(
[0] =&gt; 44/1
[1] =&gt; 44/100
[2] =&gt; 4/1
)

[GPSAltitudeRef] =&gt;
[GPSAltitude] =&gt; 444/1
[GPSTimeStamp] =&gt; Array
(
[0] =&gt; 4/1
[1] =&gt; 3/1
[2] =&gt; 3187/100
)

[GPSImgDirectionRef] =&gt; T
[GPSImgDirection] =&gt; 444/691
)

 

 

// << GD2 Uses counterclockwise rotation  -_-

[SHORTCODE_Insert_Google_Adsence_Here]

Leave a Reply