使用PHP从JPG中删除EXIF数据

tau*_*tau 19 php exif imagemagick image-processing

有没有办法使用PHP从JPG中删除EXIF数据?我听说过PEL,但我希望有一种更简单的方法.我正在上传将在线显示的图片,并希望删除EXIF数据.

谢谢!

编辑:我没有/不能安装ImageMagick.

Bil*_*l H 16

使用ImageMagick在PHP中快速完成此操作(假设您已安装并启用它).

<?php

$images = glob('*.jpg');

foreach($images as $image) 
{   
    try
    {   
        $img = new Imagick($image);
        $img->stripImage();
        $img->writeImage($image);
        $img->clear();
        $img->destroy();

        echo "Removed EXIF data from $image. \n";

    } catch(Exception $e) {
        echo 'Exception caught: ',  $e->getMessage(), "\n";
    }   
}
?>
Run Code Online (Sandbox Code Playgroud)

  • 这种方法的一个可能的问题是 stripImage() 也会擦除与颜色配置文件相关的信息。因此图像可能不会像您期望的那样。 (2认同)

Rin*_*g Ø 13

用于gd以新的方式重新创建图像的图形部分,并使用其他名称保存.

请参阅PHP gd


编辑2017

使用新的Imagick功能.

打开图片:

<?php
    $incoming_file = '/Users/John/Desktop/file_loco.jpg';
    $img = new Imagick(realpath($incoming_file));
Run Code Online (Sandbox Code Playgroud)

请务必在图像中保留任何ICC配置文件

    $profiles = $img->getImageProfiles("icc", true);
Run Code Online (Sandbox Code Playgroud)

然后剥离图像,然后将配置文件放回去

    $img->stripImage();

    if(!empty($profiles)) {
       $img->profileImage("icc", $profiles['icc']);
    }
Run Code Online (Sandbox Code Playgroud)

来自这个PHP页面,请参阅Max Eremin的评论.

  • 这不会引起jpg的再压缩吗?谢谢. (2认同)
  • @ ring0:对不起后期回复,但这种方法确实有效.不幸的是它确实重新压缩,只要我没有安装imagemagick,我就不得不弄清楚什么对我来说更重要. (2认同)

Nav*_*ons 6

以下将删除 jpeg 文件的所有 EXIF 数据。这将制作一个没有 EXIF 的原始文件的副本并删除旧文件。使用 100 质量不会丢失图片的任何质量细节。

$path = "/image.jpg";

$img = imagecreatefromjpeg ($path);
imagejpeg ($img, $path, 100);
imagedestroy ($img);
Run Code Online (Sandbox Code Playgroud)

(可以在此处找到图形的简单近似值)

  • “使用100质量,不丢失图片的任何质量细节。” ——严格来说,这不是事实。JPEG 使用有损压缩,即使质量为 100%。 (2认同)

xte*_*ore 6

我也在寻找解决方案。最后,我使用PHP重写了删除所有Exif数据的JPEG。我不需要任何目的。

此选项有几个优点...

  • 该文件较小,因为EXIF数据不见了。
  • 不会降低图像质量(因为图像数据不变)。

还要注意有关使用imagecreatefromjpeg的注意事项:我尝试了此操作,并且文件变大了。如果将质量设置为100,则文件将更大,因为图像已经过重新采样,然后以无损方式存储。如果您不使用质量100,则会失去图像质量。避免重采样的唯一方法是不使用imagecreatefromjpeg。

这是我的职能...

/**
 * Remove EXIF from a JPEG file.
 * @param string $old Path to original jpeg file (input).
 * @param string $new Path to new jpeg file (output).
 */
function removeExif($old, $new)
{
    // Open the input file for binary reading
    $f1 = fopen($old, 'rb');
    // Open the output file for binary writing
    $f2 = fopen($new, 'wb');

    // Find EXIF marker
    while (($s = fread($f1, 2))) {
        $word = unpack('ni', $s)['i'];
        if ($word == 0xFFE1) {
            // Read length (includes the word used for the length)
            $s = fread($f1, 2);
            $len = unpack('ni', $s)['i'];
            // Skip the EXIF info
            fread($f1, $len - 2);
            break;
        } else {
            fwrite($f2, $s, 2);
        }
    }

    // Write the rest of the file
    while (($s = fread($f1, 4096))) {
        fwrite($f2, $s, strlen($s));
    }

    fclose($f1);
    fclose($f2);
}
Run Code Online (Sandbox Code Playgroud)

代码很简单。打开输入文件进行读取,输出文件进行写入,然后开始读取输入文件。它从一个到另一个的数据。一旦到达EXIF标记,它将读取EXIF记录的长度,并跳过该字节数。然后,通过读取和写入剩余数据继续进行。


Dmi*_*rov 5

function remove_exif($in, $out)
{
    $buffer_len = 4096;
    $fd_in = fopen($in, 'rb');
    $fd_out = fopen($out, 'wb');
    while (($buffer = fread($fd_in, $buffer_len)))
    {
        //  \xFF\xE1\xHH\xLLExif\x00\x00 - Exif 
        //  \xFF\xE1\xHH\xLLhttp://      - XMP
        //  \xFF\xE2\xHH\xLLICC_PROFILE  - ICC
        //  \xFF\xED\xHH\xLLPhotoshop    - PH
        while (preg_match('/\xFF[\xE1\xE2\xED\xEE](.)(.)(exif|photoshop|http:|icc_profile|adobe)/si', $buffer, $match, PREG_OFFSET_CAPTURE))
        {
            echo "found: '{$match[3][0]}' marker\n";
            $len = ord($match[1][0]) * 256 + ord($match[2][0]);
            echo "length: {$len} bytes\n";
            echo "write: {$match[0][1]} bytes to output file\n";
            fwrite($fd_out, substr($buffer, 0, $match[0][1]));
            $filepos = $match[0][1] + 2 + $len - strlen($buffer);
            fseek($fd_in, $filepos, SEEK_CUR);
            echo "seek to: ".ftell($fd_in)."\n";
            $buffer = fread($fd_in, $buffer_len);
        }
        echo "write: ".strlen($buffer)." bytes to output file\n";
        fwrite($fd_out, $buffer, strlen($buffer));
    }
    fclose($fd_out);
    fclose($fd_in);
}
Run Code Online (Sandbox Code Playgroud)

它是从命令行调用的原型。