Manage and certify large photo batches with a self-hosted, metadata-first workflow. IPTC Studio lets you import images, apply presets, validate metadata, and export clean deliverables without relying on third-party services or databases.
- Highlights
- Quick Start
- System Requirements
- Project Layout
- Configuration
- Working With Metadata
- AI-Assisted Captioning
- Troubleshooting
- Contributing
- Contact & License
- 📦 Batch-focused import/export that keeps files and state on disk for air-gapped or on-premise deployments.
- ✍️ Rich metadata editor for IPTC, XMP, and EXIF fields with preset application and validation flow.
- 🤖 Optional AI assistance via Google Gemini—bring your own prompt to generate first-pass captions.
- ⚙️ Vanilla stack: HTML, CSS, and JavaScript on the frontend; a lightweight PHP JSON API on the backend.
- 🗃️ Zero external databases required—storage directories hold presets, batches, exports, and working state.
- Clone the repository
git clone https://github.com/<your-org>/iptc-studio.git cd iptc-studio
- Prepare environment
cp .env.example .env # Only required when enabling AI assistance # export GOOGLE_GEMINI_API_KEY="your-key"
- Ensure writable storage
mkdir -p storage/batches storage/exports chmod -R 775 storage
- Run locally
php -S 127.0.0.1:8000 -t . - Visit
http://127.0.0.1:8000and start uploading your photo batches.
| Component | Details |
|---|---|
| PHP | 8.2+ with json, mbstring, exif, fileinfo, gd extensions |
| CLI tools | exiftool v12 or newer in PATH |
| Web server | Apache, Nginx + PHP-FPM, Caddy, or PHP built-in server for local runs |
| Optional | Node.js for front-end tooling, Composer for additional PHP packages |
Grant the web/PHP user write access to storage/ and its subdirectories.
.
├── api/ # JSON endpoints for uploads, updates, exports, AI, presets
├── assets/ # Vanilla JS UI logic and CSS stylesheets
├── src/ # Domain services (BatchStore, MetadataService, PresetStore…)
├── storage/ # Batches, exports, presets, and working state (state.json)
├── index.php # Frontend bootstrap shell
├── preset.php # Preset editor interface
└── README.md # You are here
GOOGLE_GEMINI_API_KEY— only required when enabling AI-assisted metadata generation.storage/preset.json— optional JSON file to preload metadata fields likecreator,credit,usageTerms, etc. Leave values empty for manual entry.- PHP ini values
upload_max_filesizeandpost_max_sizeshould accommodate your batch sizes.
Document your presets and environment values alongside deployment notes for faster onboarding.
- Upload images via drag-and-drop or file dialog; batches live under
storage/batches/{batchId}with astate.jsondescriptor. - Edit metadata using the in-browser editor; the backend synchronizes updates through
api/update.php. - Validate by applying presets, reviewing AI suggestions (if enabled), and running the apply step to rewrite IPTC, XMP, and EXIF data via
exiftool. - Export either processed images (
api/export_images.php) or structured datasets (api/export.php) in JSON/CSV formats.
- Implement your own prompt in
api/ai_generate.phpvia thebuildGeminiPromptfunction. - Provide descriptive context (who, what, when, where, why) per asset for better caption quality.
- The backend queues Gemini calls, merges results, and flags assets as
aiGeneratedfor easy review before applying metadata changes.
- ❌ Uploads failing? Check PHP
upload_max_filesize/post_max_sizeand write permissions onstorage/batches. - ❌ Preset not applying? Confirm
storage/preset.jsonexists, is readable, and contains the expected keys. - ❌ AI errors? Validate your Gemini API key and that outbound HTTPS is allowed from the server.
- ❌ Missing thumbnails? Ensure the PHP
gdextension is enabled.
Contributions are welcome! Open a pull request describing the problem you solve, include testing notes, and update documentation when behavior changes. Follow PSR-12 formatting and run php -l on modified files.
- 📫 Questions or commercial inquiries:
polgebenjamin(at)outlook.com - 📄 Licensed under the GNU Affero General Public License v3. Commercial SaaS hosting or resale requires written permission from Benjamin Polge.