The File Handling API allows web applications to register themselves as a file handler for file formats the application can support. Learn how the image editing application Photopea makes use of this API.
Introduction
(This article is also available in form of a video.)
Photopea is a free online image editor developed by Ivan Kutskir. Ivan started working on the app in 2012, and maintains a blog sharing the major features he adds to Photopea. Photopea can work with PSD (Adobe Photoshop), XCF (GIMP), Sketch (Sketch App), XD (Adobe XD), and CDR (CorelDRAW) formats.
File handling in Photopea
As an installable PWA, Photopea runs in a standalone window when the user chooses to install the app. Doing so unlocks a PWA super power, which Photopea makes heavy use of: file handling.
The declarative part of the File Handling API
After installation, Photopea registers itself as a file handler with the operating system for the different file formats it supports. This happens in the Web App Manifest, by adding the file_handlers
field. Each supported file type is an object, the action
has a relative URL as its value, the accept
object a map of MIME types and associated file extensions. For example, {"image/jpeg": [".jpeg", ".jpg"]}
. The following code is the production Web App Manifest of Photopea, with the relevant parts highlighted.
{
"name": "Photopea",
"short_name": "Photopea",
"display": "standalone",
"icons": [
{ "src": "promo/icon512.png", "type": "image/png", "sizes": "512x512" },
{ "src": "promo/maskable512.png", "type": "image/png", "sizes": "512x512", "purpose":"maskable" }
],
"start_url": "/?utm_source=homescreen",
"background_color":"#0f171d",
"theme_color": "#474747",
"file_handlers": [
{ "action": "/", "accept": { "image/psd" : [ ".psd" ] } },
{ "action": "/", "accept": { "image/jpeg": [ ".jpeg", ".jpg" ] } },
{ "action": "/", "accept": { "image/png" : [ ".png" ] } },
{ "action": "/", "accept": { "image/webp": [ ".webp" ] } },
{ "action": "/", "accept": { "image/bmp" : [ ".bmp" ] } },
{ "action": "/", "accept": { "image/gif" : [ ".gif" ] } },
{ "action": "/", "accept": { "image/svg+xml": [ ".svg" ] } },
{ "action": "/", "accept": { "image/pdf" : [ ".pdf" ] } },
{ "action": "/", "accept": { "image/tiff": [ ".tif", ".tiff" ] } },
{ "action": "/", "accept": { "image/ai" : [ ".ai" ] } },
{ "action": "/", "accept": { "image/psb": [ ".psb" ] } },
{ "action": "/", "accept": { "image/xcf": [ ".xcf" ] } },
{ "action": "/", "accept": { "image/sketch": [ ".sketch" ] } },
{ "action": "/", "accept": { "image/xd" : [ ".xd" ] } },
{ "action": "/", "accept": { "image/pxd": [ ".pxd" ] } },
{ "action": "/", "accept": { "image/cdr": [ ".cdr" ] } },
{ "action": "/", "accept": { "image/eps": [ ".eps", ".ps" ] } },
{ "action": "/", "accept": { "image/x-icon": [ ".ico" ] } },
{ "action": "/", "accept": { "image/jpx": [ ".jpx" ] } },
{ "action": "/", "accept": { "image/jp2": [ ".jp2" ] } },
{ "action": "/", "accept": { "image/x-tga": [ ".tga" ] } },
{ "action": "/", "accept": { "image/vnd-ms.dds": [ ".dds" ] } }
],
"share_target": {
"action": "/",
"method": "POST",
"enctype": "multipart/form-data",
"params": {
"files": [
{
"name": "image",
"accept": ["image/jpeg", "image/png", "image/webp", "image/gif"]
}
]
}
}
}
The imperative part of the File Handling API
The imperative part of the API then deals with actually handling the file(s) that the operating system passes to the PWA. Photopea's code is obviously heavily minimized and uglified, but nevertheless the gist of the snippet below is not so hard to grasp. The LaunchQueue
interface (minified as N
) has a setConsumer()
method, which accepts a function as an argument. This function in turn takes a LaunchParams
object (minified as W
) . This LaunchParams
object has a files
property pointing at a read-only array of FileSystemHandle
objects, which the rest of the code then loops over and for each obtains the File
object (minified as G
) by calling getFile()
. This file is then passed off to other logic in Photopea that takes care of displaying the file.
var N = window.launchQueue;
if (N) {
var $ = this.UA;
N.setConsumer(function (W) {
var O = W.files;
console.log(O);
for (var Y = 0; Y < O.length; Y++) {
var T = O[Y];
T.getFile().then(function (G) {
$.YO([G], null, null, null, [T]);
});
}
});
}
Conclusions
Users have been asking for Photopea to become a file handler for images for a long time. In 2020, when the question appeared, this feature was completely unthinkable, but an eager user discovered the file handling API in its earliest stages in the beginning of 2022 when it was still behind a flag. File handling eventually shipped in Chrome 102 and has been a beloved Photopea feature used on a daily basis by its users, some even calling it a gamechanger. Be sure to give Photopea a try, install it on your desktop, and then try opening one of the file formats it supports! Happy image editing!