diff --git a/package.json b/package.json index 1229c81..7b62c36 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@astrojs/tailwind": "^5.1.0", "astro": "^4.11.0", "astro-i18n-aut": "^0.7.0", + "exifreader": "^4.23.3", "svelte": "^4.2.18", "svelte-gestures": "^5.0.1", "tailwindcss": "^3.4.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8e37f2e..10f010a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: astro-i18n-aut: specifier: ^0.7.0 version: 0.7.0(astro@4.11.0(@types/node@20.14.7)(typescript@5.5.2))(kleur@4.1.5) + exifreader: + specifier: ^4.23.3 + version: 4.23.3 svelte: specifier: ^4.2.18 version: 4.2.18 @@ -952,6 +955,10 @@ packages: '@vscode/l10n@0.0.18': resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} + '@xmldom/xmldom@0.8.10': + resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} + engines: {node: '>=10.0.0'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1346,6 +1353,9 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} + exifreader@4.23.3: + resolution: {integrity: sha512-/Ii4jiNp/5BXdKOiWXZYrWmZFn/ANu3bMVGO7GFQufao5M52/fK2OsAPMH34PL4S79z1eZBzAoaYyBXit0zzVA==} + extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} @@ -3871,6 +3881,9 @@ snapshots: '@vscode/l10n@0.0.18': {} + '@xmldom/xmldom@0.8.10': + optional: true + acorn-jsx@5.3.2(acorn@8.12.0): dependencies: acorn: 8.12.0 @@ -4327,6 +4340,10 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 + exifreader@4.23.3: + optionalDependencies: + '@xmldom/xmldom': 0.8.10 + extend-shallow@2.0.1: dependencies: is-extendable: 0.1.1 diff --git a/src/components/Image.astro b/src/components/Image.astro index 5f077da..a29de48 100644 --- a/src/components/Image.astro +++ b/src/components/Image.astro @@ -1,7 +1,7 @@ --- import type { ImageMetadata } from "astro"; import { Picture as AstroImage } from "astro:assets"; -import { generateThumbHash } from "@helpers/image"; +import { generateThumbHash, getExifData } from "@helpers/image"; interface Props { src: ImageMetadata; alt: string; @@ -24,6 +24,8 @@ const { let thumbhash = hash ? await generateThumbHash(image) : ""; +let exif = await getExifData(image); + const sizes = [ { width: 240, @@ -47,6 +49,7 @@ const sizes = [ src={image} alt={alt} data-thumbhash={thumbhash} + data-exif={JSON.stringify(exif)} pictureAttributes={{ class: `${hash ? "block h-full relative" : ""} ${loader ? "thumb" : ""} ${pictureClass}`, }} diff --git a/src/components/ImageGallery.svelte b/src/components/ImageGallery.svelte index e8679bb..599ff39 100644 --- a/src/components/ImageGallery.svelte +++ b/src/components/ImageGallery.svelte @@ -150,6 +150,7 @@ try { let rawExif = image.getAttribute("data-exif"); exif = JSON.parse(rawExif); + console.log(exif); } catch (error) { // No biggie } @@ -187,8 +188,7 @@ class:active={currentIndex === i} on:click={() => { currentIndex = i; - }} - /> + }} /> {/each} {/if} @@ -204,21 +204,18 @@ on:swipe={handleSwipe} on:wheel|passive={handleScroll} on:mousemove={handleMouseMove} - on:pointermove={handlePointerMove} - > + on:pointermove={handlePointerMove}> {#if progress[currentIndex] && progress[currentIndex] < 0.99}
+ style={`transform: scaleX(${progress[currentIndex]});`} /> {/if} background blur + alt="background blur" /> {images[currentIndex].alt} + alt={images[currentIndex].alt} />
{#if images[currentIndex].exif} {@const exif = images[currentIndex].exif}
console.log(exif)}> {#if "FocalLength" in exif} - {exif.FocalLength}mm | + {exif.FocalLength} | {/if} {#if "FNumber" in exif} diff --git a/src/helpers/image.ts b/src/helpers/image.ts index ab4695f..c66f6c0 100644 --- a/src/helpers/image.ts +++ b/src/helpers/image.ts @@ -1,16 +1,14 @@ let loadingSharp = false; import { rgbaToThumbHash } from "thumbhash"; +import ExifReader from 'exifreader'; let s: typeof import("sharp") | undefined; async function getSharp(): Promise { if (s) return s; - - if (import.meta.env.MODE !== "development") { - s = (await import("sharp")).default; - return s; - } + s = (await import("sharp")).default; + return s; if (!loadingSharp) { loadingSharp = true; @@ -42,3 +40,33 @@ export async function generateThumbHash(image: { width: number, height: number } const buffer = rgbaToThumbHash(smallWidth, smallHeight, smallImg); return Buffer.from(buffer).toString("base64"); } + +const allowedExif = [ + "ApertureValue", + "DateTimeOriginal", + "ExposureTime", + "ApertureValue", + "FNumber", + "FocalLength", + "GPSLatitude", + "GPSLongitude", + "GPSAltitude", + "IsoSpeedRatings", +]; + +export async function getExifData(image: { fsPath: string }) { + const sharp = await getSharp(); + if (!sharp) return; + const tags = await ExifReader.load(image.fsPath, { async: true }); + + const out: Record = {}; + let hasExif = false; + + for (const key of allowedExif) { + if (!tags[key]) continue; + hasExif = true; + out[key] = tags[key].description; + } + + return hasExif ? out : undefined; +}