|
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, "Exif 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 |
@@ -367,42 +369,76 @@ gpujpeg_writer_write_exif(struct gpujpeg_encoder* encoder) |
367 | 369 | length_p[1] = length; |
368 | 370 | } |
369 | 371 |
|
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) |
375 | 374 | { |
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 != ':' ) { |
379 | 377 | ERROR_MSG("Error parsing Exif tag ID or missing type!\n"); |
380 | 378 | return false; |
381 | 379 | } |
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 |
387 | 383 | continue; |
388 | 384 | } |
389 | 385 | 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; |
393 | 389 | break; |
394 | 390 | } |
395 | 391 | } |
396 | | - if (type == ET_NONE) { |
| 392 | + if ( type == ET_NONE ) { |
397 | 393 | ERROR_MSG("Error parsing Exif tag type!\n"); |
398 | 394 | return false; |
399 | 395 | } |
400 | | - if (*endptr != '=') { |
| 396 | + if ( **endptr != '=' ) { |
401 | 397 | ERROR_MSG("Error parsing Exif - missing value!\n"); |
402 | 398 | return false; |
403 | 399 | } |
| 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 | + |
404 | 440 | 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 ) { |
406 | 442 | ERROR_MSG("Only unsigned integers currently supported!\n"); |
407 | 443 | return false; |
408 | 444 | } |
|
0 commit comments