How to remove EXIF data without recompressing the JPEG?

后端 未结 11 2054
梦毁少年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: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 
    #include 
    #include 
    #include 
    #include 
    
    // 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!

提交回复
热议问题