Automated Photo Metadata (EXIF)

Summary

I’m looking to automatically collect specific metadata from uploaded photos (EXIF data), and store / cache, the data, and have the ability to use the data within MODX.

Example EXIF Data

Here is a list of the particular EXIF data I’m looking to collect / use:

  • Aperture
  • Exposure
  • Focal Length
  • ISO

Example Usage

Just an example of how you might be able to call the data in a chunk… :grimacing:

<div class="d-flex flex-row justify-content-start noselect">
    <abbr title="Aperture">ƒ/[[+aperture]]</abbr>
    <abbr title="Exposure">[[+exposure]]</abbr>
    <abbr title="Focal Length">[[+focallength]]mm</abbr>
    <abbr title="ISO">[[+iso]]</abbr>
</div>

Current Solution

Initially I built repeatable TVs via MIGX. I have one TV per field (aperture, exposure…), but I have quickly realized that it’s a bit of work to manually lookup and enter each photo’s data; especially since the data is already in the file. :tired_face:

Research

I know I could probably use a snippet to read the data [exif_read_data();], but this is not cached.

I noticed the MoreGallery premium extra appears to have what I’m looking for, but it also has way more than what I’m looking for. I’m not interested in: galleries, video, cropping, pagination…

I ran across this post from ancient times. It sounds like @gissirob came close to coming up with a solution that I’m looking for. I also found this post by @Bruno17. It seems like it might be a good starting point but Ich spreche deutsch nicht.

To start with, it almost seems like I would need the ability to add custom fields to files in the filesystem. :thinking: I found this gem, which has lead me here.

Environment

  • MODX v2.7.1
  • Apache v2.4.39
  • MIGX: 2.12.0-pl
  • PHP: 7.3
  • MySQL: 5.1

As always, thanks for your help!

Fetching EXIF data from an image is pretty easy. Here’s how MoreGallery does it:

    public function loadExifData($file) {
        $ext = pathinfo($file, PATHINFO_EXTENSION);
        if (in_array(strtolower($ext), array('jpeg', 'jpg', 'tiff'), true) && function_exists('exif_read_data')) {
            try {
                // Fetch EXIF data if we have it.
                $exif = @exif_read_data($file, NULL, false, false);
                if (is_array($exif)) {
                    foreach ($exif as $key => $value) {
                        $exif[$key] = $this->cleanInvalidData($value);
                    }
                    $this->set('exif', $exif);
                }
            } catch (Exception $e) {
                $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, '[moreGallery] Exception while trying to read exif data: ' . $e->getMessage());
            }
        } else {
            $this->xpdo->log(xPDO::LOG_LEVEL_WARN, '[moreGallery] This server does not have the exif_read_data function installed. MoreGallery cannot extract exif data now.');
        }
    }

    public function cleanInvalidData($value)
    {
        if (is_array($value)) {
            foreach ($value as $key => $subValue) {
                $value[$key] = $this->cleanInvalidData($subValue);
            }
            return $value;
        }

        return preg_replace('/[^\PC\s]/u', '', $value);
    }

Turn that into a snippet that you provide an image path, and that’s a versatile solution you can apply to any image.

2 Likes

Thanks @markh.

My issue isn’t extracting the EXIF data, its caching it. I don’t want 20+ images per page asking for EXIF data every time someone refreshes. :disappointed:

1 Like

Snippet output is cached, so it wouldn’t be every refresh, even with no additional work.

Could write results to the cache with the cache manager as an additional layer. Perhaps based on filename/path.

https://docs.modx.org/current/en/extending-modx/caching/example

1 Like