A diary

The story

Why Fotollection exists, and how it found its own way: a diary of the first kilometres, told from the project's notes and the history of its code.

I. The starting line

One day I realised I had lived twenty years. My phone held tens of thousands of photos, and I had almost never opened them again. Things from five or six years ago were starting to fade: an afternoon, a face, the name of a street. The photos were still there, sitting quietly in a folder I never visited.

Then I came to Europe to study. Winters here are long and the dark comes early, so there are more quiet hours than I expected. In those hours I scrolled back through the old years and felt a soft kind of sadness: good memories, stories left unfinished, all of it behind a sheet of glass. My grandparents had thick albums, every photo held by paper corners, a line of handwriting on the back. My generation takes more pictures than any before it and keeps fewer of them. I thought: let me start there. I wanted to make something that turns those memories back into things you can hold.

I think of it as a marathon. Nobody runs forty-two kilometres in one breath, so I only asked what the first step was. In September 2026, the first step was a plan for a web app called “PhotoOrder”. The problems I wrote down then still stand: people shoot thousands of photos and print almost none; prints say neither when nor where, and in a few years nobody remembers; labs crop photos to 2:3, 3:4 or square on their own, sometimes cutting off heads and horizons; and online tools want your photos uploaded, while their GPS data can point straight at your home.1

II. The first strides

The project’s first commit came on the afternoon of 23 October 2026, with three pages in it: a plan, a note on safety and a progress page, and not a line of code. Thirty-five minutes later the project had a new name, Fotollection, and a different direction altogether. I dropped the web app for a desktop app that works fully offline, with its core written in Rust. The reason is in the very first architecture decision: the people it is for take photography seriously, so speed and print quality come first, and a browser caps a tab’s memory and keeps me from controlling how a photo is encoded.

A few rules were set down that same day, and they still hold. Place names are looked up on your own computer, from a bundled GeoNames dataset, so your coordinates are never sent to a server. The code is licensed under GPL-3.0, so nobody can turn it into a closed copy. The installers are not signed, because this is a free project with no budget for yearly certificates. And the notes on the code change in the same commit as the code itself, a habit that later kept the whole project from losing its way.

That evening the first slice ran from end to end: import, preview, date stamp, JPEG export. Then I did what every runner should do early: I timed it. I put the Rust build next to a version running in the browser, on the same 95 photos of 16 MP on the same machine. The result surprised me. Export ran at nearly the same speed, 18.0 photos a second against 17.9. My first guess, that the browser would be slow, was wrong, and I wrote down that word, wrong. The real reasons for a native app lie elsewhere: prints encoded at 4:4:4 rather than 4:2:0, memory that stays bounded even at five thousand photos, colour profiles that are kept, and files written straight to disk. On day one I learnt that a measured number is worth more than a belief.2,3

III. The first fall

The first bug fix had nothing to do with photos: the test programs would not start on Windows because a system manifest was missing. A small stumble, and a reminder that every operating system is a different road surface.

Two days later the stumbles began to teach me more. Once, a red mark from the automatic checks sat unnoticed through three pushes, because a list in the project’s notes was numbered “7.” twice; from then on the notes are checked in the same step I always run before a commit. Once, opening a photo with the app closed did nothing at all: macOS handed the file over before the app had built its state. And the first “Shot on” frame read “NIKON CORPORATION NIKON D750”, because the Make field in EXIF names a company, not a brand.4

After falls like these I started writing down the lessons. Every bug that took more than one look goes into them: what was seen, why, the fix, and the rule from now on. They are the first thing I read whenever something breaks. Running a long way is not about never falling; it is about remembering where you fell.

IV. A print must not look flat

I had noticed it for a long time: photos printed through web editors often look flat, the colour dull and blotchy, with less depth than the original. On 24 October I put that suspicion to a pixel-by-pixel test. Against a typical web-editor export, Fotollection’s colour error was ΔE2000 0.19 on average instead of 1.39, it kept 100 % of the fine detail instead of 13 %, it kept 99.9 % of the saturation of Display P3 photos instead of 86.8 %, and it kept the ICC colour profile on 20 photos out of 20. The causes are no mystery: a dropped colour profile, a photo shrunk and blown up again, colour halved. Leave those out, and the print keeps the photo.

