从没有库的JPEG中获取DPI会返回错误结果

时间:2019-05-17 07:51:16

标签: php

我获得了一个可以从JPEG here读取DPI值的函数。

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在300DPI下创建的图像时,它错误地返回了42DPI的值。

Photoshop CC screenshot

我想念什么?


由Photoshop生成的有问题的图像:https://drive.google.com/open?id=117LHlgpefXZsuiVSl_nMG6MUQfKcT1MI

更新:我尝试使用online DPI converter重新生成300DPI的JPEG,PHP函数报告了正确的值300DPI。

重新生成的图像:https://drive.google.com/open?id=1-C4GZ8_K4wit3sISz21ngd4OVlLXuL72

我比较了2个JPEG的元数据,生成的JPEG具有JIFF信息,但是初始JPEG没有。那是问题的原因吗?

鉴于我没有Imagick库,因此无法使用其getImageResolution()函数来读取值。

1 个答案:

答案 0 :(得分:0)

感谢@ 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/文件夹中(可选步骤),然后读取了使用get_exif($filename)函数从EXIF获取DPI。

如果可以从EXIF数据中读取DPI,则将返回DPI值;否则,DPI值是从JPEG元数据(JPEG文件的前几个字节)中获取的,在某些情况下(例如,我提供的第一张图像),这被证明是不准确的。

do_maths()函数将从EXIF的IPF0数据的XResolution中解析出值(显然是数学方程式3000000/10000)并计算最终值。请注意,eval()存在一些潜在的安全问题,因此首先使用preg_replace()正则表达式清除输入,以确保不存在注入代码。此do_maths()函数来自https://stackoverflow.com/a/5805773/188331

最后,get_dpi()函数将删除上载的文件以节省服务器中的磁盘空间(可选)。