25

If I take a photo with a camera it stores the orientation/angle of the apparatus so when I view the image on the PC with a good app, it shows auto-rotated to 0.

But when I upload to a website it shows the original angle, so the image doesn't look good.

How can I detect this with PHP and rotate the image, and clear this angle flag from it's meta information.

Pentium10
  • 204,586
  • 122
  • 423
  • 502

4 Answers4

28

I modified Chris' example to add a check for the exif function, remove the mirroring, and also to write the file back out to the filesystem using the same filename. This way, you can call this function right after calling move_uploaded_file, like this:

move_uploaded_file($uploadedFile, $destinationFilename);
correctImageOrientation($destinationFilename);

function correctImageOrientation($filename) {
  if (function_exists('exif_read_data')) {
    $exif = exif_read_data($filename);
    if($exif && isset($exif['Orientation'])) {
      $orientation = $exif['Orientation'];
      if($orientation != 1){
        $img = imagecreatefromjpeg($filename);
        $deg = 0;
        switch ($orientation) {
          case 3:
            $deg = 180;
            break;
          case 6:
            $deg = 270;
            break;
          case 8:
            $deg = 90;
            break;
        }
        if ($deg) {
          $img = imagerotate($img, $deg, 0);        
        }
        // then rewrite the rotated image back to the disk as $filename 
        imagejpeg($img, $filename, 95);
      } // if there is some rotation necessary
    } // if have the exif orientation info
  } // if function exists      
}
Wes
  • 826
  • 9
  • 18
  • it seems to be not working. `correctImageOrientation($destinationFilename);` is not working with $destinationFilename being the absolute path. Any idea ? – Jeremy Mar 05 '15 at 19:49
  • Nice. I added a mime type check to correctly load the data (ie imagecreatefrompng for PNG files) and then save the data back to that format. – Sp4cecat Jul 18 '19 at 04:53
26

In order to do that, you must read the EXIF information out of the JPEG file. You can either do that with exif PHP extension or with PEL.

Basically, you have to read the Orientation flag in the file. Here is an example using the exif PHP extension and WideImage for image manipulation.

<?php
$exif = exif_read_data($filename);
$ort = $exif['Orientation'];

$image = WideImage::load($filename);

// GD doesn't support EXIF, so all information is removed.
$image->exifOrient($ort)->saveToFile($filename);

class WideImage_Operation_ExifOrient
{
  /**
   * Rotates and mirrors and image properly based on current orientation value
   *
   * @param WideImage_Image $img
   * @param int $orientation
   * @return WideImage_Image
   */
  function execute($img, $orientation)
  {
    switch ($orientation) {
      case 2:
        return $img->mirror();
        break;

      case 3:
        return $img->rotate(180);
        break;

      case 4:
        return $img->rotate(180)->mirror();
        break;

      case 5:
        return $img->rotate(90)->mirror();
        break;

      case 6:
        return $img->rotate(90);
        break;

      case 7:
        return $img->rotate(-90)->mirror();
        break;

      case 8:
        return $img->rotate(-90);
        break;

      default: return $img->copy();
    }
  }
}
Andrew Moore
  • 93,497
  • 30
  • 163
  • 175
  • Wasn't sure how to use the class Andrew posted, so just placed the function inside my controller and passed the image variable and orientation to it. Work's like a champ. Only comment is to verify that the image is of type JPEG before calling exif_read_data otherwise php will throw an error. – w00tw00t111 Oct 15 '12 at 16:33
  • Note that this code requires that you install the WideImage PHP library. (Andrew mentiones that, but I know most people are just going to copy and paste the code and then not understand why it doesn't work for them.) If you don't want to install WideImage, there are other examples of how to do this without it. – orrd Feb 20 '13 at 20:46
  • @w00tw00t111 is a non-JPEG file type what causes the following error? `Fatal error: Uncaught exception 'WideImage_UnknownImageOperationException' with message 'Can't load 'exifOrient' operation.'` – Yami Medina Feb 06 '16 at 03:38
17

If you just want to use GD and the php EXIF extension you can use this:

function _mirrorImage ( $imgsrc)
{
    $width = imagesx ( $imgsrc );
    $height = imagesy ( $imgsrc );

    $src_x = $width -1;
    $src_y = 0;
    $src_width = -$width;
    $src_height = $height;

    $imgdest = imagecreatetruecolor ( $width, $height );

    if ( imagecopyresampled ( $imgdest, $imgsrc, 0, 0, $src_x, $src_y, $width, $height, $src_width, $src_height ) )
    {
        return $imgdest;
    }

    return $imgsrc;
}

function adjustPicOrientation($full_filename){        
    $exif = exif_read_data($full_filename);
    if($exif && isset($exif['Orientation'])) {
        $orientation = $exif['Orientation'];
        if($orientation != 1){
            $img = imagecreatefromjpeg($full_filename);

            $mirror = false;
            $deg    = 0;

            switch ($orientation) {
              case 2:
                $mirror = true;
                break;
              case 3:
                $deg = 180;
                break;
              case 4:
                $deg = 180;
                $mirror = true;  
                break;
              case 5:
                $deg = 270;
                $mirror = true; 
                break;
              case 6:
                $deg = 270;
                break;
              case 7:
                $deg = 90;
                $mirror = true; 
                break;
              case 8:
                $deg = 90;
                break;
            }
            if ($deg) $img = imagerotate($img, $deg, 0); 
            if ($mirror) $img = _mirrorImage($img);
            $full_filename = str_replace('.jpg', "-O$orientation.jpg",  $full_filename); 
            imagejpeg($img, $full_filename, 95);
        }
    }
    return $full_filename;
}
Chris Cinelli
  • 4,679
  • 4
  • 28
  • 40
  • 1
    This is, of course, the complete solution. It's worth pointing out, however, that since PHP 5.5, you can replace your _mirrorImage function call with imageflip($img, IMG_FLIP_HORIZONTAL) – wordragon Sep 22 '19 at 07:57
2

The rotation flag is stored as part of the EXIF data (see this article for more info).

You will need to read the rotation flag from the EXIF data in PHP and then rotate the image to suit. There are a variety of PHP EXIF libraries, if you have the web server set up with the extension installed you would be able to use the PHP provided library.

I would suggest rotating the image once on upload (e.g. using the GD library - most PHP installations these days seem to come with it), so that you don't need to worry about clearing the EXIF rotation data (not sure how easy this is with PHP, I've never tried it).