【问题标题】:How to remove EXIF data without recompressing the JPEG?如何在不重新压缩 JPEG 的情况下删除 EXIF 数据?
【发布时间】:2011-02-08 21:40:41
【问题描述】:

我想从 JPEG 文件中删除 EXIF 信息(包括缩略图、元数据、相机信息......一切!),但我不想重新压缩它,因为重新压缩 JPEG 会降低质量,以及通常会增加文件大小。

我正在寻找 Unix/Linux 解决方案,如果使用命令行会更好。如果可能,使用 ImageMagick(转换工具)。如果这不可行,一个小的 Python、Perl、PHP(或 Linux 上的其他通用语言)脚本就可以了。

有一个类似的问题,但是related to .NET

【问题讨论】:

标签: unix imagemagick jpeg exif


【解决方案1】:

exiftool 为我完成了这项工作,它是用 perl 编写的,因此应该适用于任何操作系统

https://exiftool.org/

用法:

exiftool -all= image.jpg

已更新 - 正如 PeterCo 在下面解释的那样,这将删除所有标签。如果您只想删除 EXIF 标签,那么您应该使用

exiftool -EXIF= image.jpg

【讨论】:

  • 其他一些有趣的选项:“-o outfile.jpg”或“-out outfile.jpg”、“-overwrite_original”或“-overwrite_original_in_place”、“-P”或“-preserve”、“ -r" 或 "-recurse"
  • 我刚刚遇到这个线程,正在寻找同样的东西。我只是想在这里为 Ubuntu 用户添加一条评论:该脚本在 Ubuntu 存储库中以 libimage-exiftool-perl 的形式提供:sudo apt-get install libimage-exiftool-perl
  • 或者用自制软件brew install exiftool
  • 如果你真的信任程序添加-overwrite_original开关,程序将不会创建备份文件。
  • 接受的使用选项 -all= 会从您的 image.jpg 中删除所有标签!正确答案是exiftool -EXIF= image.jpg
【解决方案2】:

我建议jhead:

man jhead
jhead -purejpg image.jpg

在 debian/ubuntu 上只有 123Kb,速度很快,而且它只触及 EXIF,保持图像本身完好无损。请注意,如果要保留包含 EXIF 的原始文件,则需要创建一个副本。