In those days the most concrete finish line was the self-service printers in dm and Rossmann stores, and every size on the price list of the CEWE photo service there went into the app. The website was born at the same time, in English and Vietnamese, opening with a question I still find true: thousands of photos, only looked at on the plane home? On 25 October it moved to fotollection.org, and that same day brought seven releases, from v0.3.0 to v0.7.0: the print basket, a viewer with zoom, then camera RAW. Those were the fastest kilometres, with fresh legs on a new road.5

V. Turned away at the roadside

On 26 October I applied to the SignPath Foundation for free code signing of the Windows installer. The answer came the same day: they look for outside signs of public trust, such as stars, forks, contributors and independent articles, and the project did not show enough yet; I could apply again later. That refusal did not stop me. It only showed how much road was still ahead. The installers are still unsigned, and every release lists SHA-256 checksums, so anyone can check the file they downloaded.

The same day I made a mistake I still remind myself of. The website and the v0.7.0 notes said camera RAW opened with nothing to install, and on Windows that was not true. I found it myself, not a test. The lesson became a rule: never write “supports” before it has been tried on every system. And from then on I decided that RAW must be read by code inside Fotollection, not by something the user has to install.

VI. Making my own shoes

A long-distance runner ends up wanting shoes that fit their own feet. On 27 October Fotollection got a RAW decoder of its own, DNG first. I wanted colour as good as the big programs, without anyone installing anything extra. On a Ricoh GR III DNG the new decoder took 355 ms, used 526 MB of memory, and came within ΔE2000 2.67 of the camera’s own JPEG; the library I had used before needed 640 ms and 1.33 GB, and was 4.08 away.

That 2.67 has a story of its own. While my DNG was still about one unit off, I was sure the colour was to blame. Mapping the error showed the centre of the frame brighter than its edges: it was the lens’s vignetting, not the colour. The lesson I wrote then: map the error by region before adding parameters. The same week v0.8.0 arrived, named “Places and Lightroom”: camera clocks set right, dates and places set by hand, stars read from Lightroom. Then came two nearly silent days, the 28th and the 29th, the only real pause in the whole race.

VII. Finding the rhythm

By the end of October the app could do a great deal, and the more it did, the harder it was for someone new. On 31 October I split it into three modes. Simple is the shortest way from a folder to prints: look at each photo once, keep it or drop it, then export. Collage puts two photos on one print, the way a half-frame film camera put two frames on one negative, so a set costs half as much. Pro is everything built before.

That was when Fotollection found its rhythm. It does not try to be an all-purpose photo manager; it is a short, clear road from a phone or a memory card to a sheet of photo paper in your hand. v0.9.0 “Three modes” shipped on 2 November. The bugs of those days became rules too: a field that made the whole panel jump while typing gave the rule “nothing blinks, nothing jumps”. A collage sheet exports in 214 ms, quicker than its two photos one by one (633 ms), and the grid of sheets redraws from thumbnails in 29 ms instead of 4,088.

VIII. The first cheers, and the green photos

On 1 November real users spoke for the first time, and they showed me what no test had. Someone on v0.8.0 opened their folder and found half the photos shown as green tiles with fine horizontal stripes. I suspected the RAW decoder first, but the files were JPEGs. The fast JPEG decoder I relied on read one rare file layout wrongly and still reported success. v0.8.1 “Green photos fixed” put a reference decoder behind the fast one, and from then on there is a rule I count among the core ones: a fast decoder is trusted only on the layouts a test proves.

The same day came another report: with three photos ticked, the export button said “Export 12 photos”. v0.8.3 fixed exactly that, and added a red Report button so people could tell me more. That day Fotollection also arrived on Linux. I have no Linux machine, but Linux has few good photo apps, so it is a place where Fotollection can be the obvious choice. The first people to cheer did not stand at the finish line; they stood along the road and pointed out where I was running wrong.

IX. Saving strength for the long run

A long race asks for things nobody sees. The app works offline and sends nothing, so when something goes wrong, the only clue a user can read to me is a code. v0.9.1 gave every error its own code, like ERR-IMG-0006, with an error log kept on the computer itself, free of photos, places and file names, and a Copy diagnostics button to paste it into a report.

