Image Processing Pipeline — a modern image build orchestrator
Tags: showdev, webdev, node, productivity
Published: 2020-09-21 10:38:56

---
title: Image Processing Pipeline — a modern image build orchestrator
published: true
description: A free and open-source tool to help make websites pop
tags: showdev,webdev,node,productivity
cover_image: https://source.unsplash.com/a2NRu2Wxa2o/1920x1200
---

This 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](https://cloudinary.com/). However, none of them, in my opinion, fulfilled my needs. Furthermore, I was in love with [gatsby-image](https://www.gatsbyjs.com/plugins/gatsby-image/) and the [primitive library](https://github.com/fogleman/primitive) 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 processing of images in different ways.

> Psst! You can read more about the motivation behind the project [here](https://ipp.vercel.app/blog/2020/09/12/motivation).

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](https://medium.com/swlh/automatic-adaptive-images-in-angular-applications-a93942d3e85a), 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](https://github.com/MarcusCemes/image-processing-pipeline), which aims to be simple and human-readable.

https://ipp.vercel.app

---

## 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](https://nodejs.org).

> It's recommended to get an LTS release or a less recent version of Node.js to avoid installation problems. [Learn more](https://ipp.vercel.app/docs/troubleshooting#node-gyp--sharp-error)

### 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](https://unsplash.com/) 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):

```yaml
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:

```json
{
  "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](https://ipp.vercel.app/docs/webpack) 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_.

```yaml
- 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 that you can read in the [official documentation](https://ipp.vercel.app).

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…?_