guide to adjusting contrast and saturation levels with fabric.js

I am looking to adjust the contrast, saturation, and hue in my image editor using fabric.js. However, I have only been able to find the brightness option.

Below is the code I have been using with fabric js:

(function() {

fabric.Object.prototype.transparentCorners = false;
  var $ = function(id){return document.getElementById(id)};
  console.log($);

  function applyFilter(index, filter) {
    console.log(filter);
      var obj = canvas.getActiveObject();
      obj.filters[index] = filter;
      obj.applyFilters(canvas.renderAll.bind(canvas));
  }

  function applyFilterValue(index, prop, value) {
   var obj = canvas.getActiveObject();
   if (obj.filters[index]) {
      obj.filters[index][prop] = value;
      obj.applyFilters(canvas.renderAll.bind(canvas));
    }
 }

  fabric.Object.prototype.padding = 5;
  fabric.Object.prototype.transparentCorners = false;

  var canvas = this.__canvas = new fabric.Canvas('c'),
  f = fabric.Image.filters;

  fabric.Image.fromURL('../lib/bg.png', function(img) {
    canvas.backgroundImage = img;
   canvas.backgroundImage.width = 400;
  canvas.backgroundImage.height = 400;
  });

  canvas.on({
   'object:selected': function() {
    fabric.util.toArray(document.getElementsByTagName('input'))
                       .forEach(function(el){ el.disabled = false; })

    var filters = ['brightness',];
 //         var filters = ['grayscale', 'invert', 'remove-white',  'sepia', 'sepia2',
 //                      'brightness', 'noise', 'gradient-transparency', 'pixelate',
 //                      'blur', 'sharpen', 'emboss', 'tint', 'multiply',   'blend'];

      for (var i = 0; i < filters.length; i++) {
         $(filters[i]).checked = !!canvas.getActiveObject().filters[i];
      }

      applyFilter(5, true   && new f.Brightness({
      brightness: parseInt($('brightness-value').value, 10)
    }));



    },
    'selection:cleared': function() {
      fabric.util.toArray(document.getElementsByTagName('input'))
                      .forEach(function(el){ el.disabled = true; })
    }
   });

   fabric.Image.fromURL('../upload/Chrysanthemum.jpg', function(img) {
    var oImg = img.set({ left: 50, top: 100, angle: 0 }).scale(0.9);
   canvas.add(oImg).renderAll();
   canvas.setActiveObject(oImg);
  });

 $('brightness').onclick = function () {
   applyFilter(5, this.checked && new f.Brightness({
    brightness: parseInt($('brightness-value').value, 10)
   }));
   };
    $('brightness-value').onchange = function() {
    applyFilterValue(5, 'brightness', parseInt(this.value, 10));
  };

 })();

Answer №1

As a developer, I created a custom HSL plugin last year that could be beneficial:

fabric.Image.filters.HSL = fabric.util.createClass(fabric.Image.filters.BaseFilter, {

    type: 'HSL',

    initialize: function(options) {
        options || (options = {});
        this.hue        = options.hue        || 0;
        this.saturation = options.saturation || 0;
        this.lightness  = options.lightness  || 0;
    },

    rgbToHsl: function(r, g, b) {
        r /= 255, g /= 255, b /= 255;
        var max = Math.max(r, g, b), min = Math.min(r, g, b);
        var h, s, l = (max + min) / 2;

        if (max == min) {
            h = s = 0;
        } else {
            var d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            switch (max) {
                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                case g: h = (b - r) / d + 2; break;
                case b: h = (r - g) / d + 4; break;
            }
            h /= 6;
        }

        return [h, s, l];
    },

    hslToRgb: function(h, s, l) {
        var r, g, b;

        if (s == 0) {
            r = g = b = l;
        } else {
            function hue2rgb(p, q, t){
                if (t < 0) t += 1;
                if (t > 1) t -= 1;
                if (t < 1/6) return p + (q - p) * 6 * t;
                if (t < 1/2) return q;
                if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
                return p;
            }

            var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
            var p = 2 * l - q;
            r = hue2rgb(p, q, h + 1/3);
            g = hue2rgb(p, q, h);
            b = hue2rgb(p, q, h - 1/3);
        }
        return [r * 255, g * 255, b * 255];
    },

    applyTo: function(canvasEl) {
        var context = canvasEl.getContext('2d'),
            imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
            data = imageData.data;

        for (var i=0; i<data.length; i+=4)
        {
            // Convert RGB to HSL
            var hsl = this.rgbToHsl(data[i], data[i+1], data[i+2]);

            // Apply HSL values
            if (this.hue       ) hsl[0] = this.hue;
            if (this.saturation) hsl[1] = this.saturation;
            if (this.lightness ) hsl[2] = this.lightness;

            // Convert HSL back to RGB
            var rgb = this.hslToRgb(hsl[0], hsl[1], hsl[2]);

            // Update data
            data[i]   = rgb[0];
            data[i+1] = rgb[1];
            data[i+2] = rgb[2];
        }

        context.putImageData(imageData, 0, 0);
    },

    toObject: function() {
        return extend(this.callSuper('toObject'), {
            hue: this.hue,
            saturation: this.saturation,
            lightness: this.lightness
        });
    }
});

After loading FabricJS, integrate the following code snippet to utilize the plugin:

var hue = 1;        // Range: 0 to 1
var brightness = 1; // Range: 0 to 1
var lightness = 1;  // Range: 0 to 1

var filterHSL = new img.filters.HSL({
    hue: hue,
    saturation: saturation,
    lightness: lightness
});

img.filters = [filterHSL];
img.applyFilters(canvas.renderAll.bind(canvas));

