Создание полезных сайтов
Фото поворачивается после загрузки: как исправить EXIF-ориентацию
Сохраните оригинал, один раз примените инструкцию ориентации к пикселям и проверьте экспорт и загруженную миниатюру. Если тег отсутствует или неверен, правильное положение нужно выбрать визуально.
Начните с нового экспорта оригинала
Если на телефоне фотография выглядит правильно, а после загрузки поворачивается набок, сохраните оригинал и сделайте отдельный экспорт. Одна из возможных причин — EXIF-ориентация: пиксели записаны в одном положении, а тег сообщает программе просмотра, как их повернуть. Создание миниатюры или преобразование файла может проигнорировать либо удалить эту инструкцию. Сам по себе повёрнутый снимок ещё не доказывает, что причина именно в ней.
Без программирования это можно сделать в редакторе, который умеет экспортировать новое изображение с применением видимой ориентации к пикселям. Управление зависит от приложения; ниже описан проверяемый результат, а не испытанная последовательность пунктов меню.
- Откройте оригинал в редакторе и выберите понятный ориентир: читаемую надпись, горизонт или деталь, которая должна находиться слева.
- Если снимок уже расположен правильно, не добавляйте четверть оборота только потому, что другой предпросмотр показывал его боком. Если положение неверное, исправьте поворот или отражение в редакторе.
- Экспортируйте новый файл под новым именем. Если редактор поддерживает такой режим, примените ориентацию к пикселям и удалите либо сбросьте инструкцию ориентации. PNG удобен для промежуточной проверки, если площадка его принимает.
- Откройте экспортированный файл заново, затем загрузите именно его и проверьте выдаваемое площадкой полное изображение и миниатюру. Сохраните оригинал, пока оба результата не станут правильными.
Ориентация может храниться в двух местах
Ширина и высота файла описывают массив пикселей. EXIF Orientation сообщает, как его показывать. Например, значение 6 задаёт четверть оборота по часовой стрелке: изображение с записанными размерами 96 × 64 после применения инструкции становится 64 × 96. Число пикселей не меняется.
Нормализовать ориентацию — значит один раз применить инструкцию к пикселям, затем удалить или сбросить старую инструкцию. Если сначала удалить тег, нужные для исправления сведения потеряются; если повернуть пиксели и сохранить прежний тег, другая программа может повернуть их повторно. Это отдельная операция, не обрезка, растягивание или замена фона.

