Adding Gray Scale Filter in React- Pigshell
Tags: javascript, appwritehack, webdev, react
Published: 2022-04-18 06:08:37

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.
<img width="70%" style="width:70%" src="https://media.giphy.com/media/3oAt2dA6LxMkRrGc0g/giphy.gif">

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 : 
```html
<input type="file" accept="image/*" name="uploadedImage" id="uploadedImage"/>
```
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`
```html
<img src={previewImage} alt="to convert" ref={uploadRef} />
```

```javascript
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]));
 }
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rfqjlhls22ws33picqr1.png)

## 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??**
<img style="width:70px; height:40px" src="https://media.giphy.com/media/bAftZ12SC0uEjLndIh/giphy.gif">

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](https://www.freecodecamp.org/news/how-displaying-an-image-on-html5-canvas-works-13e3f6a6c4bd/) for a detailed explanation for that.

The code I used is this in `React` : 
```javascript
    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);
    }

```
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 : 
```javascript
const currImage = new Image();
currImage.src = previewImage;
```

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yk6pf0fmish5glalqzi4.png)

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

You can checkout the whole code here on 👉👉 [Github](https://github.com/thevinitgupta/Pigshell)

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

Cover Image by <a href="https://unsplash.com/@jakobowens1?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Jakob Owens</a> on <a href="https://unsplash.com/s/photos/filter?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>