Ensure to replace canvas with your FabricJS canvas object when doing so.

Feel free to reach out for any assistance or queries.

Answer №2

The newest update of Fabricjs, version 1.6.6, now allows you to accomplish this task.

Two new filters, fabric.Image.filters.Contrast and fabric.Image.filters.Saturate, have been introduced in this release.

I have created a demonstration in a fiddle to guide you through the process (please remember to adjust the applyFilter() function to experiment with different filters):

DEMO

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to utilize a prepared statement in MySQL using NodeJS for inserting or updating data in a specific table?

Below is the code snippet I need assistance with: connection.query({ sql: 'CREATE TABLE ? ( `wage` FLOAT NOT NULL , `monday` FLOAT NOT NULL , `tuesday` FLOAT NOT NULL , `wednesday` FLOAT NOT NULL , `thursday` FLOAT NOT NULL , `friday`) ENGINE = InnoDB ...

Issues with Mega Menu functionality preventing items from being clickable and links from properly navigating

Recently, I encountered a strange issue related to the integration of a mega menu found at . Unfortunately, despite integrating the mega menu, the Category and sub category links seem unresponsive - they are not directing me to the desired links. I suspec ...

I am facing issues with my submit buttons as they are not functioning

Once I hit the submit buttons, there seems to be an issue with redirecting to another page. Could anyone assist in identifying the error within this code and why my buttons "typ1" and "cod" are not redirecting to the specified location? <?php inc ...

What is the best way to convert this JavaScript iteration function into jQuery?

I recently encountered an issue with my JavaScript function that returns a list of elements with the class ".youtube", loops through them, and calls another function. The JavaScript logic is flawless, but I wanted to convert it into jQuery for better reada ...

Populate vue-multiselect with links from the router

Is there a way to populate the vue-multiselect dropdown with <router-link> options? Typically, router links are defined declaratively in the <template>, but vue-multiselect relies on binding an array of options. Any suggestions on how to approa ...

What is the best way to obtain the attribute value when a user clicks on a child element?

Is there a way to retrieve the value of the data-custom attribute when the red square is clicked without having to add the same attribute to nested elements? This can become cumbersome if there are multiple levels of nesting. class Example extends React ...

modifying output of data when onchange event is triggered

I am struggling with creating an onchange event for my option box in which the users of a site are listed. I have two input boxes designated for wins and losses, but the output is not changing when I select a user from the list. What could be wrong with my ...

Ways to remove the initial row of inline-block divs

My webpage is filled with inline-block divs that are contained within a larger div like so: <div class="container"> <div class="text">Text 1</div> <div class="text">Text 2 ... rest of the nu ...

Show the nested div when hovering over the containing div using JavaScript

I have a situation where I have multiple divs within a parent div, all using the same class. Here is an example: <div class="deck-content"> <div class="deck-box">TEST< <div class="deck-hidden">< <span class= ...

SyntaxError: Identifier was not expected

I am currently working on a function that involves a table of rows with edit buttons. Whenever the edit button is clicked, the following function is called and I encounter this error: Uncaught SyntaxError: Unexpected identifier The error seems to be poin ...

What is the reason behind using AJAX to attempt sending a new URL request on

Having a strange issue with my product list. When trying to edit a product by clicking on it, I am redirected to the product form where an AJAX request is supposed to be sent to getFiltersGroup. However, on error, the AJAX request is somehow being sent to ...

Is there a way to determine the dimensions of a pdf file using javascript and capture a snapshot of it for showcasing on a website?

I'm fairly new to HTML/CSS and haven't delved into javascript yet, but I have a good understanding of reading other people's code. Currently, I'm putting together my portfolio website and would like to include my resume on the page in a ...

How is it possible that my form is able to save data into the database even without any

I am considering adding a captcha process to my form and I am brainstorming some logic for it. I downloaded a login from Google, but I am confused why my form is still storing data into the database using action=' ' instead of action="register.ph ...

What is the method for creating a new array of objects in Typescript with no initial elements?

After retrieving a collection of data documents, I am iterating through them to form an object named 'Item'; each Item comprises keys for 'amount' and 'id'. My goal is to add each created Item object to an array called ' ...

Unlocking the power of dynamic text using a single form

My comment reply system is experiencing an issue where the first reply works fine, but subsequent replies are unable to get the reply text value. How can I ensure that all replies work properly based on the Razor code provided below? <h4>Comments< ...

What are the steps for encoding a value using jquery serialize?

I attempted to encode all values using the following code: encodeURIComponent($("#customer_details").serialize()); Unfortunately, it did not produce the desired results. Is there a method to retrieve all elements on a form and individually encode each v ...

"Enhancing Efficiency with Tagging and Contextual Autocomplete

I have integrated into my project for tagging and autocompletion features. Currently, I am able to autocomplete a single term successfully: This is the console log: GET .../source.php?term=value01 This is the Javascript code snippet: $("#input-newsear ...

Is there a way to find out the ultimate destination of a shortened URL without actually opening the webpage?

I am trying to implement a feature where I can click on links within email messages and have the full link displayed in a separate pane using jQuery. However, I am facing some challenges with this implementation. My plan is to use AJAX to call a PHP scrip ...

Global variables in AngularJS that are asynchronous

My challenge lies in using AngularJS to create several global objects accessible by any controller within the application. One crucial object I require is a user object containing the user's ID and other essential properties retrieved from the databa ...

Halt hovering effect after a set duration using CSS or Vanilla JavaScript

Looking for a way to create a hover effect that lasts for a specific duration before stopping. I want the background to appear for just 1 second, even if the mouse remains hovering. Preferably using CSS or JavaScript only, without jQuery. To see my curren ...