Gần đây tôi đã thực hiện dự án này trong C. Đoạn mã dưới đây thực hiện như sau:
1) Lấy hướng hiện tại của hình ảnh.
2) Xóa tất cả dữ liệu có trong APP1
(dữ liệu Exif) và APP2
(dữ liệu Flashpix) bằng cách xóa.
3) Tái tạo APP1
điểm đánh dấu định hướng và đặt nó về giá trị ban đầu.
4) Tìm EOI
điểm đánh dấu đầu tiên (Kết thúc hình ảnh) và cắt bớt tệp nếu không cần thiết.
Một số điều cần lưu ý đầu tiên là:
1) Chương trình này được sử dụng cho máy ảnh Nikon của tôi. Định dạng JPEG của Nikon thêm một số thứ vào cuối mỗi tệp mà nó tạo. Họ mã hóa dữ liệu này đến cuối tệp hình ảnh bằng cách tạo EOI
điểm đánh dấu thứ hai . Thông thường các chương trình hình ảnh đọc đến EOI
điểm đánh dấu đầu tiên được tìm thấy. Sau đó, Nikon có thông tin mà chương trình của tôi cắt ngắn.
2) Vì đây là định dạng của Nikon, nên nó giả định big endian
thứ tự byte. Nếu tệp hình ảnh của bạn sử dụng little endian
, một số điều chỉnh cần phải được thực hiện.
3) Khi cố gắng sử dụng ImageMagick
để tách dữ liệu exif, tôi nhận thấy rằng tôi đã kết thúc với một tệp lớn hơn so với những gì tôi bắt đầu. Điều này khiến tôi tin rằng Imagemagick
đang mã hóa dữ liệu bạn muốn loại bỏ và đang lưu trữ nó ở một nơi khác trong tệp. Gọi tôi là lỗi thời, nhưng khi tôi xóa một cái gì đó khỏi một tập tin, tôi muốn một kích thước tập tin nhỏ hơn nếu không cùng kích thước. Bất kỳ kết quả khác đề nghị khai thác dữ liệu.
Và đây là mã:
#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;
}
Hy vọng điều này sẽ giúp được ai đó!