Skip to content

Instantly share code, notes, and snippets.

@trey
Last active Jan 20, 2022
Embed
What would you like to do?
Display Image Exif Data in 11ty
const responsiveImage = require('./src/_includes/shortcodes/responsive-image');
const exifData = require('./src/_includes/shortcodes/exif-data');
// …
module.exports = function(eleventyConfig) {
// …
eleventyConfig.addShortcode('responsiveImage', responsiveImage);
eleventyConfig.addShortcode('exifData', exifData);
// …
}
const exif = require('fast-exif');
const imgFolder = 'src/img/gallery/';
module.exports = async(src) => {
const path = imgFolder + src;
const imageData = await exif.read(path).then(exifData => {
let DateTime;
let markup = '';
if (exifData.exif.DateTimeDigitized) {
DateTime = new Date(exifData.exif.DateTimeDigitized);
} else {
DateTime = new Date(exifData.exif.DateTimeOriginal);
}
const imgDescription = (exifData.image.ImageDescription)
? exifData.image.ImageDescription
: `Photo from ${DateTime.getFullYear()}`;
// Create an object with the items we want.
const items = Object.entries({
Year: DateTime.getFullYear(),
Camera: `${exifData.image.Make} ${exifData.image.Model}`,
Caption: imgDescription,
'ƒ/stop': exifData.exif.FNumber,
Shutter: !(isNaN(exifData.exif.ExposureTime)) ? `1/${1 / exifData.exif.ExposureTime}` : null,
'ISO': exifData.exif.ISO,
});
// Loop through the objects one by one and only include output
// where it exists and makes sense.
for (const [key, value] of items) {
if (value) {
markup += `<div>${key}: ${value}</div>`;
}
}
return markup;
}).catch(console.error);
return imageData;
};
const Image = require('@11ty/eleventy-img');
const exif = require('fast-exif');
module.exports = async (src, alt, title, width, height) => {
const options = {
inputDir: 'src/img/gallery',
outputDir: 'dist/img/gallery',
urlPath: '/img/gallery',
widths: [800, 1600, 2200, null],
formats: 'jpeg',
};
if (alt === undefined) {
// Pull in Exif data if we don’t have alt text.
const altText = await exif.read(`${options.inputDir}/${src}`).then(
exifData => exifData.image.ImageDescription
);
if (altText) {
alt = altText;
} else {
throw new Error(`Missing alt on responsiveImage from: ${src}`);
}
}
let stats = await Image(`${options.inputDir}/${src}`, options);
let lowestSrc = stats.jpeg[0];
let titleAttribute = (title) ? `title="${title}"` : '';
let props = stats[options.formats].pop();
// If sizes are passed in, use them. Otherwise, analyze the files.
let definedWidth = (width) ? width : props.width;
let definedHeight = (height) ? height : props.height;
const imgTag = `<img ${titleAttribute}
alt="${alt}"
src="${lowestSrc.url}"
width="${definedWidth}"
height="${definedHeight}"
srcset="${stats.jpeg.map(entry => `${entry.url} ${entry.width}w`)}" />`;
// Remove extraneous spaces and newlines.
return imgTag.replace(/\n/g, '').replace(/\s+/g, ' ');
};
<figure>
{% responsiveImage image %}
<figcaption>
{% exifData image %}
</figcaption>
</figure>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment