Skip to content

Commit 2f8369f

Browse files
committed
Exif: write Orientation+DateTime by default
both are recommended but check that user doesn't override, eg. Orientation
1 parent b06a893 commit 2f8369f

File tree

1 file changed

+48
-13
lines changed

1 file changed

+48
-13
lines changed

src/gpujpeg_exif.c

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <stdint.h>
3535
#include <stdlib.h>
3636
#include <string.h>
37+
#include <time.h> // for strftime
3738

3839
#ifdef _WIN32
3940
#define strncasecmp _strnicmp
@@ -86,6 +87,7 @@ enum exif_tiff_tag {
8687
ETIFF_YRESOLUTION, ///< Image resolution in height direction (mandatory)
8788
ETIFF_RESOLUTION_UNIT, ///< Unit of X and Y resolution (mandatory)
8889
ETIFF_SOFTWARE, ///< Software used (optional)
90+
ETIFF_DATE_TIME, ///< File change date and time (recommeneded)
8991
ETIFF_YCBCR_POSITIONING, ///< Y and C positioning (mandatory)
9092
ETIFF_EXIF_IFD_POINTER, ///< EXIF tag (mandatory)
9193
// 0th SubIFD Exif Private Tags
@@ -107,6 +109,7 @@ const struct exif_tiff_tag_info_t {
107109
[ETIFF_YRESOLUTION] = {0x11B, ET_RATIONAL, "YResolution" },
108110
[ETIFF_RESOLUTION_UNIT] = {0x128, ET_SHORT, "ResolutionUnit" },
109111
[ETIFF_SOFTWARE] = {0x131, ET_ASCII, "Sofware" },
112+
[ETIFF_DATE_TIME] = {0x132, ET_ASCII, "DateTime" },
110113
[ETIFF_YCBCR_POSITIONING] = {0x213, ET_SHORT, "YCbCrPositioning" },
111114
[ETIFF_EXIF_IFD_POINTER] = {0x8769, ET_LONG, "Exif IFD Pointer"},
112115
// Exif SubIFD
@@ -120,6 +123,7 @@ const struct exif_tiff_tag_info_t {
120123

121124
// misc constants
122125
enum {
126+
ETIFF_ORIENT_HORIZONTAL = 1, // normal
123127
ETIFF_CENTER = 1,
124128
ETIFF_SRGB = 1,
125129
ETIFF_INCHES = 2,
@@ -294,35 +298,66 @@ gpujpeg_write_ifd(struct gpujpeg_writer* writer, const uint8_t* start, size_t co
294298
writer->buffer_current = end; // jump after the section Value longer than 4Byte of 0th IFD
295299
}
296300

301+
/**
302+
* from tags remove the items that are overriden by custom_tags
303+
*/
304+
static size_t
305+
remove_overriden(size_t count, struct tag_value tags[], const struct custom_exif_tags* custom_tags)
306+
{
307+
for ( unsigned i = 0; i < custom_tags->count; ++i ) {
308+
for ( unsigned j = 0; j < count; ++j ) {
309+
if ( custom_tags->vals[i].tag_id == exif_tiff_tag_info[tags[j].tag].id ) {
310+
memmove(tags + j, tags + j + 1, (count - j - 1) * sizeof(tags[0]));
311+
count -= 1;
312+
break;
313+
}
314+
}
315+
}
316+
return count;
317+
}
318+
297319
static void
298320
gpujpeg_write_0th(struct gpujpeg_encoder* encoder, const uint8_t* start)
299321
{
300-
const struct tag_value tags[] = {
301-
{ETIFF_XRESOLUTION, {.urational = {72, 1}} },
302-
{ETIFF_YRESOLUTION, {.urational = {72, 1}} },
303-
{ETIFF_RESOLUTION_UNIT, {.uvalue = ETIFF_INCHES}},
304-
{ETIFF_SOFTWARE, {.csvalue = "GPUJPEG"} },
305-
{ETIFF_YCBCR_POSITIONING, {.uvalue = ETIFF_CENTER}}, // center
306-
{ETIFF_EXIF_IFD_POINTER, {0} }, // value later; should be last
322+
char date_time[] = " : : : : "; // unknown val by Exif 2.3
323+
time_t now = time(NULL);
324+
(void) strftime(date_time, sizeof date_time, "%Y:%m:%d %H:%M:%S", localtime(&now));
325+
struct tag_value tags[] = {
326+
{ETIFF_ORIENTATION, {.uvalue = ETIFF_ORIENT_HORIZONTAL}},
327+
{ETIFF_XRESOLUTION, {.urational = {72, 1}} },
328+
{ETIFF_YRESOLUTION, {.urational = {72, 1}} },
329+
{ETIFF_RESOLUTION_UNIT, {.uvalue = ETIFF_INCHES} },
330+
{ETIFF_SOFTWARE, {.csvalue = "GPUJPEG"} },
331+
{ETIFF_DATE_TIME , {.csvalue = date_time} },
332+
{ETIFF_YCBCR_POSITIONING, {.uvalue = ETIFF_CENTER} },
333+
{ETIFF_EXIF_IFD_POINTER, {0} }, // value will be set later
307334
};
308-
const struct custom_exif_tags* custom_tags =
309-
encoder->writer->exif_tags != NULL ? &encoder->writer->exif_tags->tags[CT_TIFF] : NULL;
335+
size_t tag_count = ARR_SIZE(tags);
336+
const struct custom_exif_tags* custom_tags = NULL;
337+
if (encoder->writer->exif_tags != NULL) {
338+
custom_tags = &encoder->writer->exif_tags->tags[CT_TIFF];
339+
tag_count = remove_overriden(tag_count, tags, custom_tags);
340+
}
310341

311-
gpujpeg_write_ifd(encoder->writer, start, ARR_SIZE(tags), tags, custom_tags);
342+
gpujpeg_write_ifd(encoder->writer, start, tag_count, tags, custom_tags);
312343
}
313344

314345
static void gpujpeg_write_exif_ifd(struct gpujpeg_encoder* encoder, const uint8_t *start)
315346
{
316-
const struct tag_value tags[] = {
347+
struct tag_value tags[] = {
317348
{EEXIF_EXIF_VERSION, {.csvalue = "0230"} }, // 2.30
318349
{EEXIF_COMPONENTS_CONFIGURATION, {.csvalue = "\1\2\3\0"} }, // YCbCr
319350
{EEXIF_FLASHPIX_VERSION, {.csvalue = "0100"} }, // "0100"
320351
{EEXIF_COLOR_SPACE, {.uvalue = ETIFF_SRGB} },
321352
{EEXIF_PIXEL_X_DIMENSION, {encoder->coder.param_image.width} },
322353
{EEXIF_PIXEL_Y_DIMENSION, {encoder->coder.param_image.height}},
323354
};
324-
const struct custom_exif_tags* custom_tags =
325-
encoder->writer->exif_tags != NULL ? &encoder->writer->exif_tags->tags[CT_EXIF] : NULL;
355+
size_t tag_count = ARR_SIZE(tags);
356+
const struct custom_exif_tags* custom_tags = NULL;
357+
if (encoder->writer->exif_tags != NULL) {
358+
custom_tags = &encoder->writer->exif_tags->tags[CT_EXIF];
359+
tag_count = remove_overriden(tag_count, tags, custom_tags);
360+
}
326361

327362
gpujpeg_write_ifd(encoder->writer, start, ARR_SIZE(tags), tags, custom_tags);
328363
}

0 commit comments

Comments
 (0)