
Поворот изображения на основании данных EXIF

Поворот изображения на основании данных EXIF
Сложно представить современный интернет без загруженных фотографий. Это социальные сети, форумы, фотогалереи, фотохостинги и множество других ресурсов и сервисов. В зависимости от композиции, фотографии могут быть как вертикальными, так и горизонтальными. Но ни одна камера технически не в состоянии сделать вертикальный снимок, все без исключения снимки делаются горизонтальными, а ориентация (угол поворота) кадра записывается в секцию EXIF. Программы просмотра считывают эти данные и показывают изображение с нужным углом поворота. При обработке графических файлов средствами PHP, информация об ориентации игнорируется, поэтому при загрузке фотографий на различные сайты полученное изображение может оказаться повернутым, так как именно в таком виде снимок был сделан камерой. Конечно, можно предложить пользователю выполнить предварительную обработку фотографии в каком-нибудь графическом редакторе, но, во-первых, не все пользователи умеют с ними работать, а во-вторых, порой бывает очень сложно объяснить людям, почему у них в программе просмотра все отображается как надо, а после загрузки "все сломалось".
В качестве решения проблемы в различных интернетах предлагается считывать данные EXIF функцией exif_read_data, а затем на основании тега "Orientation" поворачивать изображение. Что-то вроде такого:
Code (PHP) : Убрать нумерацию
- $image = imagecreatefromjpeg($file_path);
- // Прочитать данные EXIF
- $exif = exif_read_data($file_path);
- if (!empty($exif['Orientation'])) {
- switch ($exif['Orientation']) {
- // Поворот на 180 градусов
- case 3: {
- $image = imagerotate($image,180,0);
- break;
- }
- // Поворот вправо на 90 градусов
- case 6: {
- $image = imagerotate($image,-90,0);
- break;
- }
- // Поворот влево на 90 градусов
- case 8: {
- $image = imagerotate($image,90,0);
- break;
- }
- }
- }
В процессе разработки своих программ я неплохо изучил внутреннее устройство JPEG-файлов, поэтому было принято решение разбирать секцию EXIF самостоятельно без использования штатных функций PHP и искать там тег "Orientation". Вот что у меня получилось.
Code (PHP) : Убрать нумерацию
- $orientation=0;
- $f=fopen($file_path,'r');
- $tmp=fread($f, 2);
- if ($tmp==chr(0xFF).chr(0xD8)) {
- $section_id_stop=array(0xFFD8,0xFFDB,0xFFC4,0xFFDD,0xFFC0,0xFFDA,0xFFD9);
- while (!feof($f)) {
- $tmp=unpack('n',fread($f,2));
- $section_id=$tmp[1];
- $tmp=unpack('n',fread($f,2));
- $section_length=$tmp[1];
- // Началась секция данных, заканчиваем поиск
- if (in_array($section_id, $section_id_stop)) {
- break;
- }
- // Найдена EXIF-секция
- if ($section_id==0xFFE1) {
- $exif=fread($f,($section_length-2));
- // Это действительно секция EXIF?
- if (substr($exif,0,4)=='Exif') {
- // Определить порядок следования байт
- switch (substr($exif,6,2)) {
- case 'MM': {
- $is_motorola=true;
- break;
- }
- case 'II': {
- $is_motorola=false;
- break;
- }
- }
- // Количество тегов
- if ($is_motorola) {
- $tmp=unpack('N',substr($exif,10,4));
- $offset_tags=$tmp[1];
- $tmp=unpack('n',substr($exif,14,2));
- $num_of_tags=$tmp[1];
- }
- else {
- $tmp=unpack('V',substr($exif,10,4));
- $offset_tags=$tmp[1];
- $tmp=unpack('v',substr($exif,14,2));
- $num_of_tags=$tmp[1];
- }
- if ($num_of_tags==0) { return true; }
- $offset=$offset_tags+8;
- // Поискать тег Orientation
- for ($i=0; $i<$num_of_tags; $i++) {
- if ($is_motorola) {
- $tmp=unpack('n',substr($exif,$offset,2));
- $tag_id=$tmp[1];
- $tmp=unpack('n',substr($exif,$offset+8,2));
- $value=$tmp[1];
- }
- else {
- $tmp=unpack('v',substr($exif,$offset,2));
- $tag_id=$tmp[1];
- $tmp=unpack('v',substr($exif,$offset+8,2));
- $value=$tmp[1];
- }
- $offset+=12;
- // Orientation
- if ($tag_id==0x0112) {
- $orientation=$value;
- break;
- }
- }
- }
- }
- else {
- // Пропустить секцию
- fseek($f, ($section_length-2), SEEK_CUR);
- }
- // Тег Orientation найден
- if ($orientation) { break; }
- }
- }
- fclose($f);
- $image = imagecreatefromjpeg($file_path);
- if ($orientation) {
- switch($orientation) {
- // Поворот на 180 градусов
- case 3: {
- $image=imagerotate($image,180,0);
- break;
- }
- // Поворот вправо на 90 градусов
- case 6: {
- $image=imagerotate($image,-90,0);
- break;
- }
- // Поворот влево на 90 градусов
- case 8: {
- $image=imagerotate($image,90,0);
- break;
- }
- }
- }
Просмотров: 10060 | Комментариев: 12

Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(19.05.2018 в 14:28):
Меняешь значение поворота на нужное, сохраняешь EXIF. В чем проблема? Само изображение остается нетронутым.

