Photography Portfolio Site
An automated photography pipeline that extracts GPS data from images, reverse geocodes locations, optimizes for the web, and presents them in a responsive gallery
The Idea
Travel is how I learn about the world. Every country I visit adds a layer — a new perspective on how people live, what they value, and how places feel. I wanted a gallery that captured that: not just a folder of images, but a visual record of curiosity-driven exploration across 60+ countries.
The challenge was making it feel intentional without making it manual. I had hundreds of photos, each with GPS coordinates already embedded in their EXIF data. I wanted a pipeline that could extract that data, reverse geocode it to a real city and country, optimise each image for the web, and present them in a browsable, searchable gallery — automatically.
The Challenge
GPS Extraction at Scale
Parsing EXIF metadata from 198+ JPEG files to extract GPS coordinates, handling missing or malformed data gracefully.
Reverse Geocoding
Converting raw latitude/longitude into human-readable city and country names using OpenStreetMap's Nominatim API with rate limiting.
Image Optimization
High-resolution travel photos are often 5-10MB each. Needed a pipeline to resize and compress without losing visual quality.
Gallery UX
Building a responsive grid with category filtering, full-screen lightbox with keyboard navigation, and preloading for smooth browsing.
How It Works
EXIF Extraction
A TypeScript processing script reads each photo's EXIF data using the exif-reader library, extracting GPS coordinates, date taken, and camera settings.
Reverse Geocoding
GPS coordinates are sent to OpenStreetMap's Nominatim API to resolve city and country names. The script handles rate limiting and caches results to avoid redundant lookups.
Image Optimization
Sharp resizes photos to web-friendly dimensions and compresses them while maintaining visual quality. Original files are preserved; optimized versions are served to visitors.
Manifest & Gallery
All metadata is compiled into a JSON manifest that powers an API route. The React gallery reads from this API, rendering a responsive grid with category filtering and a lightbox viewer.
Key Features
Automatic GPS Tagging
City and country extracted from photo EXIF data automatically
Reverse Geocoding
GPS coordinates resolved to readable locations via OpenStreetMap
Category Filtering
Browse photos by country with one-click category filters
Lightbox with Preloading
Full-screen viewer with keyboard navigation and adjacent image preloading
Image Optimization
Sharp-based resize and compression for fast page loads
Responsive Grid
Adaptive layout from 1 to 4 columns based on screen size
Tech Stack
Next.js & TypeScript
Full-stack framework powering the gallery page, API routes, and processing scripts with type safety throughout.
Sharp
High-performance image processing library for resizing and compressing photos while maintaining visual quality.
EXIF Reader & OpenStreetMap
EXIF metadata extraction for GPS coordinates, paired with Nominatim reverse geocoding to resolve locations.
React Query & Tailwind CSS
Server state management for gallery data fetching, combined with utility-first styling for the responsive grid and lightbox.
What I Learned
Building this gallery taught me several valuable lessons about working with media at scale:
- Image Optimization Pipelines: The difference between serving raw photos (5-10MB) and optimized versions (100-300KB) is night and day for user experience. Sharp made this straightforward but the configuration choices matter.
- EXIF Metadata is Messy: Not every photo has GPS data, and the format varies between camera models. Building robust fallback handling was essential.
- Reverse Geocoding at Scale: Rate limiting and caching are critical when hitting external APIs for hundreds of requests. Respecting Nominatim's usage policy while keeping the pipeline fast required careful throttling.
- Lightbox UX Patterns: Keyboard navigation, image preloading, and body scroll locking are small details that make a gallery feel polished and professional.