Skip to content

Commit a095cfa

Browse files
committed
read exif from thumbnail to get exif, no longer uses an api call for every image
1 parent ded9df9 commit a095cfa

File tree

3 files changed

+25
-12
lines changed

3 files changed

+25
-12
lines changed

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"class-variance-authority": "^0.7.0",
1919
"cloudinary": "^2.6.1",
2020
"clsx": "^2.1.1",
21+
"exifr": "^7.1.3",
2122
"framer-motion": "^11.3.2",
2223
"geist": "^1.3.1",
2324
"lucide-react": "^0.408.0",

src/app/photography/page.tsx

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
BreadcrumbSeparator,
1313
} from "@/components/ui/breadcrumb"
1414
import { Aperture, X } from "lucide-react";
15+
import exifr from 'exifr'
1516

1617
export const metadata: Metadata = {
1718
title: "Photography",
@@ -27,12 +28,13 @@ const getBase64 = async (src: ArrayBuffer, size: number) => {
2728
return `data:image/${info.format};base64,${data.toString('base64')}`;
2829
};
2930

30-
async function getBlurPreviewDataUrl(public_id: string) {
31+
async function getBlurPreviewAndMetadata(public_id: string) {
3132
const imageUrl = cloudinary.url(public_id, { transformation: [{ crop: 'thumb', width: 30 }] })
3233
// fetch image content and convert to data url
3334
const response = await fetch(imageUrl);
3435
const arrayBuffer = await response.arrayBuffer();
35-
return getBase64(arrayBuffer, 8)
36+
const metadata = await exifr.parse(Buffer.from(arrayBuffer))
37+
return { blurDataURL: await getBase64(arrayBuffer, 8), metadata }
3638
}
3739

3840
async function getPhotos() {
@@ -42,12 +44,15 @@ async function getPhotos() {
4244
secure: true,
4345
});
4446
const res = await cloudinary.api.resources_by_tag('photography', { resource_type: 'image', tags: true })
45-
return Promise.all(res.resources.map(async resource => ({
46-
...resource,
47-
tags: resource.tags.filter(t => t !== 'photography'),
48-
blurDataURL: await getBlurPreviewDataUrl(resource.secure_url),
49-
metadata: (await cloudinary.api.resource(resource.public_id, { media_metadata: true })).media_metadata
50-
})));
47+
return Promise.all(res.resources.map(async resource => {
48+
const { blurDataURL, metadata } = await getBlurPreviewAndMetadata(resource.secure_url)
49+
return {
50+
...resource,
51+
tags: resource.tags.filter(t => t !== 'photography'),
52+
blurDataURL,
53+
metadata
54+
}
55+
}));
5156
} catch (error) {
5257
console.error("Error fetching photos from Cloudinary:", error);
5358
return [];
@@ -62,7 +67,7 @@ const getThumbUrl = (public_id: string) => {
6267

6368
export default async function PhotographyPage() {
6469
const photos = await cachedGetPhotos()
65-
console.log(photos.map(p => p))
70+
console.log(photos.map(p => p.metadata))
6671
return (
6772
<div className="container mx-auto px-4 py-8">
6873
<Breadcrumb className="pb-8">
@@ -103,11 +108,11 @@ export default async function PhotographyPage() {
103108
{photo.metadata && (
104109
<div className="mt-2 text-xs">
105110
<div className="mb-1 flex flex-wrap gap-x-4 text-xs text-muted-foreground justify-between">
106-
<span>{photo.metadata.FocalLength}</span>
111+
<span>{photo.metadata.FocalLength}mm</span>
107112
<span>f/{photo.metadata.FNumber}</span>
108-
<span>{photo.metadata.ExposureTime}s</span>
113+
<span>1/{1 / photo.metadata.ExposureTime}s</span>
109114
<span>ISO {photo.metadata.ISO}</span>
110-
<span>{Number(photo.metadata.ExposureCompensation) === 0 ? "±" : ""}{photo.metadata.ExposureCompensation} EV</span>
115+
<span>{photo.metadata.ExposureCompensation === 0 ? "±" : ""}{photo.metadata.ExposureCompensation} EV</span>
111116
</div>
112117
<div className="flex gap-2 flex-wrap">
113118
<span className="font-semibold">{photo.metadata.Make} {photo.metadata.Model}</span>

0 commit comments

Comments
 (0)