Some faults made me stop and catch my breath. Zooming into one RAW photo once froze every preview for five minutes, not because it was slow, but because a lock was held while a pool of threads waited for itself. The rule since: never hold a lock while parallel work runs. On 2 November I wrote down the direction for the core in one short sentence I want to keep to the end: simple software, never careless.

X. Running through Prague

On 3 November I wanted something to send to people far away: postcards printed from my own photos. One half of the print is the photo, the other the back of a postcard, with a stamp box, writing lines and text typed as if on a typewriter, laid out as in my own sketch. v0.9.4 brought postcards into Collage mode, followed by a smaller stamp box that the stamp hides, a fourth address line when one is needed, and a red mark when the text does not fit.

Then I put the app to a real test: a whole folder copied off a Lumix GX9 after a weekend in Prague, 396 JPEGs of 20 MP and 26 RAW files, 4.7 GB in all. The real trip broke two budgets that the test sets had never touched: export ran at only 7.6 photos a second, and memory climbed to 2.14 GB, past the 2 GB ceiling. I measured each step again. The encoder turned out to hold every coefficient of each photo only to make its file less than 1 % smaller, and half of the memory “left over” belonged to the benchmark itself. v0.9.7 exports those JPEGs at 10.1 a second, and the whole run stays under 1.31 GB. In the same days a user told me that exporting by day made them hunt for their photos, so since v0.9.6 everything goes into one folder by default, just as a USB stick taken to a print shop wants.

The night trams of Prague now sit on the home page, as a postcard addressed to the National Museum, with “Ahoj Praha!” on its lines. The memory of a weekend has become something you can put a stamp on and send.

XI. A second wind

On 5 November two things came together. v0.10.0 gave Fotollection its own RAW engine: every Bayer camera developed by our own code, opened neutral, with the camera’s look one click away, and brightness, highlights and shadows worked on the sensor’s own data, as a RAW editor does. That same evening I opened my Prague RAW files and the preview’s spinner kept turning and never stopped.

I did not guess. A snapshot of every thread in the running app showed the knot: every worker was waiting for a develop, and the develop was waiting for a worker. That was fixed the same night, and then a second, quieter hang in the screen itself. Then I asked for more. In Lightroom, once a folder has loaded, any photo you click is simply there. I wrote down a sentence that changed how I think about the app: it is not good to use little memory, it is good to use memory well.

So since v0.11.0 Fotollection prepares a preview of every photo in the background once the thumbnails are done, keeps it on disk, and gives the photos around the one on screen a quarter of the computer’s memory. On the same 422 photos from Prague, v0.9.0 took 274 ms to open a JPEG and 531 ms to open a RAW. v0.11.0 takes 27 ms for either. It felt like a rocket, and like a second wind in a long race.

XII. How far still

Fourteen days, more than four hundred and thirty commits, twenty-four releases. Counted as a marathon, I have only passed the first kilometres. Ahead are v0.12.0, one window for every setting and a strip of photos under the preview to skim a trip, then v0.14.0 “Looks”, with looks of one’s own, and further on, version 1.0.

I often ask myself how far I can take Fotollection. Could it one day be like the open-source projects a whole community knows, the repositories tens of thousands of people trust every day? I do not know yet. What I know is that each photo printed is a memory no longer behind glass, like my grandparents’ albums once were. If you have read this far, thank you for running a stretch of the road with me. The road is still long, and I am still running.

  1. 1. GPS (Global Positioning System) is the United States' satellite navigation system. Phones and many cameras use it, often with Galileo, GLONASS or BeiDou, to record where a photo was taken.
  2. 2. JPEG is the image format of the Joint Photographic Experts Group, standardised as ISO/IEC 10918-1 and ITU-T T.81.
  3. 3. Units: px is a pixel, one dot of an image; MP (megapixel) is a million pixels, so a 20 MP photo is about 5,472 × 3,648 px; ms is a millisecond, a thousandth of a second; MB and GB are megabytes and gigabytes; RAM (random-access memory) is the computer's working memory.
  4. 4. EXIF (Exchangeable Image File Format) is the standard, maintained by Japan's JEITA and CIPA, for the information a camera writes into each photo: the camera and lens, the date and time, the exposure, often the GPS position, and a small embedded thumbnail.
  5. 5. A RAW file holds what the camera's sensor recorded before the camera turned it into a picture, so colour, brightness and detail can still be decided later, much as a negative is developed. Each maker has its own format (CR3 for Canon, NEF for Nikon, ARW for Sony, RW2 for Panasonic and others); DNG (Digital Negative) is the open RAW format published by Adobe.

