Enhance Your Photos with the CSS Contrast, Brightness, Saturation, and Sepia Functions

Written by ljaviertovar | Published 2023/08/22
Tech Story Tags: react | javascript | css3 | html5 | react-tutorial | javascript-tutorial | web-development | programming

TLDRvia the TL;DR App

Nowadays, many applications help us to edit our photos and images. With these applications, we can add some artistic effect or a filter that makes our image look with better color or maybe without color or look like an old photo, etc.

Apps such as Instagram offer editing options with many predefined filters and the option to create one by ourselves. This makes me wonder: “How do filters work on digital images? How are they created, or what do they do to the image?”.

I’m not going to address issues such as image processing with graphics or algorithms, but I would like to develop an application that allows us to add filters to an image.

Using web technologies and a cool repository, I found we will develop a clone of the Instagram filters.

What is a filter on an image?

A filter is a mathematical equation (called a convolution product) that allows modifying the value of a pixel according to the values of contiguous pixels, with coefficients for each pixel in the region to which it is applied.

Different objectives:

  • Smooth the image: reduce intensity variations between neighboring pixels.

  • Eliminate noise: modify those pixels whose intensity level is very different from that of their neighbors.

  • Enhance the image: increase intensity variations where they occur.

  • Detect edges: detect those pixels where there is an abrupt change in the intensity function.

The CSS Filter property

The CSS filter property provides graphical effects such as blurring or color change in the rendering before the element is displayed. Filters are commonly used to adjust the rendering of images, backgrounds, or borders.

The functions that we will use of this property to create our filters are:

contrast(): This is the difference in light intensity between the black and white tones of the image. High contrasts darken shadows and dark tones more, making whites brighter, while low contrasts decrease the intensity of both ranges.

brightness(): The attribute of a visual sensation whereby an area appears to show more or less light.

saturate(): It is the intensity of each color in a photo according to its composition’s degree of white, black, or gray. The more absence of these on a color, the more purity and intensity. And the more it is mixed with gray, the less saturation.

sepia(): A sepia image is a black-and-white image that has a warm brown tone. Sepia tints can make an image look older.

grayscale(): Grayscale is a range of monochrome shades of black to white. Therefore, a grayscale image contains only shades of gray and no color.

Time to Code

As I mentioned before, we will use Instagram.css, which is like a CSS class library that provides us with filters very similar to Instagram’s. You can find the repository and demo of the application we will develop at the end of the tutorial.

Setting Up

We create our application with the following command:

npx create-react-app myApp

We install the dependencies that we will need in the project:

npm i react-slick slick-carousel rc-slider styled-components react-icons

After that, we create the following structure for the project:

src/
├── assets/
│   ├── fonts
│   └── img
├── components/
│   ├── CustomFilter.jsx
│   ├── CustomFilterOptions.jsx
│   ├── Filter.jsx
│   ├── ImgWrapper.jsx
│   ├── NormalFilter.jsx
│   └── Title.jsx
├── pages/
│   └── Home.js
├── styles/
│   └── GlobalStyles.js
│   ├── instagram.min.css
│   └── Typography.js
├── App.js
└── index.js

As you can see, it will be a simple application where what we want to review is how to add the CSS classes to our previously added image in the assets/img folder.

Also, develop functionalities with which we will be able to create a customized filter.

Components

Home.jsx: It is the root component, where we will create a couple of states which will allow us to know which filter is selected at the moment and thus apply it to our main image.

It also has a state that will be responsible for saving the custom filters that the user will select through the range of Sliders that we are going to create.

Filters.jsx: In this component, we import the file instagram.min.css and we map the names of the classes that the library offers us. I have created a JSON object which contains all the available classes.

const filters = [
  { name: 'Aden', class: 'filter-aden'},
  { name: 'Amaro', class: 'filter-amaro'},
  { name: 'Ashby', class: 'filter-ashby'},
  { name: 'Brannan', class: 'filter-brannan'}
  ...
]

Now with the filters in an object, we will make a map and create for each element a card with the image we want to edit, adding the corresponding class to give a preview of the added effect.

In addition to that with the react-slick library, we have created a Slider so we can visualize all the elements.

import React, { useEffect } from 'react'
import styled from 'styled-components'
import Slider from 'react-slick'

import thumbnail from '../assets/img/img1.jpg'

import '../styles/instagram.min.css'
import 'slick-carousel/slick/slick.css'
import 'slick-carousel/slick/slick-theme.css'

