šŸ“• LangChain for JavaScript developers is now out!
Build 5 Next.js apps with ChatGPT integrated features using LangChain.

Generating black-white and grayscale images with Javascript and canvas

In today's article, we will build a simple app where we can upload an image, and using Javascript and the canvas element we will get a black-white plus a grayscale version of that image.

black-white and grayscale images with Javascript and canvas

I will not get into too many details about the initial setup of the project. For a better understanding, I encourage you to read the posts about how to upload an image and generate its preview, and invert the colors of a picture on a canvas.

So, we will start with this HTML code:

<input id="inp" type='file' accept='image/*' capture='camera'/>
<img id="img" />
<canvas id="can-bw" width="200" height="200"></canvas>
<canvas id="can-bwg" width="200" height="200"></canvas>

And from this Javascript:

const input = document.querySelector('#inp')
const img = document.querySelector('#img')
const ID_BLACK_WHITE_CANVAS = 'can-bw'
const ID_GRAY_CANVAS = 'can-bwg'

input.addEventListener('change', () => {
  const url = URL.createObjectURL(input.files[0])
  img.src = url
})

img.onload = ()=> {
  setupCanvas(ID_BLACK_WHITE_CANVAS, toBlackAndWhite)
  setupCanvas(ID_GRAY_CANVAS, toBlackWhiteGray)
}

const setupCanvas = (id, pFunction)=> {
  const canvas = document.getElementById(id)
  const ctx = canvas.getContext('2d')
  ctx.drawImage(img, 0, 0)
  processCanvas(canvas, ctx, pFunction)
}

const processCanvas = (canvas, ctx, pFunction)=> {
  const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height)
  imgData.data = processImgData(imgData, pFunction)
  ctx.putImageData(imgData, 0, 0)
}

const processImgData = ({data}, pFunction) => {
  // use the pFunction to process the image
  return data
}

const toBlackAndWhite = () => {
  // to be implemented
}

const toBlackWhiteGray = (red, green, blue) => {
  // to be implemented
}

For the time being what this code does is just display the same picture we initially upload in the two canvases:
black-white and grayscale images with Javascript and canvas

By the way, if you want to add CSS styles on the upload button I've written a tutorial about this.

The data that arrives in the processImgData() is the result of ctx.getImageData(). As we have seen in the example with inverting the colors of a picture each set of 4 items from the data parameter represents an RGBA set for a pixel from the image. So, we can do something like this:

const processImgData = ({data}, pFunction) => {
  for (i = 0; i < data.length; i += 4) {
    data[i] //  red (0-255)
    data[i + 1] //  green (0-255)
    data[i + 2] //  blue (0-255)
    data[i + 3] //  alpha (0-255, 0 = transparent, 255 = fully visible)
  }
  return data
}

Therefore we need to find a way to convert the RGBA values to just one black/white/gray value.

The key points here are the toBlackAndWhite() and toBlackWhiteGray() functions, which are not yet implemented.

A toBlackWhiteGray() function can look like this:

const toBlackAndWhite = (red, green, blue) => {
  const count = red + green + blue
  const colour = count < 383 ? 0 : 255
  return colour
}

While the toBlackWhiteGray() function can look like this:

const toBlackWhiteGray = (red, green, blue) => {
  const count = red + green + blue
  let colour = 0
  if (count > 510) colour = 255
  else if (count > 255) colour = 127.5
  return colour
}

Of course, we can tweak the way we interpret the gray color, and could add a more complex grayscale to the function.

Finally, with these functions implemented, we can now replace a color pixel with the result of one of these functions:

const processImgData = ({data}, pFunction) => {
  for (i = 0; i < data.length; i += 4) {
    const color = pFunction(data[i], data[i+1], data[i+2])
    data[i] = color
    data[i + 1] = color
    data[i + 2] = color
    data[i + 3] = 255
  }
  return data
}

You can see here the full working codepen for this example.

I will leave it as homework to you to implement the functionality of downloading the resulting images. Hint, you can use the download attribute of links for this.

šŸ“– 50 Javascript, React and NextJs Projects

Learn by doing with this FREE ebook! Not sure what to build? Dive in with 50 projects with project briefs and wireframes! Choose from 8 project categories and get started right away.

šŸ“– 50 Javascript, React and NextJs Projects

Learn by doing with this FREE ebook! Not sure what to build? Dive in with 50 projects with project briefs and wireframes! Choose from 8 project categories and get started right away.


Leave a Reply

Your email address will not be published. Required fields are marked *