Recentemente ho intrapreso questo progetto in C. Il codice di seguito esegue le seguenti operazioni:.
1) Ottiene l'orientamento corrente dell'immagine
2) rimuove tutti i dati contenuti nel APP1
(dati Exif) e APP2
(dati Flashpix) per tranciatura.
3) ricrea il marcatore APP1
orientamento e imposta al valore originale.
4) Trova il primo indicatore EOI
(Fine dell'immagine) e tronca il file se necessario.
Alcune cose da notare prima sono:
1) Questo programma viene utilizzato per la mia macchina fotografica Nikon. Il formato JPEG di Nikon aggiunge qualcosa alla fine di ogni file che crea. Codificano questi dati fino alla fine del file immagine creando un secondo indicatore EOI
. Normalmente i programmi di immagine leggono fino al primo marker EOI
trovato. Nikon ha informazioni dopo ciò che il mio programma tronca.
2) Poiché questo è per il formato Nikon, assume l'ordine dei byte big endian
. Se il file immagine utilizza little endian
, è necessario apportare alcune modifiche.
3) Quando si tenta di utilizzare ImageMagick
per eliminare i dati exif, ho notato che ho finito con un file più grande di quello che ho iniziato con. Questo mi porta a credere che codifichi i dati che vuoi togliere e li stia conservando da qualche altra parte nel file. Chiamami vecchio stile, ma quando rimuovo qualcosa da un file, voglio una dimensione del file più piccola se non della stessa dimensione. Qualsiasi altro risultato suggerisce il data mining.
Ed ecco il codice:
#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;
}
Spero che questo aiuti qualcuno!
Cura di modificare il post e aggiungere un esempio di riga di comando? –
sicuro :) anche se è piuttosto semplice – oedo
Alcune altre opzioni interessanti: "-o outfile.jpg" o "-out outfile.jpg", "-overwrite_original" o "-overwrite_original_in_place", "-P" o "-preserve", "-r" o "-recurse" –