# photofield **Repository Path**: d00160/photofield ## Basic Information - **Project Name**: photofield - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-01-23 - **Last Updated**: 2024-01-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

Logo

Photofield

Experimental fast photo viewer.

Demo ยท Report Bug ยท Request Feature

Table of Contents
  1. About
  2. Getting Started
  3. Configuration
  4. Usage
  5. Maintenance
  6. Development Setup
  7. Contributing
  8. License
  9. Acknowledgements
## About ![Zoom to logo within a 43k images](docs/assets/logo-zoom.gif) _Zoom to logo within a sample of 43k images from [open-images-dataset], i7-5820K 6-Core CPU, NVMe SSD_ Photofield is a photo viewer built to mainly push the limits of what is possible in terms of the number of photos visible at the same time and at the speed at which they are displayed. The goal is to be as fast or faster than Google Photos on commodity hardware while displaying more photos at the same time. It is non-invasive and can be used either completely standalone or complementing other photo gallery software. ### Features * **Seamless zoomable interface**. Thanks to tiled image loading supported by [OpenLayers] and the API implementing tile rendering, you can switch between levels of detail seamlessly without loading a special detailed or fullscreen view. ![Seamless zoom to giraffe face](docs/assets/seamless-zoom.gif) * **Progressive multi-resolution loading**. Not only are thumbnails used to show a single photo quicker, the whole layout is progressively loaded, so even if you move through photos quickly or zoom around, you will almost always have some form of feedback to not lose track. ![Progressive load of a deer](docs/assets/progressive-load.gif) * **Different layouts**. Collections of photos can be displayed with different layouts. ![layout examples](docs/assets/layouts.png) * **Album:** chronological photos grouped by event * **Timeline:** reverse-chronological timeline similar to Google Photos * **Wall:** a square collage of all the photos, because zooming is fun! * **Map:** all the photos on a map? Sure! * [More future ideas?](https://github.com/SmilyOrg/photofield/issues/1) * **Semantic search using [photofield-ai] (alpha)**. If you set up an AI server and configure it in the `ai` section of the [configuration], you should be able to search for photo contents using words like "beach sunset", "a couple kissing", or "cat eyes". ![semantic search for "cat eyes"](docs/assets/semantic-search.jpg) * **Tagging (alpha)**. You can tag photos with arbitrary tags. Currently tags are only stored in the database and not in the photos themselves. You need to enable them in the `tags` section of the [configuration] and restart the server. This forms a foundation for many other features, see below (checked - implemented). * [x] **Persistent photo selection**. You can Ctrl+Click or Ctrl+Drag to select photos. This creates a new randomly generated "selection" tag that is persistent and shareable. It also means you can select tens of thousands of photos without losing your progress. These tags are currently never cleaned up and you can't do anything with it yet, so it's not useful yet, but it's a start. * [x] **Custom tags**. You canadd your own tags to photos, e.g. `#family` or `#vacation`. Batch tagging not supported yet, but should be relatively easy to add considering the selections (above) are already tags. * [x] **EXIF tags**. Tags are automatically added from the EXIF data, e.g. `exif:make:sony` or `exif:model:sm-g950f`. You need to enable this in the `exif` section of the [configuration]. Only `make` and `model` are currently supported (hardcoded). * [x] **Filter by tags**. You can filter by a tag by searching for `tag:TAG`. For example, you can search for `tag:fav` to only show favorited photos, or `tag:hello tag:world` to only show photos with both `hello` and `world` tags. This is an early version of filtering and should be more user-friendly in the future. * [ ] **Location tags**. Photos could be automatically tagged with the location, e.g. `city:berlin` or `country:germany`. See #59. * [ ] **Face recognition**. Photos could be automatically tagged with the person's name. This would be a great way to search for photos of a specific person. * **Reverse geolocation**. Local, embedded reverse geolocation via [tinygpkg]. Does not need any API calls, has negligible performance impact, and supports ~50 thousand places. Currently only supported for photos with GPS coordinates in the EXIF data and the Timeline view. * **Flexible media/thumbnail system**. Do you have hundreds of gigabytes of existing thumbnails from an existing system? Me too! Let's reuse those. Don't have any? No worries, they will be generated automatically to speed up display. Here are the currently supported thumbnail sources: * Bespoke SQLite thumbnail database - `photofield.thumbs.db`. * Synology Moments / Photo Station auto-generated thumbnails in `@eaDir`. * Embedded JPEG thumbnails - `ThumbnailImage` Exif tag. * Native Go [image](https://pkg.go.dev/image) package. * FFmpeg on-the-fly conversion - thumbnails and full sized variants. * Configurable via the `sources` section of the [Configuration]. * Please [open an issue] for other systems, bonus points for an idea on how to integrate! * **Single file binary**. Thanks to [Go] and [GoReleaser], all the dependencies are packed into a [single binary file](#binaries) for most major OSes. * **Read-only file system based collections**. Photofield never changes your photos, thumbnails or directories. You are encouraged to even mount your photos as read-only to ensure this. The file system is the source of truth, everything else is just a more or less stale cache. * **Fast indexing**. Thanks to [godirwalk], file indexing practically runs at the speed of the file system 1000-10000 files/sec on fast SSD and hot cache. EXIF metadata and [prominent color] are extracted as separate follow-up operations and run at up to ~200 files/sec and ~1000 files/sec on a fast system. * **Basic video support**. Videos are supported, however the user experience is not great yet as there are some usability quirks. Different resolutions are supported if they have been previously transcoded, but there is no on-the-fly transcoding supported right now. ### Limitations * **No photo details (yet)**. There is no way to show metadata of a photo in the UI at this point. * **Not optimized for many clients**. As a lot of the normally client-side state is kept on the server, you will likely run into CPU or Memory problems with more than a few simultaneous users. * **No user accounts**. Not the focus right now. You can define separate collections for separate users based on the directory structure, but there is no authentication or authorization support. * **Initial load can be slow**. All the photos need to be laid out when you first load a page in a specific window size and configuration, which can take some time with a slow CPU and cold HDD cache. * **No permalinks**. Deep linking to images works, but it's currently not stable over time as IDs can change. ### Built With * [Go] - API and server-side tile rendering * [Canvas (tdewolff)](https://github.com/tdewolff/canvas) - vector rendering in Go * [SQLite 3 (zombiezen)](https://github.com/zombiezen/go-sqlite) - fast single-file database/cache * [Vue 3] - frontend framework * [BalmUI] - Material UI components * [OpenLayers] - in-browser tiled image rendering * [OpenSeadragon] (honorary mention) - tiled image rendering library used previously * [+ more Go libraries](go.mod) * [+ more npm libraries](ui/package.json) ## Getting Started ### Docker Make sure you create an empty `data` directory in the working directory and that you put some photos in a `photos` directory. ```sh docker run -p 8080:8080 -v "$PWD/data:/app/data" -v "$PWD/photos:/app/photos:ro" ghcr.io/smilyorg/photofield ``` The cache database will be persisted to the `data` dir and the app should be accessible at http://localhost:8080. It should show the `photos` collection by default. For further configuration, create a `configuration.yaml` in the `data` dir.
docker-compose.yaml example This example binds the usual Synology Moments photo directories and assumes a certain path structure, modify to your needs graciously. It also assumes you have configured the `/photo` and `/user` directories as collections in the `configuration.yaml`. ```yaml version: '3.3' services: photofield: image: ghcr.io/smilyorg/photofield:latest ports: - 8080:8080 volumes: - /volume1/docker/photofield/data:/app/data - /volume1/photo/:/photo:ro - /volume1/homes/ExampleUser/Drive/Moments:/exampleuser:ro ```
### Binaries 1. [Download and unpack a release]. 2. Run `./photofield` or double-click on `photofield.exe` to start the server. 3. Open http://localhost:8080, folders in the working directory will be displayed as collections. ๐ŸŽ‰ * ๐Ÿ“ Create a `configuration.yaml` in the working dir to configure the app * ๐Ÿ•ต๏ธโ€โ™€๏ธ Install [exiftool] and add it to PATH for better metadata support (esp. for video) * โšช Set the `PHOTOFIELD_DATA_DIR` environment variable to change the path where the app looks for the `configuration.yaml` and cache database [Download and unpack a release]: https://github.com/SmilyOrg/photofield/releases [exiftool]: https://exiftool.org/ ## Configuration You can configure the app via `configuration.yaml`. The location of the file depends on the installation method, see [Getting Started]. The following is a minimal `configuration.yaml` example, see [`defaults.yaml`] for all options. ```yaml collections: # Normal Album-type collection - name: Vacation Photos dirs: - /photo/vacation-photos # Timeline collection (similar to Google Photos) - name: My Timeline layout: timeline dirs: - /photo/myphotos - /exampleuser # Create collections from sub-directories based on their name - expand_subdirs: true expand_sort: desc dirs: - /photo ``` ## Usage This section will cover some obvious uses, but also some possibly unintuitive UI quirks that exist in the current version. ### App Bar ![App bar explanation](docs/assets/app-bar.png) ### Photo Viewer * Click to zoom to a photo * `Escape` or pinch out to get back to the list of photos * Zoom in/out directly with `Ctrl/Cmd`+`Wheel` * Pinch-to-zoom on touch devices * Press/hold `Arrow Left` or `Arrow Right` to quickly switch between photos * Right-click or long-tap as usual to open a custom context menu allowing you to copy or download original photos or thumbnails. ![context menu](docs/assets/context-menu.png) _You can open/copy/copy link the original or access any existing thumbnails that already exist for it with the bottom list of thumbnails by pixel width._ ## Maintenance Over time the cache database can grow in size due to version upgrades and so on. To shrink the database to its minimum size, you can _vacuum_ it. Multiple vacuums in a row have no effect as the vacuum itself rewrites the database from the ground up. While the vacuum is in progress, it will take twice the database size and may take several minutes if you have lots of photos and a low-power system. As an example it took around 5 minutes to vacuum a 260 MiB database containing around 500k photos on a DS418play. The size after vacuuming was 61 MiB as all the leftover data from database upgrades was cleaned up. ```sh # CLI ./photofield -vacuum # Docker docker exec -it photofield ./photofield -vacuum ``` ## Development Setup ### Prerequisites * [Go] - for the backend / API server * [Node.js] - for the frontend * [just] - to run common commands conveniently * [watchexec] - for auto-reloading the Go server * sh-like shell (e.g. sh, bash, busybox) - required by `just` * [exiftool] - for testing metadata extraction **[Scoop] (Windows)**: `scoop install busybox just exiftool watchexec` ### Installation 1. Clone the repo ```sh git clone https://github.com/smilyorg/photofield.git ``` 2. Install Go dependencies ```sh go get ``` 3. Install NPM packages ```sh cd ui npm install ``` ### Running Run both the API server and the UI server in separate terminals. They are set up to work with each other by default with the API server running at port `8080` and the UI server on port `3000`. `just` is [just] as defined in the [prerequisites](#prerequisites). #### API * `just watch` the source files and auto-reload the server using [watchexec] * or `just run` the server #### UI * `just ui` to start a hot-reloading development server * or run from within the `ui` folder ```sh cd ui npm run dev ``` ## Contributing Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. ## License Distributed under the MIT License. See `LICENSE` for more information. ## Acknowledgements * [Open Images Dataset][open-images-dataset] * [geoBoundaries](https://www.geoboundaries.org/) for geographic boundary data used for reverse geolocation * [sams96/rgeo](https://github.com/sams96/rgeo) for previous reverse geolocation implementation and inspiration * [Best-README-Template](https://github.com/othneildrew/Best-README-Template) * [readme.so](https://readme.so/) [Configuration]: #configuration [open an issue]: https://github.com/SmilyOrg/photofield/issues [Getting Started]: #getting-started [`defaults.yaml`]: defaults.yaml [open-images-dataset]: https://opensource.google/projects/open-images-dataset [Scoop]: https://scoop.sh/ [just]: https://github.com/casey/just [watchexec]: https://github.com/watchexec/watchexec [Go]: https://golang.org/ [GoReleaser]: https://github.com/goreleaser/goreleaser [godirwalk]: https://github.com/karrick/godirwalk [prominent color]: https://github.com/EdlinOrg/prominentcolor [OpenLayers]: https://openlayers.org/ [OpenSeadragon]: https://openseadragon.github.io/ [Node.js]: https://nodejs.org/ [Vue 3]: https://v3.vuejs.org/ [BalmUI]: https://next-material.balmjs.com/ [photofield-ai]: https://github.com/smilyorg/photofield-ai [tinygpkg]: https://github.com/smilyorg/tinygpkg