Programmatically generate images with CSS Painting API

Programmatically Generate Images with CSS Painting API

A JavaScript API for dynamic image creation coupled with CSS

Images add color to an application. However, as we all know, having a lot of high-resolution images affects the page load time. For images of products, scenarios, and so on, we have no option but to include these images and optimize the application by caching them. But if you need a geometric image in your application, you don’t have to include it as an asset anymore.

You can programmatically generate geometric images on the fly using the CSS Painting API.

Let’s find out what this API is and how to generate an image using it.

Introduction to the CSS Painting API

The CSS Painting API enables developers to write JavaScript functions to draw images into CSS properties like background-image and border-image. It provides a set of APIs that gives developers access to the CSSOM. This is a part of CSS Houdini (Houdini — a collection of new browser APIs, gives developers lower-level access to CSS itself.).

The traditional approach to include an image is as follows.

div {
background-image: url('assets/background.jpg);
}

With the CSS Painting API, you can call the paint() function and pass in a worklet written in JS instead of the above.

div {
background-image: paint(background);
}

The workflow of this would be as follows.

You may have come across some unknown terms in the above section. For example, what are these worklets that we keep talking about?

In brief, the JavaScript code written to programmatically generate an image is called a Paint Worklet. A worklet is an extension point into the browser rendering pipeline. There are other types of worklets apart from paint worklets as well, such as animation worklets, layout worklets, etc.

Now let’s look at a step-by-step approach to generate an image programmatically.

Using the CSS Painting API in practice

In this article, we’ll look at how to create a bubble background.

Step 1: Add the CSS paint() function

First of all, you need to add the paint() function to the CSS property you need your image to be on.

.bubble-background {
width: 400px;
height: 400px;
background-image: paint(bubble);
}

bubble will be the worklet that we create to generate the images. This will be done in the next few steps.

Tip: Share your reusable components between projects using Bit (Github).

Bit makes it simple to share, document, and reuse independent components between projects. Use it to maximize code reuse, keep a consistent design, speed up delivery, and build apps that scale.

Bit supports Node, TypeScript, React, Vue, Angular, and more.

Example: exploring reusable React components shared on Bit.dev

Step 2: Defining the worklet

The worklets need to be kept in an external JS file. The paint worklet would be a class . E.g.:- class Bubble { …. } . This worklet needs to be registered using the registerPaint() method.

class Bubble {
paint(context, canvas, properties) {
........
}
}
registerPaint('bubble', Bubble);

The first parameter of the registerPaint() method should be the reference you included in CSS.

Now let’s draw the background.

class Bubble {
paint(context, canvas, properties) {
const circleSize = 10;
const bodyWidth = canvas.width;
const bodyHeight = canvas.height;

const maxX = Math.floor(bodyWidth / circleSize);
const maxY = Math.floor(bodyHeight / circleSize);

for (let y = 0; y < maxY; y++) {
for (let x = 0; x < maxX; x++) {
context.fillStyle = '#eee';
context.beginPath();
context.arc(x * circleSize * 2 + circleSize, y * circleSize * 2 + circleSize, circleSize, 0, 2 * Math.PI, true);
context.closePath();
context.fill();
}
}
}
}
registerPaint('bubble', Bubble);

The logic to create the image is inside the paint() method. You would need a bit of knowledge on canvas creation to draw images as above. Refer to the Canvas API documentation if you aren’t familiar with it.

Step 3: Invoke the worklet

The final step would be to invoke the worklet in the HTML file.

<div class="bubble-background"></div>
<script>
CSS.paintWorklet.addModule('https://codepen.io/viduni94/pen/ZEpgMja.js');
</script>

It’s done!

You have programmatically generated an image in just 3 steps.

Generated image

The output of what we created will look as follows.

View in Editor

What else can we do with this CSS Painting API?

The power of the CSS Painting API is not over yet. There are more things you can do with it.

1. You can create dynamic images

For example, you can dynamically change the color of the bubbles. CSS variables are used for this purpose. In order to use CSS variables, the browser should have prior knowledge that we are using it. We can use the inputProperties() method to do this.

registerPaint('bubble', class {
static get inputProperties() {
return ['--bubble-size', '--bubble-color'];
}

paint() {
/* ... */
}
});

The variables can be assigned using the third parameter passed to the paint() method.

paint(context, canvas, properties) {
const circleSize = parseInt(properties.get('--bubble-size').toString());
const circleColor = properties.get('--bubble-color').toString();

const bodyWidth = canvas.width;
const bodyHeight = canvas.height;

const maxX = Math.floor(bodyWidth / circleSize);
const maxY = Math.floor(bodyHeight / circleSize);

for (let y = 0; y < maxY; y++) {
for (let x = 0; x < maxX; x++) {
context.fillStyle = circleColor;
context.beginPath();
context.arc(x * circleSize * 2 + circleSize, y * circleSize * 2 + circleSize, circleSize, 0, 2 * Math.PI, true);
context.closePath();
context.fill();
}
}
}

2. You can generate random images using Math.random() in the paint() method.

// CSS
body {
width: 200px;
height: 200px;
background-image: paint(random);
}
// JS
function getRandomHexColor() {
return '#'+ Math.floor(Math.random() * 16777215).toString(16)
}
class Random {
paint(context, canvas) {
const color1 = getRandomHexColor();
const color2 = getRandomHexColor();

const gradient = context.createLinearGradient(0, 0, canvas.width, 0);
gradient.addColorStop(0, color1);
gradient.addColorStop(1, color2);

context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
}
}
registerPaint('random', Random);

If you want to know more details about how to implement these, let me know in the comments section below.

It’s awesome, isn’t it?

But, every good thing has at least one bad side to it. This API has very limited support in browsers.

Browser Support

Source: Can I Use

Most browsers including Firefox have no support for the CSS Paint API. Only Chrome and Chromium-based browsers have full support for this so far. Let’s hope that browser support will improve in the near future.

Summary

The CSS Paint API is extremely useful to reduce the response time of network requests. This is achieved by generating some images programmatically rather than retrieving them via network requests.

On top of this, the main benefits in my opinion are as follows.

  • Ability to create fully customizable images as opposed to static images.
  • It creates resolution-independent images (no more bad quality images on your site).

An important point to note is that you can use a polyfill as a workaround to support the browsers like Firefox that’s yet to implement the CSS Painting API.

Let us know your thoughts on this too. Thanks for reading!

Learn more


Programmatically generate images with CSS Painting API was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Bits and Pieces - Medium and was authored by Viduni Wickramarachchi

Programmatically Generate Images with CSS Painting API

A JavaScript API for dynamic image creation coupled with CSS

Images add color to an application. However, as we all know, having a lot of high-resolution images affects the page load time. For images of products, scenarios, and so on, we have no option but to include these images and optimize the application by caching them. But if you need a geometric image in your application, you don’t have to include it as an asset anymore.

You can programmatically generate geometric images on the fly using the CSS Painting API.

Let’s find out what this API is and how to generate an image using it.

Introduction to the CSS Painting API

The CSS Painting API enables developers to write JavaScript functions to draw images into CSS properties like background-image and border-image. It provides a set of APIs that gives developers access to the CSSOM. This is a part of CSS Houdini (Houdini — a collection of new browser APIs, gives developers lower-level access to CSS itself.).

The traditional approach to include an image is as follows.

div {
background-image: url('assets/background.jpg);
}

With the CSS Painting API, you can call the paint() function and pass in a worklet written in JS instead of the above.

div {
background-image: paint(background);
}

The workflow of this would be as follows.

You may have come across some unknown terms in the above section. For example, what are these worklets that we keep talking about?

In brief, the JavaScript code written to programmatically generate an image is called a Paint Worklet. A worklet is an extension point into the browser rendering pipeline. There are other types of worklets apart from paint worklets as well, such as animation worklets, layout worklets, etc.

Now let’s look at a step-by-step approach to generate an image programmatically.

Using the CSS Painting API in practice

In this article, we’ll look at how to create a bubble background.

Step 1: Add the CSS paint() function

First of all, you need to add the paint() function to the CSS property you need your image to be on.

.bubble-background {
width: 400px;
height: 400px;
background-image: paint(bubble);
}

bubble will be the worklet that we create to generate the images. This will be done in the next few steps.

Tip: Share your reusable components between projects using Bit (Github).

Bit makes it simple to share, document, and reuse independent components between projects. Use it to maximize code reuse, keep a consistent design, speed up delivery, and build apps that scale.

Bit supports Node, TypeScript, React, Vue, Angular, and more.

Example: exploring reusable React components shared on Bit.dev

Step 2: Defining the worklet

The worklets need to be kept in an external JS file. The paint worklet would be a class . E.g.:- class Bubble { .... } . This worklet needs to be registered using the registerPaint() method.

class Bubble {
paint(context, canvas, properties) {
........
}
}
registerPaint('bubble', Bubble);

The first parameter of the registerPaint() method should be the reference you included in CSS.

Now let’s draw the background.

class Bubble {
paint(context, canvas, properties) {
const circleSize = 10;
const bodyWidth = canvas.width;
const bodyHeight = canvas.height;

const maxX = Math.floor(bodyWidth / circleSize);
const maxY = Math.floor(bodyHeight / circleSize);

for (let y = 0; y < maxY; y++) {
for (let x = 0; x < maxX; x++) {
context.fillStyle = '#eee';
context.beginPath();
context.arc(x * circleSize * 2 + circleSize, y * circleSize * 2 + circleSize, circleSize, 0, 2 * Math.PI, true);
context.closePath();
context.fill();
}
}
}
}
registerPaint('bubble', Bubble);

The logic to create the image is inside the paint() method. You would need a bit of knowledge on canvas creation to draw images as above. Refer to the Canvas API documentation if you aren’t familiar with it.

Step 3: Invoke the worklet

The final step would be to invoke the worklet in the HTML file.

<div class="bubble-background"></div>
<script>
CSS.paintWorklet.addModule('https://codepen.io/viduni94/pen/ZEpgMja.js');
</script>

It’s done!

You have programmatically generated an image in just 3 steps.

Generated image

The output of what we created will look as follows.

View in Editor

What else can we do with this CSS Painting API?

The power of the CSS Painting API is not over yet. There are more things you can do with it.

1. You can create dynamic images

For example, you can dynamically change the color of the bubbles. CSS variables are used for this purpose. In order to use CSS variables, the browser should have prior knowledge that we are using it. We can use the inputProperties() method to do this.

registerPaint('bubble', class {
static get inputProperties() {
return ['--bubble-size', '--bubble-color'];
}

paint() {
/* ... */
}
});

The variables can be assigned using the third parameter passed to the paint() method.

paint(context, canvas, properties) {
const circleSize = parseInt(properties.get('--bubble-size').toString());
const circleColor = properties.get('--bubble-color').toString();

const bodyWidth = canvas.width;
const bodyHeight = canvas.height;

const maxX = Math.floor(bodyWidth / circleSize);
const maxY = Math.floor(bodyHeight / circleSize);

for (let y = 0; y < maxY; y++) {
for (let x = 0; x < maxX; x++) {
context.fillStyle = circleColor;
context.beginPath();
context.arc(x * circleSize * 2 + circleSize, y * circleSize * 2 + circleSize, circleSize, 0, 2 * Math.PI, true);
context.closePath();
context.fill();
}
}
}

2. You can generate random images using Math.random() in the paint() method.

// CSS
body {
width: 200px;
height: 200px;
background-image: paint(random);
}
// JS
function getRandomHexColor() {
return '#'+ Math.floor(Math.random() * 16777215).toString(16)
}
class Random {
paint(context, canvas) {
const color1 = getRandomHexColor();
const color2 = getRandomHexColor();

const gradient = context.createLinearGradient(0, 0, canvas.width, 0);
gradient.addColorStop(0, color1);
gradient.addColorStop(1, color2);

context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
}
}
registerPaint('random', Random);

If you want to know more details about how to implement these, let me know in the comments section below.

It’s awesome, isn’t it?

But, every good thing has at least one bad side to it. This API has very limited support in browsers.

Browser Support

Source: Can I Use

Most browsers including Firefox have no support for the CSS Paint API. Only Chrome and Chromium-based browsers have full support for this so far. Let’s hope that browser support will improve in the near future.

Summary

The CSS Paint API is extremely useful to reduce the response time of network requests. This is achieved by generating some images programmatically rather than retrieving them via network requests.

On top of this, the main benefits in my opinion are as follows.

  • Ability to create fully customizable images as opposed to static images.
  • It creates resolution-independent images (no more bad quality images on your site).

An important point to note is that you can use a polyfill as a workaround to support the browsers like Firefox that’s yet to implement the CSS Painting API.

Let us know your thoughts on this too. Thanks for reading!

Learn more


Programmatically generate images with CSS Painting API was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Bits and Pieces - Medium and was authored by Viduni Wickramarachchi


Print Share Comment Cite Upload Translate Updates
APA

Viduni Wickramarachchi | Sciencx (2021-02-09T23:50:27+00:00) Programmatically generate images with CSS Painting API. Retrieved from https://www.scien.cx/2021/02/09/programmatically-generate-images-with-css-painting-api/

MLA
" » Programmatically generate images with CSS Painting API." Viduni Wickramarachchi | Sciencx - Tuesday February 9, 2021, https://www.scien.cx/2021/02/09/programmatically-generate-images-with-css-painting-api/
HARVARD
Viduni Wickramarachchi | Sciencx Tuesday February 9, 2021 » Programmatically generate images with CSS Painting API., viewed ,<https://www.scien.cx/2021/02/09/programmatically-generate-images-with-css-painting-api/>
VANCOUVER
Viduni Wickramarachchi | Sciencx - » Programmatically generate images with CSS Painting API. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/02/09/programmatically-generate-images-with-css-painting-api/
CHICAGO
" » Programmatically generate images with CSS Painting API." Viduni Wickramarachchi | Sciencx - Accessed . https://www.scien.cx/2021/02/09/programmatically-generate-images-with-css-painting-api/
IEEE
" » Programmatically generate images with CSS Painting API." Viduni Wickramarachchi | Sciencx [Online]. Available: https://www.scien.cx/2021/02/09/programmatically-generate-images-with-css-painting-api/. [Accessed: ]
rf:citation
» Programmatically generate images with CSS Painting API | Viduni Wickramarachchi | Sciencx | https://www.scien.cx/2021/02/09/programmatically-generate-images-with-css-painting-api/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.