const FiltersStyles = styled.div`
  width: 70%;
  margin: auto;
  .slick-prev:before {
    color: var(--blue-1);
  }
  .slick-next:before {
    color: var(--blue-1);
  }
`
const Filters = ({ filterClass, setFilterClass, imgRef }) => {
  useEffect(() => {
    const divImg = imgRef.current
    divImg.style.filter = ''
  }, [filterClass])

  const filters = [
    {
      name: 'Aden',
      class: 'filter-aden',
    },
    {
      name: 'Amaro',
      class: 'filter-amaro',
    },
    {
      name: 'Ashby',
      class: 'filter-ashby',
    },
  ]

  const settings = {
    dots: false,
    Infinite: true,
    speed: 500,
    slidesToShow: 5,
    slidesToScroll: 5,
  }

  return (
    <FiltersStyles>
      <Slider {...settings}>
        {filters.map((filter, index) => {
          return (
            <div key={index}>
              <div
                className={`filter-item ${
                  filterClass === filter.class ? 'filter-item--selected' : ''
                }`}
                onClick={() => setFilterClass(filter.class)}
              >
                <div className="filter-item__img">
                  <img
                    className={filter.class}
                    src={thumbnail}
                    alt={filter.name}
                  />
                </div>
                <div className="filter-item__name">
                  <p>
                    <strong>{filter.name}</strong>
                  </p>
                </div>
              </div>
            </div>
          )
        })}
      </Slider>
    </FiltersStyles>
  )
}

export default Filters

CustomFilterOptions.jsx: In this component, we try to create controls that allow us to create our effect. For this case, we use the CSS Filter property, which provides us with several interesting functions.

So that our app is more similar to the controls of the already existing applications, I have used the rc-slider library with which we will create ranges of values with which each function of the Filter property works.

We will create a state and initialize it with the starting value of each effect. Using the Sliders, we will save each newly selected value with the onChange property of each component.

Finally, we have a function that we call setCustomFilterClass with which we will create our CSS style starting from the values of each effect that we create and if we assign it to our main image.

With this, the effect will be created in our image.

import React, { useState } from 'react'
import Slider, { SliderTooltip } from 'rc-slider'
import styled from 'styled-components'

import 'rc-slider/assets/index.css'

const CustomFilterOptionsStyles = styled.div`
  .customFilters-container {
    width: 400px;
    margin-right: 100px;
  }
  .customFilters-item {
    margin: 3rem 0;
    display: flex;
    gap: 1rem;
    align-content: center;
    p {
      width: 160px;
    }
  }
`

const CustomFilterOptions = ({ imgRef }) => {
  const [contrast, setContrast] = useState(100)
  const [brightness, setBrightness] = useState(100)

  const { Handle } = Slider

  const handle = props => {
    const { value, dragging, index, ...restProps } = props

    return (
      <SliderTooltip
        prefixCls="rc-slider-tooltip"
        overlay={`${value} %`}
        visible={true}
        placement="top"
        key={index}
      >
        <Handle value={value} {...restProps} />
      </SliderTooltip>
    )
  }

  const onChangeContrast = value => {
    setContrast(value)
    setCustomFilterClass()
  }

  const onChangeBrightness = value => {
    setBrightness(value)
    setCustomFilterClass()
  }

  const setCustomFilterClass = () => {
    const style = `contrast(${contrast}%) brightness(${brightness}%) saturate(${saturate}%) sepia(${sepia}%) grayScale(${gray}%)`

    const divImg = imgRef.current
    divImg.style.filter = style
  }

  return (
    <CustomFilterOptionsStyles>
      <div className="customFilters-container">
        <div className="customFilters-item">
          <p>Contrast</p>
          <Slider
            step={1}
            min={0}
            max={200}
            defaultValue={contrast}
            handle={handle}
            onChange={onChangeContrast}
          />
        </div>
        <div className="customFilters-item">
          <p>Brightness</p>
          <Slider
            step={1}
            min={0}
            max={200}
            defaultValue={brightness}
            handle={handle}
            onChange={onChangeBrightness}
          />
        </div>
      </div>
    </CustomFilterOptionsStyles>
  )
}

export default CustomFilterOptions

That’s it! We have created an application with which we can assign Instagram-like effects to any image we want, in addition to being able to create our custom effect.

See the demo here

Project repo here

Conclusion

In this tutorial, we tried to simulate the operation of applications that edit images by adding filters or effects to them, in this case, Instagram-like filters.

Although this application can still be improved and add many other basic features that these types of apps have, we have developed the part that interested us about the filters.

I hope you had fun developing this app as I did and that you can add these features to any project that comes your way.


Read more:

Want to connect with the Author?

Love connecting with friends all around the world on Twitter.


Also published here.


Written by ljaviertovar | ☕ FrontEnd engineer 👨‍💻 Indie maker ✍️ Tech writer
Published by HackerNoon on 2023/08/22