|
30 | 30 | #include "gpujpeg_exif.h" |
31 | 31 |
|
32 | 32 | #include <assert.h> |
| 33 | +#include <ctype.h> |
33 | 34 | #include <stdint.h> |
34 | 35 | #include <stdlib.h> |
35 | 36 | #include <string.h> |
@@ -98,20 +99,21 @@ enum exif_tiff_tag { |
98 | 99 | const struct exif_tiff_tag_info_t { |
99 | 100 | uint16_t id; |
100 | 101 | enum exif_tag_type type; |
| 102 | + const char *name; |
101 | 103 | } 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, "iExif IFD Pointer"}, |
108 | 110 | // 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 |
115 | 117 | }; |
116 | 118 |
|
117 | 119 | // misc constants |
@@ -373,39 +375,64 @@ gpujpeg_writer_write_exif(struct gpujpeg_encoder* encoder) |
373 | 375 | bool |
374 | 376 | gpujpeg_exif_add_tag(struct gpujpeg_exif_tags** exif_tags, const char* cfg) |
375 | 377 | { |
376 | | - char *endptr = (char *) cfg; |
377 | | - long tag_id = strtol(cfg, &endptr, 0); |
378 | | - if (*endptr != ':') { |
379 | | - ERROR_MSG("Error parsing Exif tag ID or missing type!\n"); |
| 378 | + if (strcmp(cfg, "help") == 0) { |
| 379 | + printf("Exif value syntax:\n" |
| 380 | + "\t" GPUJPEG_ENC_OPT_EXIF_TAG "=<ID>:<type>=<value>\n" |
| 381 | + "\t" GPUJPEG_ENC_OPT_EXIF_TAG "=<name>=<value>\n" |
| 382 | + "\t\tname must be a tag name known to GPUJPEG\n"); |
380 | 383 | return false; |
381 | 384 | } |
382 | | - endptr += 1; |
383 | 385 |
|
| 386 | + char *endptr = (char *) cfg; |
| 387 | + long tag_id = 0; |
384 | 388 | 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 |
387 | | - continue; |
| 389 | + |
| 390 | + if (!isdigit(*endptr)) { |
| 391 | + for (unsigned i = 0; i < ARR_SIZE(exif_tiff_tag_info); ++i) { |
| 392 | + size_t len = strlen(exif_tiff_tag_info[i].name); |
| 393 | + if ( strncasecmp(endptr, exif_tiff_tag_info[i].name, len) == 0 ) { |
| 394 | + tag_id = exif_tiff_tag_info[i].id; |
| 395 | + type = exif_tiff_tag_info[i].type; |
| 396 | + endptr += len; |
| 397 | + } |
388 | 398 | } |
389 | | - 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; |
393 | | - break; |
| 399 | + if (*endptr != '=') { |
| 400 | + ERROR_MSG("[Exif] Wrong tag name or missing value!\n"); |
| 401 | + return false; |
| 402 | + } |
| 403 | + } else { |
| 404 | + tag_id = strtol(cfg, &endptr, 0); |
| 405 | + if (*endptr != ':') { |
| 406 | + ERROR_MSG("Error parsing Exif tag ID or missing type!\n"); |
| 407 | + return false; |
| 408 | + } |
| 409 | + endptr += 1; |
| 410 | + for ( unsigned i = ET_NONE + 1; i < ET_END; ++i ) { |
| 411 | + if ( exif_tag_type_info[i].name == NULL ) { // unset/invalid type |
| 412 | + continue; |
| 413 | + } |
| 414 | + size_t len = strlen(exif_tag_type_info[i].name); |
| 415 | + if ( strncasecmp(endptr, exif_tag_type_info[i].name, len) == 0 ) { |
| 416 | + type = i; |
| 417 | + endptr += len; |
| 418 | + break; |
| 419 | + } |
| 420 | + } |
| 421 | + if ( type == ET_NONE ) { |
| 422 | + ERROR_MSG("Error parsing Exif tag type!\n"); |
| 423 | + return false; |
| 424 | + } |
| 425 | + if ( *endptr != '=' ) { |
| 426 | + ERROR_MSG("Error parsing Exif - missing value!\n"); |
| 427 | + return false; |
| 428 | + } |
| 429 | + unsigned numeric_unsigned = T_NUMERIC | T_UNSIGNED; |
| 430 | + if ( (exif_tag_type_info[type].type_flags & numeric_unsigned) != numeric_unsigned ) { |
| 431 | + ERROR_MSG("Only unsigned integers currently supported!\n"); |
| 432 | + return false; |
394 | 433 | } |
395 | 434 | } |
396 | | - if (type == ET_NONE) { |
397 | | - ERROR_MSG("Error parsing Exif tag type!\n"); |
398 | | - return false; |
399 | | - } |
400 | | - if (*endptr != '=') { |
401 | | - ERROR_MSG("Error parsing Exif - missing value!\n"); |
402 | | - return false; |
403 | | - } |
404 | | - unsigned numeric_unsigned = T_NUMERIC | T_UNSIGNED; |
405 | | - if ((exif_tag_type_info[type].type_flags & numeric_unsigned) != numeric_unsigned) { |
406 | | - ERROR_MSG("Only unsigned integers currently supported!\n"); |
407 | | - return false; |
408 | | - } |
| 435 | + |
409 | 436 | endptr += 1; |
410 | 437 | unsigned long long val = strtoull(endptr, &endptr, 0); |
411 | 438 | if (*endptr != '\0') { |
|
0 commit comments