【讨论】:

    【解决方案3】:

    如果您已经使用 jpegoptim,您也可以使用它来删除 exif。

    jpegoptim -s *
    

    【讨论】:

    • 这不起作用,它会修改图像(并且似乎没有copy 选项,并且使用-n 开关不优化图像也不会剥离EXIF 数据)。
    【解决方案4】:

    ImageMagick 有-strip 参数,但它会在保存之前重新压缩图像。因此,这个参数对我的需要没有用。

    This topic from ImageMagick forum 解释说 ImageMagick 中不支持 JPEG 无损操作(无论何时更改,请发表带有链接的评论!),并建议使用 jpegtran(来自 libjpeg):

    jpegtran -copy none -progressive image.jpg > newimage.jpg
    jpegtran -copy none -progressive -outfile newimage.jpg image.jpg
    

    (如果您不确定我是否能回答我自己的问题,请阅读 thisthisthis

    【讨论】:

    • 尝试了 jpegtran 方法,但在大多数情况下,它会增加文件大小而不是减小文件大小。在大多数情况下,您希望这样做以减小文件大小。
    • 在尝试使用 ImageMagick 剥离 exif 数据时,我注意到我最终得到的文件比我开始时要大。这使我相信 Imagemagick 正在对您想要剥离的数据进行编码,并将其存储在文件中的其他位置。称我为老式的,但是当我从文件中删除某些内容时,我希望文件大小尽可能小,如果大小不同的话。任何其他结果都表明数据挖掘。
    • 一个小问题:对我来说,列出的 2 个命令都不起作用,而是以下工作:jpegtran -copy none image.jpg newimage.jpg
    • @Codebeat 您需要添加参数-progressive 这将减小大小。
    • 请注意,jpegtran -copy none file.jpg 将删除“方向”元数据,这会使某些照片看起来旋转错误。
    【解决方案5】:

    我最近在 C 中进行了这个项目。下面的代码执行以下操作:

    1) 获取图像的当前方向。

    2) 通过消隐删除APP1(Exif 数据)和APP2(Flashpix 数据)中包含的所有数据。

    3) 重新创建APP1 方向标记并将其设置为原始值。

    4) 查找第一个 EOI 标记(图像结束)并在必要时截断文件。

    首先要注意的是:

    1) 这个程序用于我的尼康相机。尼康的 JPEG 格式在它创建的每个文件的最后添加了一些东西。他们通过创建第二个EOI 标记将此数据编码到图像文件的末尾。通常图像程序会读取到找到的第一个EOI 标记。尼康在此之后有我的程序截断的信息。

    2) 因为这是 Nikon 格式,所以它假定 big endian 字节顺序。如果您的图片文件使用little endian,则需要进行一些调整。

    3) 当尝试使用ImageMagick 去除 exif 数据时,我注意到我最终得到的文件比我开始时的大。这使我相信Imagemagick 正在对您想要剥离的数据进行编码,并将其存储在文件中的其他位置。称我为老式的,但是当我从文件中删除某些内容时,我希望文件大小尽可能小,如果大小不同的话。任何其他结果都表明数据挖掘。

    这里是代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <libgen.h>
    #include <string.h>
    #include <errno.h>
    
    // Declare constants.
    #define COMMAND_SIZE     500
    #define RETURN_SUCCESS     1
    #define RETURN_FAILURE     0
    #define WORD_SIZE         15
    
    int check_file_jpg (void);
    int check_file_path (char *file);
    int get_marker (void);
    char * ltoa (long num);
    void process_image (char *file);
    
    // Declare global variables.
    FILE *fp;
    int orientation;
    char *program_name;
    
    int main (int argc, char *argv[])
    {
    // Set program name for error reporting.
        program_name = basename(argv[0]);
    
    // Check for at least one argument.
        if(argc < 2)
        {
            fprintf(stderr, "usage: %s IMAGE_FILE...\n", program_name);
            exit(EXIT_FAILURE);
        }
    
    // Process all arguments.
        for(int x = 1; x < argc; x++)
            process_image(argv[x]);
    
        exit(EXIT_SUCCESS);
    }
    
    void process_image (char *file)
    {
        char command[COMMAND_SIZE + 1];
    
    // Check that file exists.
        if(check_file_path(file) == RETURN_FAILURE)
            return;
    
    // Check that file is an actual JPEG file.
        if(check_file_jpg() == RETURN_FAILURE)
        {
            fclose(fp);
            return;
        }
    
    // Jump to orientation marker and store value.
        fseek(fp, 55, SEEK_SET);
        orientation = fgetc(fp);
    
    // Recreate the APP1 marker with just the orientation tag listed.
        fseek(fp, 21, SEEK_SET);
        fputc(1, fp);
    
        fputc(1, fp);
        fputc(18, fp);
        fputc(0, fp);
        fputc(3, fp);
        fputc(0, fp);
        fputc(0, fp);
        fputc(0, fp);
        fputc(1, fp);
        fputc(0, fp);
        fputc(orientation, fp);
    
    // Blank the rest of the APP1 marker with '\0'.
        for(int x = 0; x < 65506; x++)
            fputc(0, fp);
    
    // Blank the second APP1 marker with '\0'.
        fseek(fp, 4, SEEK_CUR);
    
        for(int x = 0; x < 2044; x++)
            fputc(0, fp);
    
    // Blank the APP2 marker with '\0'.
        fseek(fp, 4, SEEK_CUR);
    
        for(int x = 0; x < 4092; x++)
            fputc(0, fp);
    
    // Jump the the SOS marker.
        fseek(fp, 72255, SEEK_SET);
    
        while(1)
        {
    // Truncate the file once the first EOI marker is found.
            if(fgetc(fp) == 255 && fgetc(fp) == 217)
            {
                strcpy(command, "truncate -s ");
                strcat(command, ltoa(ftell(fp)));
                strcat(command, " ");
                strcat(command, file);
                fclose(fp);
                system(command);
                break;
            }
        }
    }
    
    int get_marker (void)
    {
        int c;
    
    // Check to make sure marker starts with 0xFF.
        if((c = fgetc(fp)) != 0xFF)
        {
            fprintf(stderr, "%s: get_marker: invalid marker start (should be FF, is %2X)\n", program_name, c);
            return(RETURN_FAILURE);
        }
    
    // Return the next character.
        return(fgetc(fp));
    }
    
    int check_file_jpg (void)
    {
    // Check if marker is 0xD8.
        if(get_marker() != 0xD8)
        {
            fprintf(stderr, "%s: check_file_jpg: not a valid jpeg image\n", program_name);
            return(RETURN_FAILURE);
        }
    
        return(RETURN_SUCCESS);
    }
    
    int check_file_path (char *file)
    {
    // Open file.
        if((fp = fopen(file, "rb+")) == NULL)
        {
            fprintf(stderr, "%s: check_file_path: fopen failed (%s) (%s)\n", program_name, strerror(errno), file);
            return(RETURN_FAILURE);
        }
    
        return(RETURN_SUCCESS);
    }
    
    char * ltoa (long num)
    {
    // Declare variables.
            int ret;
            int x = 1;
            int y = 0;
            static char temp[WORD_SIZE + 1];
            static char word[WORD_SIZE + 1];
    
    // Stop buffer overflow.
            temp[0] = '\0';
    
    // Keep processing until value is zero.
            while(num > 0)
            {
                    ret = num % 10;
                    temp[x++] = 48 + ret;
                    num /= 10;
            }
    
    // Reverse the word.
            while(y < x)
            {
                    word[y] = temp[x - y - 1];
                    y++;
            }
    
            return word;
    }
    

    希望这对某人有所帮助!

    【讨论】:

      【解决方案6】:

      对于无损 EXIF 条,您可以使用libexif,即available with cygwin。删除 EXIF 和缩略图以匿名化图像:

      $ exif --remove --tag=0 --remove-thumbnail exif.jpg -o anonymized.jpg
      

      拖放.bat 文件以用于cygwin:

      @ECHO OFF
      exif --remove --tag=0 --remove-thumbnail %~1
      

      【讨论】:

      • 我试过这个并没有删除 GPS 位置数据。
      【解决方案7】:

      我们用它从 TIFF 文件中删除纬度数据:

      exiv2 mo -M"del Exif.GPSInfo.GPSLatitude" IMG.TIF 您可以在其中使用exiv2 -pa IMG.TIF 列出所有元数据。

      【讨论】:

      • OP 要求从 JPEG 中删除 everything,而不是仅从 tiff 文件中删除 GPSLatitude。因此,这并不能回答问题。
      【解决方案8】:

      为方便起见提示:如果您使用的是 Windows,则可以将 REG 文件应用到注册表,以在上下文菜单中安装一个条目,这样您就可以通过右键单击轻松删除元数据文件并选择命令。

      例如(记得编辑路径以指向您计算机上安装可执行文件的位置):


      对于 JPEG、JPG、JPE、JFIF 文件:命令“删除元数据
      (使用ExifTool,保留原始文件作为备份)
      exiftool -all= image.jpg

      JPG-RemoveExif.reg

      Windows Registry Editor Version 5.00
      [HKEY_CURRENT_USER\Software\Classes\jpegfile\shell\RemoveMetadata]
      @="Remove metadata"
      [HKEY_CURRENT_USER\Software\Classes\jpegfile\shell\RemoveMetadata\command]
      @="\"C:\\Path to\\exiftool.exe\" -all= \"%1\""
      [HKEY_CURRENT_USER\Software\Classes\jpegfile\shell\RemoveMetadata]
      "Icon"="C:\\Path to\\exiftool.exe,0"
      

      对于 PNG 文件:命令“转换为缩小的 PNG
      (使用ImageMagick,改变数据覆盖原文件)
      convert -background none -strip -set filename:n "%t" image.png "%[filename:n].png"

      PNG-Minify.reg

      Windows Registry Editor Version 5.00
      [HKEY_CURRENT_USER\Software\Classes\pngfile\shell\ConvertToMinifiedPNG]
      @="Convert to minified PNG"
      [HKEY_CURRENT_USER\Software\Classes\pngfile\shell\ConvertToMinifiedPNG\command]
      @="\"C:\\Path to\\convert.exe\" -background none -strip -set filename:n \"%%t\" \"%1\" \"%%[filename:n].png\""
      [HKEY_CURRENT_USER\Software\Classes\pngfile\shell\ConvertToMinifiedPNG]
      "Icon"="C:\\Path to\\convert.exe,0"
      

      相关:convert PNGs to ICO in context menu.

      【讨论】:

      • OP 明确要求提供 UNIX/Linux 解决方案,因此这与这个问题几乎无关。
      • 即使问题有 unix 标签,这仍然是 SO,不是 Unix SE 或 Ask Ubuntu。我可以想到很多时候我找到了一个答案(这并不完全针对这个问题),这对我解决别人的问题有帮助。我们不会仅仅为了提问者的利益而给出答案,你知道......恕我直言,没有必要对规则如此严格;这个问题在顶部已经有了很好的答案。
      • 这不是 SO 的工作方式。这是一个问答网站,答案实际上应该回答问题。而不是一个网络论坛,通常在任何线程中发布随机 apropos cmets。对于您的用例,在 SO 上,更好的方法是发布有关 Windows 注册表细节的新问题,可能直接与您的答案一起发布。然后您可以添加评论以参考相关问题。
      【解决方案9】:

      您可能还想查看Exiv2——它非常快(C++ 并且无需重新压缩),它是命令行,并且它还提供了一个可以链接的 EXIF 操作库。我不知道有多少 Linux 发行版提供了它,但在 CentOS 中,它目前在基础存储库中可用。

      用法:

      exiv2 rm image.jpg
      

      【讨论】:

      • 谢谢伙计,这是第一个在没有质量损失的情况下做得很好并且速度极快的人!哟值得+100!但是要删除所有类型的标题,我必须指定 -da 选项,否则它不会从 jpg 中删除 adobe photoshop/creator 信息。反正我在 Windows 上。
      • 谢谢!我想确认 exiv2 会显示 GPS 位置信息,以便我可以看到它已经消失了。打印的默认选项是“摘要”,不包括 GPS 信息。要查看您必须使用的所有信息:exiv2 -pa pr image.jpg
      • 请注意,这个工具破坏了我的一些 JPEG 文件的质量,幸运的是我有一个备份
      • @SteelBrain,这真的很奇怪——你能分享一张受此影响的 JPEG 图像吗?
      • 这是最安全的解决方案
      【解决方案10】:

      使用 imagemagick:

      convert <input file> -strip <output file>
      

      【讨论】:

      • 抱歉,-strip 不能按预期工作,因为 ImageMagick 仍然重新压缩 JPEG 文件。
      • 注意,顺便说一句,如果有人对文件进行其他转换,“-strip”可能很有用。另请注意,“-thumbnail 123x456”几乎等同于“-strip -resize 123x456”。
      • +1 因为这比下载新工具要容易得多。
      • 注意 -strip 删除颜色配置文件。对于任何试图在不丢失个人资料信息的情况下剥离 EXIF 数据的人,请在此处查看我的解决方案:stackoverflow.com/a/17516878/1854499
      • OP 应该更新这个答案,因为它有两次错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-21
      • 1970-01-01
      • 1970-01-01
      • 2015-08-26
      • 1970-01-01
      • 2014-05-03
      • 2023-02-21
      相关资源
      最近更新 更多