The photo services at dm and Rossmann are made by CEWE, a trademark of CEWE Stiftung & Co. KGaA. Print sizes were checked against dm's price list in October 2026; the shops may change them.

The Prague photos in the screenshots (the trams, the streets, the Vltava) were taken by @hoangphi01 on a Lumix GX9 in November 2026: © @hoangphi01, all rights reserved. They are not covered by the app's licence and may not be reused. The other demo photos are in the public domain (CC0) on Wikimedia Commons, by Dktue (7 photos), Pierre Blaché from Paris, France (2) and Kate Branch (1). The cat in the print-basket and best-shot screenshots was also photographed by @hoangphi01 on the GX9, all rights reserved; the softer, shaken and darker copies beside it were made from that one photo, to show how the best shot is chosen. Every file, its page and its checksum.

The RAW measurements use nine samples in the public domain (CC0) from raw.pixls.us, one per format; scripts/fetch-raw-samples.py downloads and checks them.

RAW formats named on this site belong to the camera makers that define them: RW2 (Panasonic Holdings Corporation), CR2 and CR3 (Canon Inc.), NEF (Nikon Corporation), ARW (Sony Group Corporation), RAF (FUJIFILM Corporation) and ORF (OM Digital Solutions Corporation, formerly Olympus). DNG is an open specification published by Adobe Inc. Fotollection reads them through a reader built into Fotollection, and on macOS through the system's codecs first (on Windows, Microsoft's Raw Image Extension is a last fallback when installed); it is not made or endorsed by any of these companies.

Camera names and logos in the screenshots and in the app's info frame are trademarks of their owners, used only to show which camera took a photo: Apple (Apple Inc.), Canon (Canon Inc.), Fujifilm (FUJIFILM Corporation), Hasselblad (Victor Hasselblad AB), Leica (Leica Camera AG), Lumix (Panasonic Holdings Corporation), Nikon (Nikon Corporation), Noritsu (Noritsu Koki Co., Ltd.), Phase One (Phase One A/S), Ricoh (Ricoh Company, Ltd.), Samsung (Samsung Electronics Co., Ltd.) and Sony (Sony Group Corporation).

Apple and macOS are trademarks of Apple Inc.; Windows of Microsoft Corporation; Linux is the registered trademark of Linus Torvalds in the U.S. and other countries; Ubuntu of Canonical Ltd.; Debian of Software in the Public Interest, Inc.; Fedora, Red Hat, RHEL and CentOS of Red Hat, Inc.; openSUSE of SUSE LLC; Pop!_OS of System76, Inc.; Rocky Linux of the Rocky Enterprise Software Foundation; AlmaLinux of the AlmaLinux OS Foundation; ChromeOS of Google LLC; NVIDIA of NVIDIA Corporation; the names of the other Linux distributions belong to their projects; Facebook and Instagram of Meta Platforms, Inc.; GitHub of GitHub, Inc.; Google Analytics of Google LLC; Lightroom of Adobe Inc.; IrfanView of Irfan Škiljan; VietQR of NAPAS; Wikimedia Commons of the Wikimedia Foundation. The Apple, Windows and Linux (Tux, first drawn by Larry Ewing) marks are drawn from Simple Icons (CC0) and only show which system a column or a step is about.

Fotollection is an independent open-source project. It is not affiliated with, sponsored or endorsed by any of these companies, and every other trademark belongs to its owner.

The Fotollection name and logo identify the official app, made by @hoangphi01. Official downloads come only from fotollection.org and the project's GitHub releases. The GPL-3.0 licence lets anyone share or sell copies, changed or not, as long as they keep this licence and offer the source code; a changed or resold copy must not use the Fotollection name or logo in a way that suggests it is the official app.

Sharing or selling Fotollection, or building on it? Please tell the author first by opening an issue on GitHub (github.com/hoangphi01/fotollection/issues). The app is free and made in spare time; a short note is the fair way to say thanks.

Quoting, reviewing or showing the app, or using these screenshots? Please credit Fotollection and link to fotollection.org.