From 846db750fc638651ee58f3d3bc9d4f9ff8a3bb59 Mon Sep 17 00:00:00 2001
From: Chuck Dries <chuck@chuckdries.com>
Date: Sun, 7 Nov 2021 08:21:06 -0800
Subject: [PATCH 1/2] Swap photo metadata parsers

---
 gatsby-node.js                              | 59 ++++++++------------
 package.json                                |  1 +
 src/components/GalleryImage/GalleryImage.js | 61 +++++++++++----------
 src/pages/photogallery.js                   |  4 +-
 src/utils.js                                |  4 +-
 yarn.lock                                   |  5 ++
 6 files changed, 64 insertions(+), 70 deletions(-)

diff --git a/gatsby-node.js b/gatsby-node.js
index dad3106..1b1fafb 100644
--- a/gatsby-node.js
+++ b/gatsby-node.js
@@ -1,14 +1,9 @@
-const fs = require("fs");
-const util = require("util");
 const path = require("path");
-const { read } = require("fast-exif");
-const iptc = require("node-iptc");
 const Vibrant = require("node-vibrant");
 const chroma = require("chroma-js");
 const chalk = require("chalk");
 const R = require("ramda");
-
-const readFile = util.promisify(fs.readFile);
+const exifr = require("exifr");
 
 const badContrast = (color1, color2) => chroma.contrast(color1, color2) < 4.5;
 
@@ -89,32 +84,27 @@ function convertDMSToDD(dms, positiveDirection) {
   return positiveDirection ? res : -res;
 }
 
