PHP read_exif_data 및 방향 조정


79

방향이 꺼져있는 경우 다음 코드를 사용하여 업로드 된 jpeg 이미지를 회전하고 있습니다. iPhone 및 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';
        }

jpeg에서 EXIF ​​데이터를 읽는 방식에 문제가 있습니까? 예상대로 이미지를 회전하지 않습니다.

이것이 내가 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) }

이 코드는 회전이 필요하지 않은 경우에도 소스 이미지를 다시 압축합니다.
Marc B

내 문제는 회전해야 할 이미지가 회전되지 않는다는 것입니다.
Jeff Thomas

var_dump($exif)회전 데이터 방식으로 안드로이드 폰이 무엇을 생성하는지 확인하려면 a 를 수행하십시오.
Marc B

1
좋아, 거기 쓰레기장을 치웠어. 명백하게. 오리엔테이션 필드가 'IFD0'섹션에 없으며 $exif['COMPUTED']['Orientation']값이 6입니다.
Marc B

1
$ exif [ '방향']; 나를 위해 잘 작동하고 있습니다. $ exif [ 'some_section'] [ 'Orientation']에 비해 더 나은 선택 일 수 있습니다.
데모 스텐

답변:


63

imagerotate에 대한 문서 는 사용하는 것과 다른 첫 번째 매개 변수 유형을 참조합니다.

imagecreatetruecolor ()와 같은 이미지 생성 함수 중 하나에서 반환하는 이미지 리소스입니다.

다음은이 함수를 사용하는 간단한 예입니다.

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);
}

어떤 이유로 android 4.1.2에서 생성 된 이미지는 회전 할 필요가 없습니다. "imagecreatefromjpen ()"로 이미지를로드 한 다음 "imagejpeg ()"로 다시 저장하면됩니다. 그 이유를 아십니까?
doron 2014

76

Daniel의 코드를 기반으로 필요한 경우 리샘플링없이 단순히 이미지를 회전하는 함수를 작성했습니다.

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;
        }
    }
}

한 줄 버전 (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;
        }
    }
}

Imagick의 경우 getImageOrientation ()을 사용하여 방향을 검색 한 다음 이미지를 회전 한 후 $ image-> setImageOrientation (\ Imagick :: ORIENTATION_TOPLEFT)을 통해 올바른 Exif 방향 값을 설정합니다.
Tilman

WideImage에 대한 솔루션이 있습니까?
Yami Medina

어떤 경우에는 getImageOrientation()변환 된 Raw 이미지를 사용해도 imagick 기능 이 제대로 작동하지 않았습니다. 위의 코드는 완벽하게 작동했습니다.
rokdd

첫 번째 버전 (GD)에서이 함수를 호출하는 & $ image에 대해 무엇을 전달해야합니까?
Bharat Maheshwari

2
로컬 파일에서 & $ image 매개 변수를 전달하는 방법을 이해하지 못하는 사람은 다음과 같이 사용하십시오. $ im = @imagecreatefromjpeg ($ local_filename); image_fix_orientation ($ im, $ local_filename); if ($ im) {imagejpeg ($ im, $ local_filename); imagedestroy ($ im); }
woheras

43

이미지를 업로드하는 사람들을위한 더 간단한 기능으로 필요한 경우 자동으로 회전합니다.

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);
    }
}

1
이 답변을 github (하나의 메서드 만있는 클래스)에서 찾을 수있는 간단한 작성기 패키지로 만들었습니다. github.com/diversen/image-auto-rotate
dennis

잘못된 정도 값을 사용합니다. 6의 경우 90 도가 필요하고 8의 경우 -90 도가 필요합니다.
bernhardh dec.

매우 유용한 기능입니다.이 경고가 잘못된 IFD 크기 인 경우 @ 연산자를 사용할 수 있습니다. : $exif = @exif_read_data($filename);
chebaby

@ user462990이 함수는 잘 작동하지만 로컬로 제공되는 이미지에만 적용됩니다. 이미지 URL을 어떻게 전달합니까? s3에 방향을 조정하는 데 필요한 이미지가 있습니다.
ultrasamad

