Skip to content

Commit a8acf83

Browse files
committed
allow Exif tag identification by name
1 parent 3be5a2c commit a8acf83

File tree

2 files changed

+68
-32
lines changed

2 files changed

+68
-32
lines changed

src/gpujpeg_encoder.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,7 @@ gpujpeg_encoder_print_options() {
760760
"] - whether is the input image should be vertically flipped (prior encode)\n");
761761
printf("\t" GPUJPEG_ENC_OPT_CHANNEL_REMAP "=XYZ[W] - input channel mapping, eg. '210F' for GBRX,\n"
762762
"\t\t'210' for GBR; special placeholders 'F' and 'Z' to set a channel to all-ones or all-zeros\n");
763-
printf("\t" GPUJPEG_ENC_OPT_EXIF_TAG "=<ID>:<type>=<value> - custom EXIF tag\n");
763+
printf("\t" GPUJPEG_ENC_OPT_EXIF_TAG "=<key>=<value>|help - custom EXIF tag (use help for syntax)\n");
764764
}
765765

766766
/* Documented at declaration */

src/gpujpeg_exif.c

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "gpujpeg_exif.h"
3131

3232
#include <assert.h>
33+
#include <ctype.h>
3334
#include <stdint.h>
3435
#include <stdlib.h>
3536
#include <string.h>
@@ -98,20 +99,21 @@ enum exif_tiff_tag {
9899
const struct exif_tiff_tag_info_t {
99100
uint16_t id;
100101
enum exif_tag_type type;
102+
const char *name;
101103
} exif_tiff_tag_info[] = {
102-
[ETIFF_XRESOLUTION] = {0x11A, ET_RATIONAL},
103-
[ETIFF_YRESOLUTION] = {0x11B, ET_RATIONAL},
104-
[ETIFF_RESOLUTION_UNIT] = {0x128, ET_SHORT },
105-
[ETIFF_SOFTWARE] = {0x131, ET_ASCII },
106-
[ETIFF_YCBCR_POSITIONING] = {0x213, ET_SHORT },
107-
[ETIFF_EXIF_IFD_POINTER] = {0x8769, ET_LONG },
104+
[ETIFF_XRESOLUTION] = {0x11A, ET_RATIONAL, "XResolution" },
105+
[ETIFF_YRESOLUTION] = {0x11B, ET_RATIONAL, "YResolution" },
106+
[ETIFF_RESOLUTION_UNIT] = {0x128, ET_SHORT, "ResolutionUnit" },
107+
[ETIFF_SOFTWARE] = {0x131, ET_ASCII, "Sofware" },
108+
[ETIFF_YCBCR_POSITIONING] = {0x213, ET_SHORT, "YCbCrPositioning" },
109+
[ETIFF_EXIF_IFD_POINTER] = {0x8769, ET_LONG, "Exif IFD Pointer"},
108110
// Exif SubIFD
109-
[EEXIF_EXIF_VERSION] = {0x9000, ET_UNDEFINED },
110-
[EEXIF_COMPONENTS_CONFIGURATION] = {0x9101, ET_UNDEFINED },
111-
[EEXIF_FLASHPIX_VERSION] = {0xA000, ET_UNDEFINED },
112-
[EEXIF_COLOR_SPACE] = {0xA001, ET_SHORT },
113-
[EEXIF_PIXEL_X_DIMENSION] = {0xA002, ET_SHORT }, // type can be also LONG
114-
[EEXIF_PIXEL_Y_DIMENSION] = {0xA003, ET_SHORT }, // ditto
111+
[EEXIF_EXIF_VERSION] = {0x9000, ET_UNDEFINED, "ExifVersion" },
112+
[EEXIF_COMPONENTS_CONFIGURATION] = {0x9101, ET_UNDEFINED, "ComponentConfiguration"},
113+
[EEXIF_FLASHPIX_VERSION] = {0xA000, ET_UNDEFINED, "FlashPixVersion" },
114+
[EEXIF_COLOR_SPACE] = {0xA001, ET_SHORT, "ColorSpace" },
115+
[EEXIF_PIXEL_X_DIMENSION] = {0xA002, ET_SHORT, "PixelXDimension" }, // type can be also LONG
116+
[EEXIF_PIXEL_Y_DIMENSION] = {0xA003, ET_SHORT, "PixelYDimension" }, // ditto
115117
};
116118

117119
// misc constants
@@ -367,42 +369,76 @@ gpujpeg_writer_write_exif(struct gpujpeg_encoder* encoder)
367369
length_p[1] = length;
368370
}
369371

