HTML5 Canvas Hue, Saturation and Luminance filter Image Tutorial
To apply filter to an Konva.Node
, we have to cache it first with cache()
function. Then apply filter with filters()
function.
To change hue, saturation and luminance components of an image with Konva, we can use the Konva.Filters.HSL
.
Instructions: Slide the controls to change HSL values.
For all available filters go to Filters Documentation.
- Vanilla
- React
- Vue
import Konva from 'konva'; const stage = new Konva.Stage({ container: 'container', width: window.innerWidth, height: window.innerHeight, }); const layer = new Konva.Layer(); stage.add(layer); const imageObj = new Image(); imageObj.onload = () => { const image = new Konva.Image({ x: 50, y: 50, image: imageObj, draggable: true, }); layer.add(image); image.cache(); image.filters([Konva.Filters.HSL]); // create sliders const createSlider = (label, min, max, defaultValue, property) => { const container = document.createElement('div'); container.style.position = 'absolute'; container.style.left = '20px'; const text = document.createElement('span'); text.textContent = `${label}: `; container.appendChild(text); const slider = document.createElement('input'); slider.type = 'range'; slider.min = min; slider.max = max; slider.step = '0.1'; slider.value = defaultValue; slider.style.width = '200px'; slider.addEventListener('input', (e) => { const value = parseFloat(e.target.value); image[property](value); layer.batchDraw(); }); container.appendChild(slider); return container; }; const hueSlider = createSlider('Hue', -180, 180, 0, 'hue'); hueSlider.style.top = '20px'; document.body.appendChild(hueSlider); const saturationSlider = createSlider('Saturation', -2, 10, 0, 'saturation'); saturationSlider.style.top = '45px'; document.body.appendChild(saturationSlider); const luminanceSlider = createSlider('Luminance', -2, 2, 0, 'luminance'); luminanceSlider.style.top = '70px'; document.body.appendChild(luminanceSlider); }; imageObj.src = 'https://new.konvajs.org/assets/lion.png'; imageObj.crossOrigin = 'anonymous';
import { Stage, Layer, Image } from 'react-konva'; import { useState, useEffect, useRef } from 'react'; import useImage from 'use-image'; const App = () => { const [hue, setHue] = useState(0); const [saturation, setSaturation] = useState(0); const [luminance, setLuminance] = useState(0); const [image] = useImage('https://new.konvajs.org/assets/lion.png', 'anonymous'); const imageRef = useRef(null); useEffect(() => { if (image) { imageRef.current.cache(); } }, [image]); const SliderControl = ({ label, value, onChange, min, max }) => ( <div style={{ margin: '10px' }}> <label>{label}: </label> <input type="range" min={min} max={max} step="0.1" value={value} onChange={(e) => onChange(parseFloat(e.target.value))} style={{ width: '200px' }} /> </div> ); return ( <> <Stage width={window.innerWidth} height={window.innerHeight}> <Layer> <Image ref={imageRef} x={50} y={50} image={image} draggable filters={[Konva.Filters.HSL]} hue={hue} saturation={saturation} luminance={luminance} /> </Layer> </Stage> <div style={{ position: 'absolute', top: '20px', left: '20px' }}> <SliderControl label="Hue" value={hue} onChange={setHue} min={-180} max={180} /> <SliderControl label="Saturation" value={saturation} onChange={setSaturation} min={-2} max={10} /> <SliderControl label="Luminance" value={luminance} onChange={setLuminance} min={-2} max={2} /> </div> </> ); }; export default App;
<template> <div> <v-stage :config="stageSize"> <v-layer> <v-image ref="imageNode" :config="{ x: 50, y: 50, image: image, draggable: true, filters: [Konva.Filters.HSL], hue: hslValues.hue, saturation: hslValues.saturation, luminance: hslValues.luminance, }" /> </v-layer> </v-stage> <div style="position: absolute; top: 20px; left: 20px"> <div v-for="control in controls" :key="control.label" style="margin: 10px"> <label>{{ control.label }}: </label> <input type="range" :min="control.min" :max="control.max" step="0.1" :value="control.value" @input="(e) => updateValue(control.prop, parseFloat(e.target.value))" style="width: 200px" /> </div> </div> </div> </template> <script setup> import { ref, computed, watch, nextTick } from 'vue'; import { useImage } from 'vue-konva'; import Konva from 'konva'; const stageSize = { width: window.innerWidth, height: window.innerHeight, }; const imageNode = ref(null); const [image] = useImage('https://new.konvajs.org/assets/lion.png', 'anonymous'); const hslValues = ref({ hue: 0, saturation: 0, luminance: 0, }); const controls = computed(() => [ { label: 'Hue', prop: 'hue', min: -180, max: 180, value: hslValues.value.hue }, { label: 'Saturation', prop: 'saturation', min: -2, max: 10, value: hslValues.value.saturation }, { label: 'Luminance', prop: 'luminance', min: -2, max: 2, value: hslValues.value.luminance }, ]); const updateValue = (prop, value) => { hslValues.value[prop] = value; }; watch(image, async (newImage) => { if (newImage) { await nextTick(); imageNode.value.getNode().cache(); } }); </script>