Image Processing Pipeline — a modern image build orchestrator

A free and open-source tool to help make websites pop

Marcus Cemes
Sep 21, 2020 · 6 min read
Photo by Luke Chesser on Unsplash

his is a post that I have been putting off for a while, but I think the time has come to share this with the community. Two years ago I sat down to start a new project, an experiment involving image downscaling and Node.js, and since then it has become my primary open-source project.

I wanted to generate responsive images for my website to offer a better experience. It came to life as a set of Node.js scripts, and over the course of several iterations, evolved into an open-source package released on npm under the name Responsive Image Builder.

It was created out of necessity due to a lack of existing open-source solutions.

Let me be clear, there are a variety of image tools, loaders, and third-party services. However, none of them, in my opinion, fulfilled my needs. Furthermore, I was in love with gatsby-image and the primitive library by Michael Fogleman (which was difficult to integrate into existing solutions).

This led me to create my own solution to solve my rather unique requirements:

  • 🔥 Fast (obviously…)
  • 💎 Best image algorithms (Lanczos3 😎)
  • 🌁 Support beautiful SVG placeholders such as the primitive library
  • 🙏 Simple
  • OS-agnostic, free, parallelization, no network round-trips, no upscaling, …

My goal was to glue together existing image libraries into a unified toolset that could be customised to allow the processing of images in different ways.

Psst! You can read more about the motivation behind the project here.

Today it goes by a different name that better reflects its new functionality (and partly due to a reserved package scope ️🤦‍♂️): Image Processing Pipeline. The processing “workflow” is now completely customisable and it has also just had a major release that refactored the internals, making it easier to implement adapters, such as the new webpack loader!

The new IPP features a declarative pipeline format. Tell it *how* it should generate your images!

Much to my own surprise, the open-source repository on GitHub has been slowly gaining stars, an issue, and even featured in an article on Medium, despite never sharing or mentioning the project online. I wanted to wait for a truly stable release of IPP before announcing it officially, but it seems that the online community is restless and eager to try new things!

Perhaps this is the right time. Summer is coming to an end and my university studies have resumed. I am, however, still fully committed to maintaining the project for the foreseeable future. It is, however, an enormous undertaking for a single contributor, so don’t expect nightly releases.

Maybe try using it on a smaller project and see if it suits your needs. If you feel like contributing, PRs are welcome! Bear in mind that the aim is to keep the core as simple as possible to promote maintainability and not feature float.

IPP is not limited to website development, but may also prove useful for batch image processing or backend image jobs, as it does not require any code to use.

I have been hard at work creating a new documentation website that is accessible for users of all technical backgrounds. Bear in mind that it is still an active work in progress. Until it is completed there is also the option of consulting the source code, which aims to be simple and human-readable.

Let’s dive in

The following section is a quick-start guide for the command-line interface. A more complete example is available at the website above.

Prerequisites

IPP runs on Node.js and is distributed via npm. They are bundled together and can be obtained from the official website.

It’s recommended to get an LTS release or a less recent version of Node.js to avoid installation problems. Learn more

Installation

Open up a terminal somewhere and execute the following (without the dollar sign), which will install the CLI globally on your system (other installation options are available):

$ npm install --global @ipp/cli

And that’s it! ✨

Once again, if you get a node-gyp related installation error, try an older release of Node.js to avoid having to install Python and a C++ compiler. This is a design limitation, compiled languages are hard and IPP wants to be fast!

Usage

Grab some images and chuck them into a new folder with a name of your choosing.

Next to that folder, create a configuration file called .ipprc.yml . Copy and paste the following into that file (replacing “images” with the name of the folder you created previously):

input: images
output: formats
manifest:
source:
x: hash:12
format:
w: width
p: path
pipeline:
- pipe: resize
options:
resizeOptions:
width: 1280
save: "[source.name]-[hash:8][ext]"

Next, open up a terminal prompt, navigate to the folder containing the configuration file and run IPP:

$ ipp

If everything was set up correctly, IPP will display some helpful runtime information and report a successful operation. There should now be a second folder called formats with a bunch of new images!

So what did it do?

The above configuration file takes each source image and resizes it to have a maximum width of 1280 pixels. Images smaller than this threshold will not be resized but passed along. This is where IPP starts to shine! The image is then saved, using IPP’s version of template literals to generate the filename.

Additionally, notice the manifest.json file in the formats directory. This contains a JSON summary of all output results. For example, you might find an entry that resembles the following:

{
"f": [
{
"w": 1280,
"p": "red-green-macaw-74cd8540.jpg"
}
],
"s": { "x": "7f5d4e26980c" }
}

The manifest file is generated based on the manifest key in the configuration file. The current manifest configuration outputs the hash of the source image, limited to 12 characters, and the width and path of each output format image.

Tip: the source hash is generated from the file contents and will never change, it could be useful as an image-lookup mechanism

IPP is not a blind resize tool but is context-aware. It also aims to make the consumer (such as the browser) aware by providing a list of available images, and letting them pick the best-suited image based on image dimensions, codec, etc…

The manifest file can be further processed or it can be downloaded and cached by the client. There are even better options, such as the official webpack loader that convert image imports into a single manifest entry, like the example above.

How does it work?

A single image transformation is represented by the concept of a pipe. In reality, it’s an asynchronous pure function (you can even make your own!).

An image is represented by a binary buffer and a metadata object. They are related pieces of data and therefore stay together (internally referred to as a DataObject). Metadata provides contextual information about the buffer and is slowly “built up” by each pipe.

Pipes may be interconnected using the then property to create a pipeline branch (resembling a tree). An array of pipeline branches creates a pipeline.

- pipe: resize
then:
- pipe: compress
save: "[source.name][ext]"
- pipe: convert
...

Every pipe may additionally specify a save property, which exports its output from the pipeline. The exported image is called a format and is a snapshot of the DataObject at that point in the pipeline (immutability is key here).

This is the basic architecture of the @ipp/core package. Implementations (such as the command-line interface) can decide on how to handle finer details, such as how to handle the save key and store metadata.

Ready for more?

Thank you for sticking to the end! There is a lot more than you can read in the official documentation.

There are more planned features, such as asynchronous iterator support to improve memory efficiency, optional disk-based caching, more adapters, front-end integrations, …

This is my first article on an open-source project and I’m excited to hear your comments and feedback! 😁 What workflows do you use for your images?

P.S. I’ll be absolutely gutted if someone replies with “hey, this already exists, check out…”. At least it was a great learning experience, right…?

Weekly Webtips

Explore the world of web technologies through a series of tutorials

Sign up for 💌 Weekly Newsletter

By Weekly Webtips

Get the latest news on the world of web technologies with a series of tutorial Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Marcus Cemes

Written by

Filmmaker, photographer and passionate coder. Studying Microengineering at EPFL. https://mastermovies.uk

Weekly Webtips

Explore the world of web technologies through a series of tutorials

Marcus Cemes

Written by

Filmmaker, photographer and passionate coder. Studying Microengineering at EPFL. https://mastermovies.uk

Weekly Webtips

Explore the world of web technologies through a series of tutorials

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store