370-
/**
371-
* add user-provided Exif tag
372-
*/
373-
bool
374-
gpujpeg_exif_add_tag(struct gpujpeg_exif_tags** exif_tags, const char* cfg)
372+
static bool
373+
get_numeric_tag_type(char** endptr, long* tag_id, enum exif_tag_type* type)
375374
{
376-
char *endptr = (char *) cfg;
377-
long tag_id = strtol(cfg, &endptr, 0);
378-
if (*endptr != ':') {
375+
*tag_id = strtol(*endptr, endptr, 0);
376+
if ( **endptr != ':' ) {
379377
ERROR_MSG("Error parsing Exif tag ID or missing type!\n");
380378
return false;
381379
}
382-
endptr += 1;
383-
384-
enum exif_tag_type type = ET_NONE;
385-
for (unsigned i = ET_NONE + 1; i < ET_END; ++i) {
386-
if ( exif_tag_type_info[i].name == NULL) { // unset/invalid type
380+
*endptr += 1;
381+
for ( unsigned i = ET_NONE + 1; i < ET_END; ++i ) {
382+
if ( exif_tag_type_info[i].name == NULL ) { // unset/invalid type
387383
continue;
388384
}
389385
size_t len = strlen(exif_tag_type_info[i].name);
390-
if (strncasecmp(endptr, exif_tag_type_info[i].name, len) == 0 ) {
391-
type = i;
392-
endptr += len;
386+
if ( strncasecmp(*endptr, exif_tag_type_info[i].name, len) == 0 ) {
387+
*type = i;
388+
*endptr += len;
393389
break;
394390
}
395391
}
396-
if (type == ET_NONE) {
392+
if ( type == ET_NONE ) {
397393
ERROR_MSG("Error parsing Exif tag type!\n");
398394
return false;
399395
}
400-
if (*endptr != '=') {
396+
if ( **endptr != '=' ) {
401397
ERROR_MSG("Error parsing Exif - missing value!\n");
402398
return false;
403399
}
400+
return true;
401+
}
402+
403+
/**
404+
* add user-provided Exif tag
405+
*/
406+
bool
407+
gpujpeg_exif_add_tag(struct gpujpeg_exif_tags** exif_tags, const char* cfg)
408+
{
409+
if (strcmp(cfg, "help") == 0) {
410+
printf("Exif value syntax:\n"
411+
"\t" GPUJPEG_ENC_OPT_EXIF_TAG "=<ID>:<type>=<value>\n"
412+
"\t" GPUJPEG_ENC_OPT_EXIF_TAG "=<name>=<value>\n"
413+
"\t\tname must be a tag name known to GPUJPEG\n");
414+
return false;
415+
}
416+
417+
char *endptr = (char *) cfg;
418+
long tag_id = 0;
419+
enum exif_tag_type type = ET_NONE;
420+
421+
if (isdigit(*endptr)) {
422+
if ( !get_numeric_tag_type(&endptr, &tag_id, &type) ) {
423+
return false;
424+
}
425+
} else {
426+
for (unsigned i = 0; i < ARR_SIZE(exif_tiff_tag_info); ++i) {
427+
size_t len = strlen(exif_tiff_tag_info[i].name);
428+
if ( strncasecmp(endptr, exif_tiff_tag_info[i].name, len) == 0 ) {
429+
tag_id = exif_tiff_tag_info[i].id;
430+
type = exif_tiff_tag_info[i].type;
431+
endptr += len;
432+
}
433+
}
434+
if (*endptr != '=') {
435+
ERROR_MSG("[Exif] Wrong tag name or missing value!\n");
436+
return false;
437+
}
438+
}
439+
404440
unsigned numeric_unsigned = T_NUMERIC | T_UNSIGNED;
405-
if ((exif_tag_type_info[type].type_flags & numeric_unsigned) != numeric_unsigned) {
441+
if ( (exif_tag_type_info[type].type_flags & numeric_unsigned) != numeric_unsigned ) {
406442
ERROR_MSG("Only unsigned integers currently supported!\n");
407443
return false;
408444
}

0 commit comments

Comments
 (0)