Извлечение DPI из JPEG без библиотеки возвращает неверный результат

Я получил функцию, которая может считывать значение DPI из JPEG здесь.

function get_dpi($filename){
    $a = fopen($filename,'r');
    $string = fread($a,20);
    fclose($a);

    $data = bin2hex(substr($string,14,4));
    $x = substr($data,0,4);
    $y = substr($data,4,4);

    return array(hexdec($x),hexdec($y));
}

Однако, когда я проверяю изображение, созданное Photoshop с разрешением 300 точек на дюйм, оно неправильно возвращает значение 42 точки на дюйм.

Извлечение DPI из JPEG без библиотеки возвращает неверный результат

Что я пропустил?


Проблемное изображение, сгенерированное Photoshop: https://drive.google.com/open?id=117LHlgpefXZsuiVSl_nMG6MUQfKcT1MI

ОБНОВИТЬ: я попытался с помощью онлайн конвертер DPI регенерировать JPEG с разрешением 300 точек на дюйм, функция PHP сообщает правильное значение, 300 точек на дюйм.

Восстановленное изображение: https://drive.google.com/open?id=1-C4GZ8_K4wit3sISz21ngd4OVlLXuL72

Я сравнил метаданные двух файлов JPEG, сгенерированный файл JPEG имеет информацию JIFF, а исходный файл JPEG — нет. Это причина проблемы?

Учитывая, что у меня нет библиотеки Imagick, я не могу использовать ее функцию getImageResolution() для чтения значения.

Можете ли вы поделиться примером изображения, чтобы другие могли воспроизвести проблему?

Nico Haase 17.05.2019 09:52

обновлено в вопросе.

Raptor 17.05.2019 10:46

Может, потому что заголовок в формате exif. Может быть, вы можете попробовать использовать exif_read_data()? lastcode.net/2013/01/read-php-exif-image-meta-data.html и stackoverflow.com/questions/36332823/…

golddragon007 17.05.2019 11:22

Если вы не можете использовать пред. упомянутая функция, и вам все еще нужно выяснить, чем вам нужно прочитать спецификации exif: media.mit.edu/pia/Research/deepview/exif.htmlsno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html пример программы (не в php): codeproject.com/Articles/47486/…

golddragon007 17.05.2019 11:41
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
4
96
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Спасибо за помощь от @golddragon007, мое окончательное решение состоит в том, чтобы объединить данные из различных функций следующим образом:

function get_dpi($filename){
    $new_filename = time() . '_' . rand(1000, 999999) . '.jpg';
    $result = move_uploaded_file($filename, 'upload/' . $new_filename);

    $dpi_from_exif = get_exif ('upload/' . $new_filename);
    if ($dpi_from_exif !== false) {
        unlink('upload/' . $new_filename);
        return $dpi_from_exif;
    } else {
        $a = fopen('upload/' . $new_filename,'r');
        $string = fread($a, 20);
        fclose($a);

        $data = bin2hex(substr($string, 14, 4));
        $x = substr($data, 0, 4);
        $y = substr($data, 4, 4);

        unlink('upload/' . $new_filename);
        return hexdec($x);
    }
}

function get_exif ($filename) {
    $exif = exif_read_data($filename);
    if ($exif === false) {
        return false;
    } else {
        if (array_key_exists('XResolution', $exif)) {
            return do_maths($exif['XResolution']);
        } else {
            return false;
        }
    }
}

function do_maths($expression) {
    eval('$o = ' . preg_replace('/[^0-9\+\-\*/\(\)\.]/', '', $expression) . ';');
    return $o;
}

Использование следующее:

$dpi_in_int = get_dpi($the_image_file);

Если я использую изображение, которое я указал в вопросе, функция вернет:

300

Объяснение функции:

В моем сценарии я прочитал загруженный файл (из <input type = "file" />), get_dpi($filename) сначала переместил временный загружаемый файл в папку upload/ (необязательный шаг), а затем прочитал DPI из EXIF ​​с помощью функции get_exif ($filename).

Если DPI можно прочитать из данных EXIF, значение DPI будет возвращено; в противном случае значение DPI извлекается из метаданных JPEG (первые несколько байтов файла JPEG), что в некоторых случаях оказывается неточным (например, первое изображение, которое я предоставил).

Функция do_maths() состоит в том, чтобы проанализировать значение из XResolution данных EXIF ​​IPF0 (что является 3000000/10000, по-видимому, математическим уравнением) и вычислить окончательное значение. Обратите внимание, что у eval() есть некоторые потенциальные проблемы с безопасностью, поэтому входные данные сначала очищаются с помощью preg_replace() регулярного выражения, чтобы гарантировать отсутствие кода инъекции. Эта функция do_maths() от https://stackoverflow.com/a/5805773/188331

Наконец, функция get_dpi() удалит загруженный файл, чтобы сэкономить место на диске сервера (необязательно).

Другие вопросы по теме