-function transformMetaToNodeData(exifData, iptcData, vibrantData, imagePath) {
-  const gps = { longitude: null, latitude: null };
+function transformMetaToNodeData(metaData, vibrantData, imagePath) {
+  // const gps = { longitude: null, latitude: null };
 
-  if (exifData) {
-    if (exifData.gps && exifData.gps.GPSLongitude && exifData.gps.GPSLatitude) {
-      gps.longitude = convertDMSToDD(
-        exifData.gps.GPSLongitude,
-        exifData.gps.GPSLongitudeRef === "E"
-      );
-      gps.latitude = convertDMSToDD(
-        exifData.gps.GPSLatitude,
-        exifData.gps.GPSLatitudeRef === "N"
-      );
-    }
-  }
+  // if (exifData) {
+  //   if (exifData.gps && exifData.gps.GPSLongitude && exifData.gps.GPSLatitude) {
+  //     gps.longitude = convertDMSToDD(
+  //       exifData.gps.GPSLongitude,
+  //       exifData.gps.GPSLongitudeRef === "E"
+  //     );
+  //     gps.latitude = convertDMSToDD(
+  //       exifData.gps.GPSLatitude,
+  //       exifData.gps.GPSLatitudeRef === "N"
+  //     );
+  //   }
+  // }
 
   const vibrant = vibrantData ? processColors(vibrantData, imagePath) : null;
 
   return {
-    exif: {
-      ...exifData?.exif,
-      ...exifData?.image
-    },
-    gps,
-    dateTaken: exifData?.exif?.DateTimeOriginal,
-    iptc: iptcData || undefined,
+    dateTaken: metaData.DateTimeOriginal,
+    meta: metaData,
     vibrant,
   };
 }
@@ -122,9 +112,11 @@ function transformMetaToNodeData(exifData, iptcData, vibrantData, imagePath) {
 exports.onCreateNode = async function ({ node, actions }) {
   const { createNodeField } = actions;
   if (node.internal.type === "File" && node.sourceInstanceName === "gallery") {
-    const file = await readFile(node.absolutePath);
-    const iptcData = iptc(file);
-    const exifData = await read(node.absolutePath);
+    const metaData = await exifr.parse(node.absolutePath, {
+      iptc: true,
+      xmp: true,
+      // icc: true
+    });
     const vibrantData = await Vibrant.from(node.absolutePath)
       .quality(3)
       .getPalette();
@@ -132,12 +124,7 @@ exports.onCreateNode = async function ({ node, actions }) {
     createNodeField({
       node,
       name: "imageMeta",
-      value: transformMetaToNodeData(
-        exifData,
-        iptcData,
-        vibrantData,
-        node.absolutePath
-      ),
+      value: transformMetaToNodeData(metaData, vibrantData, node.absolutePath),
     });
   }
 };
diff --git a/package.json b/package.json
index c5b11e3..dda142e 100644
--- a/package.json
+++ b/package.json
@@ -34,6 +34,7 @@
     "eslint-plugin-react": "^7.24.0",
     "eslint-plugin-react-hooks": "^4.2.0",
     "eslint-webpack-plugin": "^2.5.4",
+    "exifr": "^7.1.3",
     "fast-exif": "^1.0.1",
     "gatsby": "^3.4.1",
     "gatsby-plugin-eslint": "^3.0.0",
diff --git a/src/components/GalleryImage/GalleryImage.js b/src/components/GalleryImage/GalleryImage.js
index de60271..14486ae 100644
--- a/src/components/GalleryImage/GalleryImage.js
+++ b/src/components/GalleryImage/GalleryImage.js
@@ -60,10 +60,11 @@ const GalleryImage = ({ data, pageContext }) => {
   }, [pageContext]);
 
   const name = getName(image);
-  const meta = getMeta(image);
+  const {meta, dateTaken: dt} = getMeta(image);
+  // const locationString = meta.City;
   let locationString;
-  if (meta.iptc.city || meta.iptc.province_or_state) {
-    const location = [meta.iptc.city, meta.iptc.province_or_state].filter(
+  if (meta.City || meta.State || meta.Location) {
+    const location = [meta.Location, meta.City, meta.State].filter(
       Boolean
     );
     locationString = location.join(", ");
@@ -75,10 +76,10 @@ const GalleryImage = ({ data, pageContext }) => {
       ? "flex-col mx-auto"
       : "portrait:mx-auto landscape:mx-5 landscape:flex-row-reverse portrait:flex-col";
   const shutterSpeed = React.useMemo(
-    () => getShutterFractionFromExposureTime(meta.exif.ExposureTime || 0),
+    () => getShutterFractionFromExposureTime(meta.ExposureTime || 0),
     [meta]
   );
-  const dateTaken = React.useMemo(() => new Date(meta.dateTaken), [meta]);
+  const dateTaken = React.useMemo(() => new Date(dt), [dt]);
   return (
     <>
       <Helmet>
@@ -144,7 +145,7 @@ const GalleryImage = ({ data, pageContext }) => {
           </div>
           <div
             className={classnames(
-              "mx-2 flex flex-row portrait:items-end",
+              "px-2 flex flex-row portrait:items-end container mx-auto",
               ar <= 1
                 ? "pt-5 flex-col flex-auto text-right"
                 : "portrait:pt-5 portrait:flex-col portrait:text-right"
@@ -157,7 +158,7 @@ const GalleryImage = ({ data, pageContext }) => {
               {hasName(image) && (
                 <h1 className="text-4xl mt-0 font-serif">{name}</h1>
               )}
-              <p className="landscape:mr-2">{meta.iptc.caption}</p>
+              <p className="landscape:mr-2">{meta.Caption}</p>
             </div>
             {
               <div
@@ -173,21 +174,21 @@ const GalleryImage = ({ data, pageContext }) => {
               />
               <MetadataItem
                 data={locationString}
-                icon="location"
+                icon="map-outline"
                 title="location"
               />
-              {(meta.exif.Make || meta.exif.Model) && (
+              {(meta.Make || meta.Model) && (
                 <MetadataItem
-                  data={[meta.exif.Make, meta.exif.Model].join(" ")}
+                  data={[meta.Make, meta.Model].join(" ")}
                   icon="camera-outline"
                   title="camera"
                 />
               )}
-              {(meta.exif.LensModel || meta.exif.FocalLength) && (
+              {(meta.LensModel || meta.FocalLength) && (
                 <MetadataItem
                   data={[
-                    meta.exif.LensModel === "----" ? null : meta.exif.LensModel,
-                    meta.exif.FocalLength && `${meta.exif.FocalLength}mm`,
+                    meta.LensModel === "----" ? null : meta.LensModel,
+                    meta.FocalLength && `${meta.FocalLength}mm`,
                   ]
                     .filter(Boolean)
                     .join(" @")}
@@ -200,15 +201,15 @@ const GalleryImage = ({ data, pageContext }) => {
                 icon="stopwatch-outline"
                 title="shutter speed"
               />
-              {meta.exif.FNumber && (
+              {meta.FNumber && (
                 <MetadataItem
-                  data={`f/${meta.exif.FNumber}`}
+                  data={`f/${meta.FNumber}`}
                   icon="aperture-outline"
                   title="aperture"
                 />
               )}
               <MetadataItem
-                data={meta.exif.ISO}
+                data={meta.ISO}
                 icon="film-outline"
                 title="ISO"
               />
@@ -247,21 +248,23 @@ export const query = graphql`
           fields {
             imageMeta {
               dateTaken
-              iptc {
-                caption
-                object_name
-                keywords
-                city
-                province_or_state
-              }
-              exif {
-                FNumber
-                ExposureTime
-                FocalLength
-                ISO
-                LensModel
+              meta {
                 Make
                 Model
+                ExposureTime
+                FNumber
+                ISO
+                DateTimeOriginal
+                CreateDate
+                ShutterSpeedValue
+                ApertureValue
+                FocalLength
+                LensModel
+                ObjectName
+                Caption
+                Location
+                City
+                State
               }
               vibrant {
                 ...VibrantColors
diff --git a/src/pages/photogallery.js b/src/pages/photogallery.js
index 759038c..f14b24b 100644
--- a/src/pages/photogallery.js
+++ b/src/pages/photogallery.js
@@ -81,9 +81,7 @@ export const query = graphql`
           fields {
             imageMeta {
               dateTaken
-              iptc {
-                object_name
-              }
+              ObjectName
             }
           }
         }
diff --git a/src/utils.js b/src/utils.js
index ac2d33e..ab67b26 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -3,12 +3,12 @@
 export const getMeta = (image) => image.fields.imageMeta;
 
 export const getName = (image) =>
-  getMeta(image)?.iptc.object_name || image.base;
+  getMeta(image)?.meta?.ObjectName || image.base;
 
 // some pleasing default colors for SSR and initial hydration
 export const getVibrant = (image) => getMeta(image)?.vibrant;
 
-export const hasName = (image) => Boolean(getMeta(image)?.iptc.object_name);
+export const hasName = (image) => Boolean(getMeta(image)?.meta?.ObjectName);
 
 export const getAspectRatio = (image) =>
   image.childImageSharp.fluid.aspectRatio;
diff --git a/yarn.lock b/yarn.lock
index 20ceeca..c8b1cca 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5681,6 +5681,11 @@ exif-reader@^1.0.0:
   resolved "https://registry.yarnpkg.com/exif-reader/-/exif-reader-1.0.3.tgz#8eb63f878aeb49ec89bd5b7be10e393db78c3c2e"
   integrity sha512-tWMBj1+9jUSibgR/kv/GQ/fkR0biaN9GEZ5iPdf7jFeH//d2bSzgPoaWf1OfMv4MXFD4upwvpCCyeMvSyLWSfA==
 
+exifr@^7.1.3:
+  version "7.1.3"
+  resolved "https://registry.yarnpkg.com/exifr/-/exifr-7.1.3.tgz#f6218012c36dbb7d843222011b27f065fddbab6f"
+  integrity sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw==
+
 expand-brackets@^2.1.4:
   version "2.1.4"
   resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"

From 6f3e92b4553d41bd24bd1513e19f2a7e0430f181 Mon Sep 17 00:00:00 2001
From: Chuck Dries <chuck@chuckdries.com>
Date: Sun, 7 Nov 2021 08:21:16 -0800
Subject: [PATCH 2/2] Add japanese garden pics

---
 data/gallery/_DSC6481.jpg | 3 +++
 data/gallery/_DSC6766.jpg | 3 +++
 data/gallery/_DSC6771.jpg | 3 +++
 data/gallery/_DSC6787.jpg | 3 +++
 data/gallery/_DSC6798.jpg | 3 +++
 data/gallery/_DSC6836.jpg | 3 +++
 src/pages/index.js        | 2 ++
 7 files changed, 20 insertions(+)
 create mode 100644 data/gallery/_DSC6481.jpg
 create mode 100644 data/gallery/_DSC6766.jpg
 create mode 100644 data/gallery/_DSC6771.jpg
 create mode 100644 data/gallery/_DSC6787.jpg
 create mode 100644 data/gallery/_DSC6798.jpg
 create mode 100644 data/gallery/_DSC6836.jpg

diff --git a/data/gallery/_DSC6481.jpg b/data/gallery/_DSC6481.jpg
new file mode 100644
index 0000000..9228179
--- /dev/null
+++ b/data/gallery/_DSC6481.jpg
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0c26d364585ed50928342f05938ff72799a8a7f743ac2f5c6071097a0521077c
+size 2200300
diff --git a/data/gallery/_DSC6766.jpg b/data/gallery/_DSC6766.jpg
new file mode 100644
index 0000000..9a68fd4
--- /dev/null
+++ b/data/gallery/_DSC6766.jpg
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:88e125d1e46a7f1653936586c4fbacddd75307497604993b8acf81f86e776445
+size 6309877
diff --git a/data/gallery/_DSC6771.jpg b/data/gallery/_DSC6771.jpg
new file mode 100644
index 0000000..88d3414
--- /dev/null
+++ b/data/gallery/_DSC6771.jpg
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:449418484825fdb2a1dd5a5c39e372b34fc80f72777a63f58efad7afd16f34a5
+size 3118534
diff --git a/data/gallery/_DSC6787.jpg b/data/gallery/_DSC6787.jpg
new file mode 100644
index 0000000..6fe4c51
--- /dev/null
+++ b/data/gallery/_DSC6787.jpg
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:21428df5ab53b2828d55bace054dcb980a36650bd80f919a9764417e065e3a44
+size 9392673
diff --git a/data/gallery/_DSC6798.jpg b/data/gallery/_DSC6798.jpg
new file mode 100644
index 0000000..bb6b760
--- /dev/null
+++ b/data/gallery/_DSC6798.jpg
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0c8f1a47b19206592cf942fd4e38dd199305ce5c05c94d0369411f1a63a8fd9a
+size 7002333
diff --git a/data/gallery/_DSC6836.jpg b/data/gallery/_DSC6836.jpg
new file mode 100644
index 0000000..7643bba
--- /dev/null
+++ b/data/gallery/_DSC6836.jpg
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:68adbcb76ffe9417a4ba68c7bcfb187191d0485310f7c8f43a3e34a620031ca2
+size 7676969
diff --git a/src/pages/index.js b/src/pages/index.js
index 4b895fe..e37a2ae 100644
--- a/src/pages/index.js
+++ b/src/pages/index.js
@@ -233,6 +233,8 @@ export const query = graphql`
             "_DSC6219.jpg" # whihte/yellow rosebush
             "_DSC6243.jpg" # bright rose in darkness
             "_DSC6400-2.jpg" # Horsetail falls
+            "_DSC6798.jpg" # Japanese zen garden
+            "_DSC6481.jpg" # Mt Hood from Powell Butte
           ]
         }
       }