スマホで撮影した写真を投稿しても正しく上を向かない場合にPHP側で変換する

スマホで撮影した写真を投稿したら、写真が横向きになっているということがあります。パソコンで写真を回転させても直りません。
なんでそうなるのかについて調べてみました。

現象はこんな感じです。

スマホで見ると以下のような写真も、投稿すると変な角度になります。

スマホで見ると正しく見えますが、
投稿すると角度がおかしくなっています。
パソコンで正しく回転させても直りません。

原因はexif情報とブラウザの関係

画像はどの部分が上になるのか?
画像データには表示した際に、上になるポジションを情報として持っています。

ややこしいのは、この情報が2つあることです。
(1)従来の画像データの物理的な回転角度の情報。
(2)exifと呼ばれる仮想回転情報です。

つまりスマホで撮影した場合、(1)の物理的な回転角度情報は縦置きですが、横にして撮影した場合、(2)の仮想回転情報が横置きとなります。

exifに対応しているスマホや、パソコンでは(2)の仮想回転情報に併せて表示されます。

しかし、多くのブラウザでは(2)の仮想回転情報には対応しておらず、(1)の物理回転情報をもとに表示されます。

そのために、スマホでは正しく表示されるのに、投稿すると角度がおかしくなるのです。

ちなみに、windows10で写真を表示する「フォト」で写真を回転させても、(2)の仮想回転情報を変更するだけなので効果がありません。
パソコンで回転させたのに直らないのはこのためです。

正しく表示するためには、(1)の物理回転情報を変更する必要があるのです。

PHPで投稿時のexif情報に合わせて物理回転させるプログラム

 この問題は投稿前に、photoshopなど(1)物理回転情報を変更できるソフトで正しく回転位置を合わせればよいのですが、標準画像ソフトだけでは対応がむつかしいのが現状です。

そこで、PHP側でexif情報(仮想回転情報)を読み取り、自動的に物理回転させるプログラムを組んでみました。
また参考になれば幸いです。

※本プログラムには、例外処理やチェック処理が含まれていません。参照される場合にはご留意願います。
※PHPでの画像編集処理はサーバーのメモリを食います。レンタルサーバーでメモリエラーが発生するようであれば、使用をお控えください。

<?php

$img_type = array(
	"jpg"=>	array("conv"=>"imagecreatefromjpeg","output"=>"imagejpeg"),
	"jpeg"=>array("conv"=>"imagecreatefromjpeg","output"=>"imagejpeg"),
	"gif"=>	array("conv"=>"imagecreatefromgif","output"=>"imagegif"),
	"bmp"=>	array("conv"=>"imagecreatefromwbmp","output"=>"imagejpeg"),
	"png"=>	array("conv"=>"imagecreatefrompng","output"=>"imagepng"),
	"xbm"=>	array("conv"=>"imagecreatefromxbm","output"=>"imagepng"),
	"xpm"=>	array("conv"=>"imagecreatefromxpm","output"=>"imagejpeg")
);

$rotate_type = array(
	1=>array("sts"=>true,	"rotation"=>null,"mode"=>null),	// 変換なし
	2=>array("sts"=>false,	"rotation"=>null,"mode"=>IMG_FLIP_VERTICAL),// 水平反転
	3=>array("sts"=>false,	"rotation"=>180,"mode"=>null),	// 180度回転
	4=>array("sts"=>false,	"rotation"=>null,"mode"=>IMG_FLIP_HORIZONTAL),// 垂直反転
	5=>array("sts"=>false,	"rotation"=>270,"mode"=>IMG_FLIP_VERTICAL),// 水平反転、 反時計回りに270回転
	6=>array("sts"=>false,	"rotation"=>270,"mode"=>null),// 反時計回りに270回転
	7=>array("sts"=>false,	"rotation"=>90,"mode"=>IMG_FLIP_VERTICAL),// 反時計回りに90度回転(反時計回りに90度回転) 水平反転
	8=>array("sts"=>false,	"rotation"=>90,	"mode"=>null)// 反時計回りに90度回転(反時計回りに90度回転)
);

	/** 一時ファイル取得 */
	$tmp_file = $_FILES["photo"]["tmp_name"];

	/** 画像の回転情報を取得 */
	$exif = @exif_read_data($tmp_file);

	/** 画像の拡張子を取得する */
	$ext = substr($_FILES["photo"]["name"], strrpos($_FILES["photo"]["name"], '.') + 1);

	/** 拡張子を小文字に変換 */
	$ext = strtoLower($ext);

	/** 出力ファイル名セット */
	$out_file = "test.${ext}";

	if ((empty($exif["Orientation"]) == true) 	/* 回転情報なし ? */
		|| ($rotate_type[$exif["Orientation"]]["sts"] == true))	/* 回転の必要なし ? */
	{
		/** 単純ファイルコピー */
		move_uploaded_file($tmp_file, $out_file);
	}
	else
	{
		/** 画像を編集可能状態に変換 */
		$images = call_user_func($img_type[$ext]["conv"], $tmp_file);

		if ($rotate_type[$exif["Orientation"]]["mode"] != null)	/* モードあり ? */
		{
			/** 画像を反転 */
			imageflip($images, $rotate_type[$exif["Orientation"]]["mode"]);
		}

		if ($rotate_type[$exif["Orientation"]]["rotation"] != null)	/* 回転あり ? */
		{
			/** 画像を回転 */
			$images = imagerotate($images, $rotate_type[$exif["Orientation"]]["rotation"], 0);
		}

		/** 画像を指定形式に変換して出力 */
		call_user_func($img_type[$ext]["output"], $images, $out_file);

		/** メモリを解放 */
		imagedestroy($images);
	}

?>

<!doctype html>
<html>
<head>
<meta charset="shift_jis">
<title>画像回転テスト</title>
</head>

<body>
<form action="index.php" method="post" id="main_form" enctype="multipart/form-data">
<input name="photo" type="file" size="40">
<input name="" type="submit" value="投稿">
<br>
<img src="<?php echo($out_file) ?>" width=400>
</form>
</body>
</html>

ポイントは、exif情報(仮想情報)は8種類あり、それらに合わせて「imagerotate()」関数を使い物理回転をさせる点にあります。
物理回転情報を仮想回転情報と同じ状態にすることで、回転ずれを直しています。

いずれは全てのブラウザがexif情報に準じて表示するようになるとおもわれますが、プログラム側でも調整するようにすれば、より利用しやすいプログラムになります。

今回のレポートは以上です。
読んでいただいてありがとうございました。


Twitterでもweb集客向上、webマーケティング等についてブログの内容以外の情報発信もさせていただいております。Twitterもご覧いただければ幸いです。


ホームページに関するお悩み事やご相談事がございましたら私どもまでご連絡ください。
微力ではございますが、鋭意ご対応申し上げます。

ホームページのご提案もさせていただいております