How to remove EXIF data without recompressing the JPEG?

后端 未结 11 1976
梦毁少年i
梦毁少年i 2020-12-02 05:07

I want to remove the EXIF information (including thumbnail, metadata, camera info... everything!) from JPEG files, but I don\'t want to recompress it, as recompressing the J

相关标签:
11条回答
  • 2020-12-02 05:10

    You might also want to look into Exiv2 -- it's really fast (C++ and no recompression), it's command line, and it also provides a library for EXIF manipulation you can link against. I don't know how many Linux distros make it available, but in CentOS it's currently available in the base repo.

    Usage:

    exiv2 rm image.jpg
    
    0 讨论(0)
  • 2020-12-02 05:14

    Other Software:

    MetAbility QuickFix

    "MetabilityQuickFix strips all your personal information and GPS location data from all your photos, with just a single mouse click. It scrubs all metadata items form Exif, Iptc and XMP data blocks safely from your JPEG files and automatically makes backup copies of the original files"

    JPEG & PNG Stripper

    "A tool for stripping/cleaning/removing uncessary metadata (junk) from JPG/JPEG/JFIF & PNG files. The image quality IS NOT AFFECTED. Includes command line support. Just specify a folder or file on the commandline (wildcards allowed)"

    0 讨论(0)
  • 2020-12-02 05:15

    I recently undertook this project in C. The code below does the following:

    1) Gets the current orientation of the image.

    2) Removes all data contained in APP1 (Exif data) and APP2 (Flashpix data) by blanking.

    3) Recreates the APP1 orientation marker and sets it to the original value.

    4) Finds the first EOI marker (End of Image) and truncates the file if nessasary.

    Some things to note first are:

    1) This program is used for my Nikon camera. Nikon's JPEG format adds somthing to the very end of each file it creates. They encode this data on to the end of the image file by creating a second EOI marker. Normally image programs read up to the first EOI marker found. Nikon has information after this which my program truncates.

    2) Because this is for Nikon format, it assumes big endian byte order. If your image file uses little endian, some adjustments need to be made.

    3) When trying to use ImageMagick to strip exif data, I noticed that I ended up with a larger file than what I started with. This leads me to believe that Imagemagick is encoding the data you want stripped away, and is storing it somewhere else in the file. Call me old fashioned, but when I remove something from a file, I want a file size the be smaller if not the same size. Any other results suggest data mining.

    And here is the code:

    #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;
    }
    

    Hope this helps someone!

    0 讨论(0)
  • 2020-12-02 05:19

    ImageMagick has the -strip parameter, but it recompresses the image before saving. Thus, this parameter is useless for my need.

    This topic from ImageMagick forum explains that there is no support for JPEG lossless operations in ImageMagick (whenever this changes, please post a comment with a link!), and suggests using jpegtran (from libjpeg):

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

    (If you are unsure about me answering my own question, read this and this and this)

    0 讨论(0)
  • 2020-12-02 05:25

    For lossless EXIF strip you can use libexif, which is available with cygwin. Remove both EXIF and thumbnail to anonymize an image:

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

    Drag-n-drop .bat file for use with cygwin:

    @ECHO OFF
    exif --remove --tag=0 --remove-thumbnail %~1
    
    0 讨论(0)
  • 2020-12-02 05:29

    Hint for convenience: If you are on Windows, you can apply a REG file to the registry, to install an entry in the context menu, so you can easily remove metadata by right-clicking the file and selecting the command.

    For example (remember to edit the paths to point to where the executables are installed on your computer):


    For JPEG,JPG,JPE,JFIF files: command "Remove metadata"
    (using ExifTool, preserves original file as backup)
    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"
    

    For PNG files: command "Convert to minified PNG"
    (using ImageMagick, changes data overwriting original file)
    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"
    

    Related: convert PNGs to ICO in context menu.

    0 讨论(0)
提交回复
热议问题