Jak usunąć dane EXIF ​​bez ponownej kompresji JPEG?

127

Chcę usunąć informacje EXIF ​​(w tym miniaturę, metadane, informacje o aparacie ... wszystko!) Z plików JPEG, ale nie chcę ich ponownie kompresować, ponieważ ponowna kompresja JPEG obniży jakość, a także zwykle zwiększy rozmiar pliku.

Szukam rozwiązania Unix / Linux, nawet lepszego, jeśli używam wiersza poleceń. Jeśli to możliwe, użyj ImageMagick (narzędzie do konwersji). Jeśli to nie jest możliwe, mały skrypt w Pythonie, Perlu, PHP (lub innym popularnym języku w systemie Linux) byłby w porządku.

Jest podobne pytanie, ale związane z .NET .

Denilson Sá Maia
źródło
1
related: askubuntu.com/questions/260810/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

166

exiftool robi to za mnie, jest napisane w perlu, więc powinno działać dla ciebie na każdym systemie operacyjnym

https://exiftool.org/

stosowanie :

exiftool -all= image.jpg
chris
źródło
6
Kilka innych interesujących opcji: „-o plik wyjściowy.jpg” lub „-out plik wyjściowy.jpg”, „-overwrite_original” lub „-overwrite_original_in_place”, „-P” lub „-preserve”, „-r” lub „-recurse”
Denilson Sá Maia
6
Właśnie natknąłem się na ten wątek, szukając tego samego. Pomyślałem, że dodam tutaj komentarz dla użytkowników Ubuntu: Skrypt jest dostępny w repozytoriach Ubuntu jako libimage-exiftool-perl: sudo apt-get install libimage-exiftool-perl
user605331
7
Lub z homebrewbrew install exiftool
cwd
6
Jeśli naprawdę ufasz -overwrite_originalprzełącznikowi dodawania programu, a program nie utworzy plików kopii zapasowej.
Salman A
10
Zaakceptowane użycie z opcją -all = usuwa WSZYSTKIE tagi z twojego image.jpg! Prawidłowa odpowiedź brzmiałabyexiftool -EXIF= image.jpg
PeterCo
85

Z imagemagick:

convert <input file> -strip <output file>
JayM
źródło
21
Przepraszamy, ale -strip nie działa zgodnie z oczekiwaniami, ponieważ ImageMagick nadal ponownie kompresuje plik JPEG.
Denilson Sá Maia
5
Nawiasem mówiąc, to „-strip” może być przydatne, jeśli ktoś wykonuje inne transformacje z plikiem. Zauważ również, że „-thumbnail 123x456” jest PRAWIE równoważne z „-strip -resize 123x456”.
Denilson Sá Maia
15
+1, ponieważ było to o wiele łatwiejsze niż pobranie nowego narzędzia.
Dave Dopson,
13
Uwaga -stripusuwa profile kolorów. Dla każdego, kto próbuje usunąć dane EXIF ​​bez utraty informacji o profilu, zobacz moje rozwiązanie tutaj: stackoverflow.com/a/17516878/1854499
Robbert,
2
OP powinien zaktualizować tę odpowiedź, ponieważ jest dwukrotnie błędna.
berbt
49

ImageMagick ma parametr -strip , ale przed zapisaniem ponownie kompresuje obraz. Zatem ten parametr jest dla mnie bezużyteczny.

W tym temacie na forum ImageMagick wyjaśniono, że ImageMagick nie obsługuje bezstratnych operacji JPEG (jeśli to się zmieni, prosimy o przesłanie komentarza z linkiem!) I sugeruje użycie jpegtran (z libjpeg):

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

(Jeśli nie jesteś pewien, czy odpowiadam na moje własne pytanie, przeczytaj to i to i to )

Denilson Sá Maia
źródło
1
Wypróbowano metodę jpegtran, ale w większości przypadków zwiększa ona rozmiar pliku zamiast go zmniejszać. W większości przypadków chcesz to zrobić, aby zmniejszyć rozmiar pliku.
Codebeat
1
Próbując użyć ImageMagick do usunięcia danych exif, zauważyłem, że otrzymałem większy plik niż ten, od którego zacząłem. To prowadzi mnie do przekonania, że ​​Imagemagick koduje dane, które chcesz usunąć, i przechowuje je w innym miejscu w pliku. Nazwij mnie staroświeckim, ale kiedy usuwam coś z pliku, chcę, aby rozmiar pliku był mniejszy, jeśli nie taki sam. Wszelkie inne wyniki sugerują eksplorację danych.
Deanie
1
Drobna uwaga: dla mnie żadne z 2 wymienionych poleceń nie działało, zamiast tego działa następujące: jpegtran -copy none image.jpg newimage.jpg
ibic
@Codebeat Musisz dodać parametr -progressiveSpowoduje to zmniejszenie rozmiaru.
Tom
31

Możesz również zajrzeć do Exiv2 - jest naprawdę szybki (C ++ i bez rekompresji), jest to wiersz poleceń, a także zapewnia bibliotekę do manipulacji EXIF, z którą możesz się połączyć. Nie wiem, ile dystrybucji Linuksa udostępnia, ale w CentOS jest obecnie dostępny w repozytorium podstawowym.

Stosowanie:

