Skip to content

Commit c2ad456

Browse files
committed
Exif: allow setting mutiple values
1 parent 590d1b8 commit c2ad456

File tree

1 file changed

+49
-15
lines changed

1 file changed

+49
-15
lines changed

src/gpujpeg_exif.c

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ enum exif_tiff_tag {
101101
ETIFF_RESOLUTION_UNIT, ///< Unit of X and Y resolution (mandatory)
102102
ETIFF_SOFTWARE, ///< Software used (optional)
103103
ETIFF_DATE_TIME, ///< File change date and time (recommeneded)
104+
ETIFF_WHITE_POINT, ///< White Point
104105
ETIFF_YCBCR_POSITIONING, ///< Y and C positioning (mandatory)
105106
ETIFF_EXIF_IFD_POINTER, ///< EXIF tag (mandatory)
106107
// 0th SubIFD Exif Private Tags
@@ -124,6 +125,7 @@ const struct exif_tiff_tag_info_t {
124125
[ETIFF_RESOLUTION_UNIT] = {0x128, ET_SHORT, 1, "ResolutionUnit" },
125126
[ETIFF_SOFTWARE] = {0x131, ET_ASCII, 0, "Sofware" },
126127
[ETIFF_DATE_TIME] = {0x132, ET_ASCII, 20, "DateTime" },
128+
[ETIFF_WHITE_POINT] = {0x13E, ET_RATIONAL, 2, "WhitePoint" },
127129
[ETIFF_YCBCR_POSITIONING] = {0x213, ET_SHORT, 1, "YCbCrPositioning"},
128130
[ETIFF_EXIF_IFD_POINTER] = {0x8769, ET_LONG, 1, "Exif IFD Pointer"},
129131
// Exif SubIFD
@@ -226,6 +228,7 @@ struct custom_tag_value
226228
uint16_t tag_id;
227229
enum exif_tag_type type;
228230
union value_u value;
231+
size_t val_count;
229232
};
230233
enum { CT_TIFF, CT_EXIF, CT_NUM };
231234
/// custom exif tags given by user
@@ -276,8 +279,8 @@ gpujpeg_write_ifd(struct gpujpeg_writer* writer, const uint8_t* start, size_t co
276279
}
277280
if ( custom_tags != NULL ) { // add user custom tags
278281
for ( unsigned i = 0; i < custom_tags->count; ++i ) {
279-
write_exif_tag(writer, custom_tags->vals[i].type, custom_tags->vals[i].tag_id, 1,
280-
custom_tags->vals[i].value, start, &end);
282+
write_exif_tag(writer, custom_tags->vals[i].type, custom_tags->vals[i].tag_id,
283+
custom_tags->vals[i].val_count, custom_tags->vals[i].value, start, &end);
281284
}
282285
// ensure custom_tags are in-ordered
283286
qsort(first_rec, (writer->buffer_current - first_rec) / IFD_ITEM_SZ, IFD_ITEM_SZ, ifd_sort);
@@ -433,9 +436,13 @@ usage()
433436
"\t" GPUJPEG_ENC_OPT_EXIF_TAG "=<ID>:<type>=<value>\n"
434437
"\t" GPUJPEG_ENC_OPT_EXIF_TAG "=<name>=<value>\n"
435438
"\t\tname must be a tag name known to GPUJPEG\n");
436-
printf("\nrecognized tag name (type):\n");
439+
printf("\n");
440+
printf("If multple values required, separate with a comma; rationals are in format num/den.\n");
441+
printf("\n");
442+
printf("recognized tag name (type, count):\n");
437443
for ( unsigned i = 0; i < ARR_SIZE(exif_tiff_tag_info); ++i ) {
438-
printf("\t- %s (%s)\n", exif_tiff_tag_info[i].name, exif_tag_type_info[exif_tiff_tag_info[i].type].name);
444+
printf("\t- %s (%s, %u)\n", exif_tiff_tag_info[i].name, exif_tag_type_info[exif_tiff_tag_info[i].type].name,
445+
exif_tiff_tag_info[i].count);
439446
}
440447
}
441448

@@ -473,15 +480,42 @@ gpujpeg_exif_add_tag(struct gpujpeg_exif_tags** exif_tags, const char* cfg)
473480
}
474481
}
475482

476-
unsigned numeric_unsigned = T_NUMERIC | T_UNSIGNED;
477-
if ( (exif_tag_type_info[type].type_flags & numeric_unsigned) != numeric_unsigned ) {
478-
ERROR_MSG("Only unsigned integers currently supported!\n");
479-
return false;
480-
}
481483
endptr += 1;
482-
unsigned long long val = strtoull(endptr, &endptr, 0);
483-
if (*endptr != '\0') {
484-
ERROR_MSG("Trainling data in Exif value!\n");
484+
void* val_alloc = NULL;
485+
size_t val_count = 0;
486+
do {
487+
if ( *endptr == ',' ) {
488+
endptr += 1;
489+
}
490+
if ( (exif_tag_type_info[type].type_flags & T_NUMERIC) != 0U ) {
491+
unsigned long long val = strtoull(endptr, &endptr, 0);
492+
val_count += 1;
493+
uint32_t* val_a = realloc(val_alloc, val_count * sizeof *val_a);
494+
val_a[val_count - 1] = val;
495+
val_alloc = val_a;
496+
}
497+
else if ( (exif_tag_type_info[type].type_flags & T_RATIONAL) != 0U ) {
498+
unsigned long long num = strtoull(endptr, &endptr, 0);
499+
if ( *endptr != '/' ) {
500+
ERROR_MSG("[Exif] Malformed rational, expected '/', got '%c'!\n", *endptr);
501+
}
502+
endptr += 1;
503+
unsigned long long den = strtoull(endptr, &endptr, 0);
504+
val_count += 1;
505+
uint32_t* val_a = realloc(val_alloc, val_count * 2 * sizeof *val_a);
506+
val_a[2 * (val_count - 1)] = num;
507+
val_a[(2 * (val_count - 1)) + 1] = den;
508+
val_alloc = val_a;
509+
}
510+
else {
511+
ERROR_MSG("Only integer or rational values are currently supported!\n");
512+
return false;
513+
}
514+
} while ( *endptr == ',' );
515+
516+
if ( *endptr != '\0' ) {
517+
free(val_alloc);
518+
ERROR_MSG("Trainling data in Exif value: %s\n", endptr);
485519
return false;
486520
}
487521

@@ -495,9 +529,9 @@ gpujpeg_exif_add_tag(struct gpujpeg_exif_tags** exif_tags, const char* cfg)
495529
new_size * sizeof (*exif_tags)->tags[table_idx].vals[0]);
496530
(*exif_tags)->tags[table_idx].vals[new_size - 1].tag_id = tag_id;
497531
(*exif_tags)->tags[table_idx].vals[new_size - 1].type = type;
498-
uint32_t *val_a = malloc(sizeof *val_a);
499-
*val_a = val;
500-
(*exif_tags)->tags[table_idx].vals[new_size - 1].value.uvalue = val_a;
532+
assert(val_alloc != NULL);
533+
(*exif_tags)->tags[table_idx].vals[new_size - 1].value.uvalue = val_alloc;
534+
(*exif_tags)->tags[table_idx].vals[new_size - 1].val_count = val_count;
501535

502536
return true;
503537
}

0 commit comments

Comments
 (0)