Димма
(19.05.2018 в 14:20):
Я здесь надеялся найти информацию как изменить поворот в EXIF, вариант пакетирование сохранение с поворотом не подходит - может увеличится размер изображения.

Hovo
(06.02.2017 в 15:17):
ManHunter, я согласен за деньги ! майл оставить?

ManHunter
(06.02.2017 в 13:27):
Телепатией не владею, чтобы исправлять чьи-то ошибки без исходного кода и подробных логов. А чужие проекты я дорабатываю только за деньги.

Hovo
(05.02.2017 в 19:21):
ManHunter, а что нужно добавить,чтобу не получать ошибку cannot proceed empty imagick file ? а просто добавить, как есть
Спасибо!
Спасибо!

ManHunter
(05.02.2017 в 16:36):
Не с чем там разбираться, EXIF в файле нет.

HOVO
(05.02.2017 в 02:23):
ManHunter, Здравствуйте ! Спасибо вам за этот код, но у меня возникли проблемы с изображениями с JPEG Adobe Tags, которые не имеют IFD0, (0xFF, 0xE14),
вот ссылка на нарабочее изображение http://ivi.am/img/headers.jpg .
Помогите пожалуйста разобратся.
вот ссылка на нарабочее изображение http://ivi.am/img/headers.jpg .
Помогите пожалуйста разобратся.

Вячеслав
(03.08.2016 в 16:29):
Скрипт - работает. Автору большой респект и уважуха.

Геннадий
(06.01.2016 в 12:59):
Спасибо за решение.
Спасибо за решение. Практически применил для решения одной задачи с поворотом изображения.
Спасибо за решение. Практически применил для решения одной задачи с поворотом изображения.

Дмитрий
(31.10.2015 в 16:58):
Весьма познавательно, положу в копилку.
Озадачился поворотом изображений и сейчас меня терзает один вопрос (ответа ни где не нашел) - как повернуть изображение (только средствами PHP, GD), без потери качества? Ибо заметил что любой поворот, заметно ухудшает качество картинки. Может поможете, судя по вашим статьям, у вас опыт в разработке PHP скриптов, несрамнимо больше моего.
Озадачился поворотом изображений и сейчас меня терзает один вопрос (ответа ни где не нашел) - как повернуть изображение (только средствами PHP, GD), без потери качества? Ибо заметил что любой поворот, заметно ухудшает качество картинки. Может поможете, судя по вашим статьям, у вас опыт в разработке PHP скриптов, несрамнимо больше моего.

ManHunter
(08.05.2015 в 17:30):
Фотографировать ты можешь с любым поворотом, изображение все равно будет сохранено ландшафтно. Обрежь от вертикальной фотографии exif и открой в какой-нибудь фотожопе, все непонятки отпадут.

master-ufa
(08.05.2015 в 17:24):
"Но ни одна камера технически не в состоянии сделать вертикальный снимок, все без исключения снимки делаются горизонтальными,"
не понятно.
Если надо сфотографировать человека в полный рост, то поворачиваю фотоаппарат на 90 градусов. Это не правильно?
не понятно.
Если надо сфотографировать человека в полный рост, то поворачиваю фотоаппарат на 90 градусов. Это не правильно?

Добавить комментарий
Заполните форму для добавления комментария
