Basquiat, an IPFS-ready image resizing tool

Jean-Michel_Basquiat_graffiti

Basquiat, an IPFS-ready image resizing tool

Modern website designs have to be optimized for a wide range of devices. In order to minimize page load speed without sacrificing display quality, the size of the image is tailored to the device’s characteristics. In the centralized web, this is achieved on the server side by very fast image processing libraries such as libvips, the backbone of the popular imgproxy service.

How can we translate this functionality into the world of IPFS? In this article, I will give you a quick tour of basquiat, a new project which proposes a metadata spec and a simple implementation as first explorations of possible solutions to this emerging problem.

Primer

IPFS stores all data as a directed acyclic graph (DAG), which is essentially a tree in which a given node may have more than one parent. This tree structure is used to enable the partition of files into smaller and more manageable chunks. A node is pointed to through its content identifier (CID), a string of characters derived from the hash of its contents. This means that any CID references a static object. Each node is then a JSON-like dictionary possibly containing a data attribute which stores raw data, as well as the CIDs of other nodes containing the rest of the data.

This JSON-like data structure is defined in detail by IPLD, which is a continuously evolving specification. At first JSON-like meant json, then protobuf, and finally cbor. However, thanks to the IPLD spec, this difference in implementation can be abstracted away as we build our own spec on top of this data structure layer.

From very early on, IPFS has made use of an actual filesystem called UnixFS. Directories are implemented by adding named links to other resources within the node. For example, a cat.jpg file within a directory cid0 could be reached by the cid0/cat.jpg URI in addition to its own CID.

Basquiat

basquiat is a CLI tool implemented in Rust and built on top of go-ipfs and the libvips library. As input, it takes a path to an image as well as a configuration file which describes the targeted image sizes. Then, basquiat outputs a CID which points to the original image but contains named links to the generated versions.

$ basquiat -q ~/Pictures/yaks.jpg -c basquiat.cfg
QmfPYe4JzhcG41bXNnGUfCDZMLJ74KdQtZzniSz56t6i4F

QmfPYe4JzhcG41bXNnGUfCDZMLJ74KdQtZzniSz56t6i4F is an example output of basquiat. Directly opening this CID yields the original image. It is possible to explore the different generated versions by appending thumbnails.html to the CID.

For example, the given configuration generates a 601x400 version which can be reached in three ways :

QmfPYe4JzhcG41bXNnGUfCDZMLJ74KdQtZzniSz56t6i4F/601x400.jpg
QmfPYe4JzhcG41bXNnGUfCDZMLJ74KdQtZzniSz56t6i4F/601x_.jpg
QmfPYe4JzhcG41bXNnGUfCDZMLJ74KdQtZzniSz56t6i4F/_x400.jpg

The _ wildcard character means that applications don’t have to know the dimensions or aspect ratio of the original image in order to request a particular size. Indeed, basquiat is more than a CLI tool, it also proposes a flexible and extensible link naming schema in order to ensure eventual compatibility across different implementations. basquiat's configuration parser is also an implementation of this specification.

For a quick start with basquiat, please check out the README!

Future Development

There are several different possible ways forward for the project :

  • Right now, basquiat takes a static configuration file that enumerates every required version. An important step in order to make it more usable would be to ease generation of configuration files from target device characteristics as well as relative image display size.

  • The metadata specification is extensible to different operations such as cropping. Implementing a plugin system for basquiat would allow for this extensibility to be reflected in the implementation.

  • Integration within Fission CLI.

  • Browser-ready implementation using the pica library and js-ipfs.

Please don’t hesitate to request features by opening an issue on the basquiat repo!.

1 Like

This sounds very cool! Would be perfect for the ipfs-photo-gallery app I’ve been building. Unfortunately, I don’t see how I could make it work as my app is just a react app that uses the fission typescript library and doesn’t have a backend. Cool idea, though!

1 Like

@patdryburgh yep we focused on the CLI use case first, for devs publishing from their desktops.

We’re exploring different ways of making this browser based.

As a developer / designer, ideally this would be as simple as even calling the image with what dimensions you want.

Any wishlist items you’ve always wanted from image processing?

You can run libvips in the browser, so that’s perhaps another option. It compiles to ~4mb with emscripten, and should be quite a bit quicker than pica.

Demo:

https://kleisauke.nl/vips.js/

2 Likes

Very interesting! Thanks @jcupitt for sharing that link!

Thanks for the link!

I do agree with you that libvips would be much faster than pica. Still, I think pica is the better option right now for two reasons :

  • Compatibility : The demo implementation you linked to requires SharedArrayBuffers which are disabled in most browsers (including Firefox, but excepting Chrome) right now due to the Spectre vulnerabilities. Pica is a bit smarter in this regard and only executes webasm code when possible, and reverts to secondary implementations otherwise.
  • Maintainability : Libvips doesn’t officially support support compilation to webasm, and the author of the demo hasn’t published the build script yet. From what information he left behind in an issue on the libvips repo, I can gather that compilation isn’t that straightforward and a bit hacky.

This all means that integrating an asm version of libvips into the project would probably be a major hassle, and I’m not even sure it would be worth it : the difference in speed between libvips and pica only matters when uploading a large number of images with a large number of versions, in which case the CLI can be used.

Kleis is one of the libvips maintainers and his wasm patches are being incorporated for 8.10. vips.js is a work in progress, but it should become an officially supported platform soon.

You are quite right that fast enough is fast enough and there are many other more important factors to consider when selecting a library.

(edit: I suppose image size would be a factor, as well as the number of images. You’ll need to be able to support the large images that some phones make now.)

2 Likes