Проверяйте отражение, а не только поворот
Восемь значений EXIF-ориентации включают зеркальные варианты. Значения 2, 4, 5 и 7 содержат отражение; обработка только поворотов на 90°, 180° и 270° их не покрывает. На снимке документа или товара проверьте надписи и положение характерных деталей слева и справа, а не только верхний край.
Если инструкция ориентации не найдена или Orientation равно 1, исправление не применяется. Это не доказывает, что объект расположен правильно. Допустимый, но неверный тег тоже может дать неправильный результат. Программа, следующая тегу, не угадывает намерение фотографа; для ручного исправления ориентируйтесь на саму сцену или читаемый текст.
Почему поворот через CSS не исправляет файл
MDN указывает image-orientation: from-image как исходное значение CSS: при показе браузер может учитывать сведения об ориентации изображения. Преобразование вроде rotate(90deg) применяется после этого шага. Если добавить его без проверки, можно повернуть снимок, который браузер уже показывает правильно.
CSS меняет вид на странице; он не переписывает скачиваемый файл или миниатюру, созданную сервером. Если при обработке тег удалили, не исправив пиксели, from-image не восстановит потерянную инструкцию. Перед изменением стилей сравните локальный экспорт с изображением, которое сайт действительно отдаёт.
По желанию: нормализуйте JPEG локально в Python
Следующий пример создаёт отдельный PNG с ориентацией, применённой к пикселям. Используйте новую рабочую папку в Linux или macOS и Python 3.11 либо новее. При установке скачивается Pillow; само преобразование читает локальные файлы и не загружает фотографию на сервер. Сохраните блок Python как normalize_orientation.py, а рабочую копию JPEG положите рядом под именем input.jpg.
Вход намеренно ограничен: один JPEG в RGB или оттенках серого, не более 20 миллионов пикселей. Скрипт отклоняет CMYK, другие форматы, несколько кадров и неизвестные значения ориентации. Это не конвертер HEIC, RAW, HDR или файлов с несколькими изображениями. Расширения .jpg недостаточно: проверяется распознанный формат. Pillow может получить Orientation и из XMP; отсутствие блока EXIF само по себе не означает отсутствие распознанной ориентации.
Подготовьте проверенное окружение
bash
python3 -m venv .venv
.venv/bin/python -m pip install "Pillow==13.0.0"Проверено в Linux с Python 3.12.3 и Pillow 13.0.0. Выполните команды в новой рабочей папке.
Сохраните как normalize_orientation.py
python
import sys
from pathlib import Path
from PIL import Image, ImageOps
def normalize(source, destination):
destination = Path(destination)
if destination.suffix.lower() != ".png":
raise ValueError("Choose a new output filename ending in .png")
with Image.open(source) as image:
if image.format != "JPEG" or image.mode not in ("RGB", "L"):
raise ValueError("Use a single RGB or grayscale JPEG")
if getattr(image, "n_frames", 1) != 1:
raise ValueError("Multiple frames are outside this example")
if image.width * image.height > 20_000_000:
raise ValueError("Image exceeds this example's 20 megapixel limit")
orientation = image.getexif().get(274, 1)
if not isinstance(orientation, int) or orientation not in range(1, 9):
raise ValueError("Unrecognized orientation; inspect the source manually")
image.load()
icc = image.info.get("icc_profile")
upright = ImageOps.exif_transpose(image)
clean = Image.new(upright.mode, upright.size)
clean.paste(upright)
options = {"icc_profile": icc} if icc else {}
with destination.open("xb") as output:
clean.save(output, format="PNG", **options)
print(f"Saved {destination}: {clean.width} x {clean.height} pixels")
if __name__ == "__main__":
if len(sys.argv) != 3:
raise SystemExit("Usage: python normalize_orientation.py input.jpg upright.png")
normalize(sys.argv[1], sys.argv[2])
Ориентация применяется до копирования пикселей в чистое изображение. Из метаданных переносится только ICC-профиль; режим xb запрещает замену существующего файла.
Создайте новый PNG с исправленной ориентацией
bash
.venv/bin/python normalize_orientation.py input.jpg upright.pngПри каждом запуске выбирайте новое имя результата. Исходный JPEG читается без изменений.
Что сохраняется и что намеренно не переносится
Скрипт не масштабирует и не обрезает картинку. Четверть оборота меняет местами ширину и высоту. PNG хранит преобразованные декодированные пиксели JPEG без ещё одного сжатия JPEG с потерями; он не возвращает детали, уже потерянные в исходном JPEG. PNG может оказаться значительно больше, а площадка может его не принять или позже сжать заново.
Преобразованные пиксели копируются в новое изображение, поэтому результат не содержит EXIF, XMP и старой инструкции ориентации, в том числе значения Orientation 1. Время съёмки, поля камеры, встроенные миниатюры и другие исходные метаданные не переносятся. Если они нужны, сохраните оригинал.
Встроенный ICC-профиль копируется без изменений. Это сохраняет заданный профиль, но не проверяет его и не переводит цвета в sRGB. Удаление метаданных здесь не гарантирует обезличивание: ICC-профиль может содержать сведения, а по самому снимку можно узнать людей или места. Для точной цветопередачи или сохранения метаданных используйте подходящий редактор и отдельно проверьте эти требования.
Существующий выходной путь, включая путь исходника или символическую ссылку, отклоняется. Если запись прервётся после создания нового файла, может остаться неполный результат; перед повторной попыткой удалите именно его или выберите новое имя.
Если после загрузки снимок всё ещё повёрнут
- Сравните сохранённый экспорт с изображением, которое сайт действительно отдаёт. Миниатюра и полный снимок могут проходить разные этапы обработки.
- Убедитесь, что загрузили новый файл и открыли его новый адрес, а не старую миниатюру из кеша.
- Если неверен только вид на странице, проверьте правила image-orientation и transform. Если неверен сам отдаваемый файл, исследуйте преобразование изображения или создание миниатюр.
- Если нормализованный файл неправильно выглядит уже локально, проверьте исходный тег и выбранный ориентир верха и левой стороны. Повтор той же автоматической нормализации не исправит неверную или отсутствующую инструкцию.
Как Coru проверил пример
21 октября 2026 года мы запустили опубликованный скрипт в локальном эксперименте с отключённой сетью. Все 57 проверок прошли. Они охватили восемь значений ориентации, включая отражения, отсутствие тега, RGB и оттенки серого, сохранность байтов ICC, отсутствие EXIF/XMP, хеши исходников, существующие результаты и отклоняемые входные файлы.
Для каждого значения ориентации независимое преобразование координат пикселей декодированного JPEG побайтово сравнивалось с заново открытым PNG. Файлы 96 × 64 стали 64 × 96 при значениях 5–8 и остались 96 × 64 при значениях 1–4 либо отсутствии тега. Эти тесты проверяют скрипт на синтетических файлах; они не устанавливают поведение любого редактора, сервиса загрузки, камеры или повреждённого файла.