[libcamera-devel] [RFC PATCH v2] android: jpeg: exif: Set timezone information
Kieran Bingham
kieran.bingham at ideasonboard.com
Wed Sep 23 22:44:54 CEST 2020
Hi Umang,
On 23/09/2020 20:17, Umang Jain wrote:
> Hi,
>
> Again posting as a RFC but the patch is now functional as expected.
> Tested with few range of values (+ -) and didn't see a problem.
>
> Let me know what you think.
> ---
>
> Get timezone information from the timestamp, although the resolution
> for EXIF_TAG_TIME_ZONE_OFFSET is fairly limited (per-hour only).
>
> This commit also introduces a special case handling for this tag.
> In course of development, it was found that libexif does not
> support this tag practically but still carries it among its
> header files. The manual patching here turned out to be a small
> detail that can conveniently be removed as and when libexif's
> support for timezone information improves.
Oh, I'm surprised here - I'm not sure I fully understand and would have
to investigate - but I thought the setXXX() functions are all capable of
creating a new entry when required, and they 'remove' any existing entry ...
>
> The EXIF specification defines three other tags (OffsetTime,
> OffsetTimeOriginal, OffsetTimeDigitized), in the EXIF IFD.
> These are not supported by libexif yet.
>
> Signed-off-by: Umang Jain <email at uajain.com>
> ---
> src/android/jpeg/exif.cpp | 44 +++++++++++++++++++++++++++++++++++++++
> src/android/jpeg/exif.h | 1 +
> 2 files changed, 45 insertions(+)
>
> diff --git a/src/android/jpeg/exif.cpp b/src/android/jpeg/exif.cpp
> index c0dbfcc..27d8fde 100644
> --- a/src/android/jpeg/exif.cpp
> +++ b/src/android/jpeg/exif.cpp
> @@ -7,6 +7,8 @@
>
> #include "exif.h"
>
> +#include <stdlib.h>
> +
> #include "libcamera/internal/log.h"
>
> using namespace libcamera;
> @@ -135,6 +137,29 @@ void Exif::setShort(ExifIfd ifd, ExifTag tag, uint16_t item)
> exif_entry_unref(entry);
> }
>
> +void Exif::setSShort(ExifIfd ifd, ExifTag tag, int16_t item)
> +{
> + ExifEntry *entry;
> + /*
> + * Special case handling for EXIF_TAG_TIME_ZONE_OFFSET. We need to
> + * manually create and initialize an ExifEntry for this tag, since
> + * the intialization support is missing from libexif's function
> + * exif_entry_initialize().
> + *
> + * \todo: Remove this special case when the above issue is fixed in
> + * libexif.
> + */
> + if (tag == EXIF_TAG_TIME_ZONE_OFFSET)
> + entry = createEntry (ifd, tag, EXIF_FORMAT_SSHORT, 1, 2);
> + else
> + entry = createEntry(ifd, tag);
Is the special case required to determine the size?
Oh - I see, createEntry(ifd, tag) uses exif_entry_initialize()
presumably to initialise from a table of values based on the tag ...
which isn't provided for the EXIF_TAG_TIME_ZONE_OFFSET ...
So calling the extended version is explicitly setting everything up ...
Hrm ... a bit nasty indeed.
Becuase this is a workaround, I'd almost be tempted to handle this in
setTimestamp, as that's the only call path that needs it...
> + if (!entry)
> + return;
> +
> + exif_set_sshort(entry->data, EXIF_BYTE_ORDER_INTEL, item);
> + exif_entry_unref(entry);
> +}
> +
> void Exif::setLong(ExifIfd ifd, ExifTag tag, uint32_t item)
> {
> ExifEntry *entry = createEntry(ifd, tag);
> @@ -196,6 +221,25 @@ void Exif::setTimestamp(time_t timestamp)
> setString(EXIF_IFD_0, EXIF_TAG_DATE_TIME, EXIF_FORMAT_ASCII, ts);
> setString(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_FORMAT_ASCII, ts);
> setString(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_FORMAT_ASCII, ts);
> +
> + /*
> + * If possible, query and set timezone information via
> + * EXIF_TAG_TIME_ZONE_OFFSET. There is only per-hour resolution for tag
> + * hence, round up hours if minutes >= 30.
> + */
> + int r = strftime(str, sizeof(str), "%z", &tm);
> + if (r > 0) {
> + int16_t timezone = atoi(str);
> + int16_t hour = timezone / 100;
> + int16_t min = timezone % 100;
> +
> + if (min <= -30)
> + hour--;
> + else if (min >= 30)
> + hour++;
> +
> + setSShort(EXIF_IFD_0, EXIF_TAG_TIME_ZONE_OFFSET, hour);
So that would be remove that line (I do prefer the setSShort() type
helpers in the general case) and add something like:
> /*
> * exif_entry_initialize() does not yet support
> * EXIF_TAG_TIME_ZONE_OFFSET, so we have to do this
> * manually.
> */
> ExifEntry *entry = createEntry(EXIF_IFD_0, EXIF_TAG_TIME_ZONE_OFFSET,
> EXIF_FORMAT_SSHORT, 1, 2);
> if (entry) {
> exif_set_sshort(entry->data, EXIF_BYTE_ORDER_INTEL, hour);
> exif_entry_unref(entry);
> }
What do you think? Better - or easier just to have it in the new
setSShort() call?
--
Kieran
> + }
> }
>
> void Exif::setOrientation(int orientation)
> diff --git a/src/android/jpeg/exif.h b/src/android/jpeg/exif.h
> index f04cefc..9c9cc3b 100644
> --- a/src/android/jpeg/exif.h
> +++ b/src/android/jpeg/exif.h
> @@ -37,6 +37,7 @@ private:
> unsigned long components, unsigned int size);
>
> void setShort(ExifIfd ifd, ExifTag tag, uint16_t item);
> + void setSShort(ExifIfd ifd, ExifTag tag, int16_t item);
> void setLong(ExifIfd ifd, ExifTag tag, uint32_t item);
> void setString(ExifIfd ifd, ExifTag tag, ExifFormat format,
> const std::string &item);
>
--
Regards
--
Kieran
More information about the libcamera-devel
mailing list