exiv2 rm image.jpg
Bogdan Stăimentscu
źródło
1
Dzięki człowiekowi, to pierwszy, który wykonuje swoją pracę bardzo dobrze, bez utraty jakości i błyskawicznie! Zasługujesz na +100! Ale aby usunąć WSZYSTKIE typy nagłówków, muszę określić opcję -da, w przeciwnym razie nie usunie ona informacji Adobe Photoshop / Creator z plików jpg. I tak jestem na Windowsie.
Codebeat
Dzięki! Chciałem potwierdzić, że exiv2 pokaże informacje o lokalizacji GPS, abym mógł zobaczyć, że zniknęło. Domyślną opcją drukowania jest „podsumowanie”, które nie obejmuje informacji GPS. Aby zobaczyć wszystkie informacje, których musisz użyć: exiv2 -pa pr image.jpg
Rob Russell
Pamiętaj, że to narzędzie zniszczyło jakość niektórych moich plików JPEG, na szczęście miałem kopię zapasową
Steel Brain
@SteelBrain, to naprawdę dziwne - czy możesz udostępnić jeden z obrazów JPEG, których to dotyczy?
Bogdan Stăowestcu
To najbezpieczniejsze rozwiązanie
Mohammed Shareef C
20

Proponuję jhead:

man jhead
jhead -purejpg image.jpg

Tylko 123 KB na debianie / ubuntu, nie kompresuje ponownie. Zauważ jednak, że mutuje obraz, więc skopiuj oryginał, jeśli go potrzebujesz.

VasiliNovikov
źródło
2

Niedawno podjąłem się tego projektu w C. Poniższy kod wykonuje następujące czynności:

1) Pobiera bieżącą orientację obrazu.

2) Usuwa wszystkie dane zawarte w APP1 (Dane Exif) i APP2(Dane Flashpix) przez wygaszenie.

3) odtwarza APP1 znacznik orientacji i przywraca mu oryginalną wartość.

4) Znajduje pierwszy EOI znacznik (Koniec obrazu) iw razie potrzeby obcina plik.

Najpierw należy zwrócić uwagę na:

1) Ten program jest używany w moim aparacie Nikon. Format JPEG firmy Nikon dodaje coś na samym końcu każdego tworzonego pliku. Kodują te dane na końcu pliku obrazu, tworząc drugi EOIznacznik. Zwykle programy graficzne czytają do pierwszegoEOI znalezionego znacznika. Firma Nikon ma informacje, które następnie są obcięte przez mój program.

2) Ponieważ jest to format firmy Nikon, przyjmuje big endiankolejność bajtów. Jeśli plik obrazu używa little endian, należy wprowadzić pewne poprawki.

3) Kiedy próbowałem ImageMagickusunąć dane exif, zauważyłem, że otrzymałem większy plik niż ten, od którego zacząłem. To prowadzi mnie do przekonania, że Imagemagickkoduje dane, które chcesz usunąć, i przechowuje je w innym miejscu w pliku. Nazwij mnie staroświeckim, ale kiedy usuwam coś z pliku, chcę, aby rozmiar pliku był mniejszy, jeśli nie taki sam. Wszelkie inne wyniki sugerują eksplorację danych.

A oto kod:

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

Mam nadzieję, że to komuś pomoże!

Deanie
źródło
1

Wskazówka dla wygody: jeśli korzystasz z systemu Windows, możesz zastosować plik REG do rejestru, aby zainstalować wpis w menu kontekstowym, dzięki czemu możesz łatwo usunąć metadane, klikając plik prawym przyciskiem myszy i wybierając polecenie.

Na przykład (pamiętaj, aby edytować ścieżki tak, aby wskazywały miejsce instalacji plików wykonywalnych na komputerze):


W przypadku plików JPEG, JPG, JPE, JFIF: polecenie „ Usuń metadane
(przy użyciu ExifTool , zachowuje oryginalny plik jako kopię zapasową)
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"

W przypadku plików PNG: polecenie „ Konwertuj na zminimalizowany plik PNG
(przy użyciu programu ImageMagick zmienia dane nadpisując oryginalny plik)
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"

Powiązane: przekonwertuj pliki PNG na ICO w menu kontekstowym .

geekley
źródło
1

Użyliśmy tego do usunięcia danych szerokości geograficznej z pliku TIFF:

exiv2 mo -M"del Exif.GPSInfo.GPSLatitude" IMG.TIF gdzie możesz użyć exiv2 -pa IMG.TIFdo wyświetlenia wszystkich metadanych.

Muhammet Ali Asan
źródło
1

W przypadku bezstratnego paska EXIF ​​możesz użyć libexif , który jest dostępny z cygwin . Usuń zarówno EXIF, jak i miniaturę, aby anonimizować obraz:

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

.batPlik przeciągnij i upuść do użytku z cygwin:

@ECHO OFF
exif --remove --tag=0 --remove-thumbnail %~1
radioxoma
źródło
0

Inne oprogramowanie:

MetAbility QuickFix

„MetabilityQuickFix usuwa wszystkie dane osobowe i dane lokalizacji GPS ze wszystkich zdjęć za pomocą jednego kliknięcia myszą. Wyczyści wszystkie elementy metadanych z bloków danych Exif, Iptc i XMP bezpiecznie z plików JPEG i automatycznie tworzy kopie zapasowe oryginalnych plików "

Stripper JPEG i PNG

„Narzędzie do usuwania / czyszczenia / usuwania zbędnych metadanych (śmieci) z plików JPG / JPEG / JFIF i PNG. NIE MA WPŁYWU na jakość obrazu. Obejmuje obsługę wiersza poleceń. Po prostu określ folder lub plik w wierszu poleceń (dozwolone symbole wieloznaczne)”

Remus Rigo
źródło
0

Jeśli już używasz jpegoptim, możesz go również użyć do usunięcia exif.

jpegoptim -s *
strifel
źródło