12

미러링 된 케이스 2,4,5,7을 고려하지 않는 이유는 무엇입니까? exif 오리엔테이션 랜드에는 4 개의 케이스가 더 있습니다.

여기에 이미지 설명 입력

다음은 파일 이름을 취하는 완전한 솔루션입니다.

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;
}

탁월한 솔루션. 많은 사용자가 미러링 된 이미지를 업로드하고 최종 이미지에 문제가 있기 때문에 이것은 좋은 점이었습니다.
Albert Thompson

6

누군가가 이것을 보게 될 경우를 대비하여. 위의 switch 문 중 일부가 잘못되었음을 알 수 있습니다.

여기 에있는 정보 따르면 다음과 같아야합니다.

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;
} 

6

명령 줄에서 ImageMagick을 사용하는 경우 기존 EXIF ​​방향 데이터를 기반으로 이미지를 자동 회전하는 -auto-orient 옵션을 사용할 수 있다는 점을 언급하는 것이 좋습니다 .

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

참고 : EXIF ​​데이터가 프로세스 전에 제거 된 경우 설명 된대로 작동하지 않습니다.


2

여기서는 모든 것을 설명하고 있습니다. 저는 Laravel을 사용하고 Image Intervention Package를 사용합니다.

우선, 내 이미지를 가져 와서 크기 조정 및 기타 기능을 위해 다른 기능으로 보냅니다.이 기능이 필요하지 않으면 건너 뛸 수 있습니다.

내 컨트롤러의 메서드로 파일을 잡고,

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

이제 크기를 조정하고 이미지 이름과 확장자를 가져 오도록 보냅니다.

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;
}

이제 이미지 방향 기능을 호출합니다.

 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);
    }

}

그리고 그게 전부입니다...


1

나는 또 다른 방향 값 세트로 차임하는 것이 싫지만 위에 나열된 값 중 하나를 사용한 경험상 iPhone에서 직접 세로 방향 사진을 업로드 할 때 항상 거꾸로 된 이미지가 발생했습니다. 여기에 내가 끝낸 switch 문이 있습니다.

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;
    }

1

jhead -autorot jpegfile.jpg

이것에 접근하는 유용한 방법이기도합니다.

jhead는 Linux의 표준 프로그램입니다 ( 'sudo apt-get install jhead'를 사용하여 설치).이 옵션은 방향을 확인하고 필요한 경우에만 이미지를 정확하고 손실없이 회전합니다. 그런 다음 EXIF ​​데이터도 올바르게 업데이트합니다.

이렇게하면 회전 문제를 영구적으로 수정하는 간단한 원 패스 방식으로 jpeg (또는 폴더의 여러 jpeg)를 처리 할 수 ​​있습니다.

예 : jhead -autorot * .jpg는 OP가 초기 질문에서 요구하는 방식으로 jpeg 이미지의 전체 폴더를 수정합니다.

기술적으로 PHP는 아니지만이 스레드를 읽은 다음 대신 PHP system () 호출에서 호출 된 jhead 제안을 사용하여 OP와 일치하는 결과를 얻었습니다. 이미지를 회전하여 모든 소프트웨어 (예 : 'fbi 'Raspbian에서) 올바르게 표시 될 수 있습니다.

이것에 비추어, 나는 다른 사람들이 jhead가이 문제를 얼마나 쉽게 해결할 수 있는지 알면 도움이 될 것이라고 생각했고, 이전에 아무도 언급하지 않았기 때문에 정보를 제공하기 위해서만 여기에 정보를 게시했습니다.


답변이 짧아 품질이 낮은 것으로 표시되었습니다. 해결책을 더 자세히 설명해보세요.
Derek Brown

1

나는 또한 orientate()form Intervention을 사용 했으며 완벽하게 작동합니다.

    $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);

1

다음은 @ user462990에서 영감을 얻은 PHP 7 함수입니다.

/**
 * @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;
}

용법:

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.