DEV Community

Cover image for Adding Gray Scale Filter in React- Pigshell
Vinit Gupta
Vinit Gupta

Posted on

Adding Gray Scale Filter in React- Pigshell

I hope you haven't forgotten about Pigshell?
Well, I am not writing this post to share my completion. I'll be sharing my current progress.

What I have completed?

Unfortunately, my laptop didn't want to get charged up.

So I could not post any updates.
I have completed loading the image and adding a grayscale filter to the uploaded image. It took me a little time to implement this as I had not worked with <canvas> HTML element before.
The working steps are explained below :

Step 1 : Taking Image to Convert

The thing is uploading images are easy. Just take an input element and specify the type of input :

<input type="file" accept="image/*" name="uploadedImage" id="uploadedImage"/>
Enter fullscreen mode Exit fullscreen mode

Now there are 2 elements to this line :

  • type="file"
  • accept="image/*"

The first one is simple : only accept file type input
The second one is also similar to it : only accept images, but what does the /* mean?

It means the you can give any type of image as input like png, jpg, jpeg and svg.

Step 2 : Displaying the Uploaded Image

The next step was to display the image just inserted by the user.
This might seem simple : just have a <div></div> that displays the image.

But there are 2 things to understand here :

  1. The uploaded image is a blob and you cannot display a blob directly in HTML.
  2. We create a URL for the uploaded image and add it to the <img/> element.

Note that I am using React, so the syntax is JSX

<img src={previewImage} alt="to convert" ref={uploadRef} />
Enter fullscreen mode Exit fullscreen mode
const [previewImage, setPreviewImage] = useState(null);

const uploadRef = useRef(null);

function fileChangedHandler(event){
   setImageToConvert(new Image(event.target.files[0]));
   setPreviewImage(URL.createObjectURL(event.target.files[0]));
 }
Enter fullscreen mode Exit fullscreen mode

But there are 2 issues with the styling here.

  • The images uploaded maybe landscape or portrait mode, and
  • The image size may exceed the size of the div

Naturally, I had to use a max-width and object-fit:contain properties together to make the image adjust.

Displaying the uploaded Image

Step 3 : The main event - Loading image to Canvas

When trying to think how to convert images to pixel values, the first thing that came to my mind was : canvas.
The next thing tat came : I don't know how??

Naturally, I headed to MDN and studied about it. I came to the conclusion that loading images to canvas is very simple.

You can also checkout this post by FreeCodeCamp for a detailed explanation for that.

The code I used is this in React :

    const canvRef = useRef(null); // I am using this to refer to the canvas element as I cannot use querySelector in React.

const loadImageToCanvas = ()=>{
      const canvas = canvRef.current;
      const ctx = canvas.getContext('2d');
      const currImage = new Image();
      currImage.src = previewImage;

      canvas.height = currImage.height;
      canvas.width = currImage.width;
      ctx.drawImage(currImage, 0,0, canvas.width, canvas.height);
    }

Enter fullscreen mode Exit fullscreen mode

This code simply loads the image to the canvas.
But there was a confusion that made me slow down : What do I pass as the image in the drawImage() function.
I tried passing the file uploaded directly, as this was my first thought.
But this didn't work.
Then I understood after some reading that the function accepts the Image() object only.
So I had to use this piece of code to get that :

const currImage = new Image();
currImage.src = previewImage;
Enter fullscreen mode Exit fullscreen mode

Step 4 : Grayscale Filter

An important concept that I learned in my Image Processing class is that :

The grayscale value of a pixel in a color image in the average of the Red, Green and Blue values of that pixel.

I had to use it here. But how to get the rgb() value of a particular pixel?
I came across a function : getImageData() which was a function of the canvas element.
This returns an array (not a simple one, but something called a Uint8ClampedArray ), which we can iterate over and get the RGBA values of each pixel.
We can just calculate the average and replace the original data for that particular pixel.
This magically gives us the grayscale image of the original image :

Grayscale conversion

And there we have it : the current status of Pigshell.

You can checkout the whole code here on šŸ‘‰šŸ‘‰ Github

Do remember to checkout the previous post to see the plan.

Cover Image by Jakob Owens on Unsplash

Top comments (2)

Collapse
 
moose_said profile image
Mostafa Said

Awesome work! keep it up :)

Collapse
 
thevinitgupta profile image
Vinit Gupta

Thanks a lot for you support šŸ™Œ