mirror of
https://github.com/konvajs/konva.git
synced 2025-11-24 16:53:06 +08:00
Rewrite Emboss and Solarize filters for improved performance and usability and better license handling. close #1375
This commit is contained in:
@@ -1,12 +1,8 @@
|
||||
import { Factory } from '../Factory';
|
||||
import { Node, Filter } from '../Node';
|
||||
import { Util } from '../Util';
|
||||
import { getNumberValidator } from '../Validators';
|
||||
/**
|
||||
* Emboss Filter.
|
||||
* Pixastic Lib - Emboss filter - v0.1.0
|
||||
* Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
|
||||
* License: [http://www.pixastic.com/lib/license.txt]
|
||||
* @function
|
||||
* @memberof Konva.Filters
|
||||
* @param {Object} imageData
|
||||
@@ -19,125 +15,133 @@ import { getNumberValidator } from '../Validators';
|
||||
* node.embossBlend(true);
|
||||
*/
|
||||
export const Emboss: Filter = function (imageData) {
|
||||
// pixastic strength is between 0 and 10. I want it between 0 and 1
|
||||
// pixastic greyLevel is between 0 and 255. I want it between 0 and 1. Also,
|
||||
// a max value of greyLevel yields a white emboss, and the min value yields a black
|
||||
// emboss. Therefore, I changed greyLevel to whiteLevel
|
||||
const strength = this.embossStrength() * 10,
|
||||
greyLevel = this.embossWhiteLevel() * 255,
|
||||
direction = this.embossDirection(),
|
||||
blend = this.embossBlend(),
|
||||
data = imageData.data,
|
||||
w = imageData.width,
|
||||
h = imageData.height,
|
||||
w4 = w * 4;
|
||||
let dirY = 0,
|
||||
dirX = 0,
|
||||
y = h;
|
||||
const data = imageData.data;
|
||||
const w = imageData.width;
|
||||
const h = imageData.height;
|
||||
|
||||
switch (direction) {
|
||||
case 'top-left':
|
||||
dirY = -1;
|
||||
dirX = -1;
|
||||
break;
|
||||
case 'top':
|
||||
dirY = -1;
|
||||
dirX = 0;
|
||||
break;
|
||||
case 'top-right':
|
||||
dirY = -1;
|
||||
dirX = 1;
|
||||
break;
|
||||
case 'right':
|
||||
dirY = 0;
|
||||
dirX = 1;
|
||||
break;
|
||||
case 'bottom-right':
|
||||
dirY = 1;
|
||||
dirX = 1;
|
||||
break;
|
||||
case 'bottom':
|
||||
dirY = 1;
|
||||
dirX = 0;
|
||||
break;
|
||||
case 'bottom-left':
|
||||
dirY = 1;
|
||||
dirX = -1;
|
||||
break;
|
||||
case 'left':
|
||||
dirY = 0;
|
||||
dirX = -1;
|
||||
break;
|
||||
default:
|
||||
Util.error('Unknown emboss direction: ' + direction);
|
||||
// Inputs from Konva node
|
||||
const strength01 = Math.min(1, Math.max(0, this.embossStrength?.() ?? 0.5)); // [0..1]
|
||||
const whiteLevel01 = Math.min(
|
||||
1,
|
||||
Math.max(0, this.embossWhiteLevel?.() ?? 0.5)
|
||||
); // [0..1]
|
||||
// Convert string direction to degrees
|
||||
const directionMap = {
|
||||
'top-left': 315,
|
||||
top: 270,
|
||||
'top-right': 225,
|
||||
right: 180,
|
||||
'bottom-right': 135,
|
||||
bottom: 90,
|
||||
'bottom-left': 45,
|
||||
left: 0,
|
||||
};
|
||||
const directionDeg =
|
||||
directionMap[this.embossDirection?.() ?? 'top-left'] ?? 315; // degrees
|
||||
const blend = !!(this.embossBlend?.() ?? false);
|
||||
|
||||
// Internal mapping:
|
||||
// - "strength" was 0..10; we honor your 0..1 API and scale accordingly.
|
||||
// - Sobel directional response is roughly in [-1020..1020] for 8-bit luminance; scale to ~±128.
|
||||
const strength = strength01 * 10;
|
||||
const bias = whiteLevel01 * 255;
|
||||
const dirRad = (directionDeg * Math.PI) / 180;
|
||||
const cx = Math.cos(dirRad);
|
||||
const cy = Math.sin(dirRad);
|
||||
const SCALE = (128 / 1020) * strength; // ≈0.1255 * strength
|
||||
|
||||
// Precompute luminance (Rec.709)
|
||||
const src = new Uint8ClampedArray(data); // snapshot
|
||||
const lum = new Float32Array(w * h);
|
||||
for (let p = 0, i = 0; i < data.length; i += 4, p++) {
|
||||
lum[p] = 0.2126 * src[i] + 0.7152 * src[i + 1] + 0.0722 * src[i + 2];
|
||||
}
|
||||
|
||||
do {
|
||||
const offsetY = (y - 1) * w4;
|
||||
// Sobel kernels (flattened)
|
||||
const Gx = [-1, 0, 1, -2, 0, 2, -1, 0, 1];
|
||||
const Gy = [-1, -2, -1, 0, 0, 0, 1, 2, 1];
|
||||
|
||||
let otherY = dirY;
|
||||
if (y + otherY < 1) {
|
||||
otherY = 0;
|
||||
}
|
||||
if (y + otherY > h) {
|
||||
otherY = 0;
|
||||
}
|
||||
// neighbor offsets around center pixel in lum space
|
||||
const OFF = [-w - 1, -w, -w + 1, -1, 0, 1, w - 1, w, w + 1];
|
||||
|
||||
const offsetYOther = (y - 1 + otherY) * w * 4;
|
||||
// Helpers
|
||||
const clamp8 = (v) => (v < 0 ? 0 : v > 255 ? 255 : v);
|
||||
|
||||
let x = w;
|
||||
do {
|
||||
const offset = offsetY + (x - 1) * 4;
|
||||
// Process: leave a 1px border unchanged (faster/cleaner)
|
||||
for (let y = 1; y < h - 1; y++) {
|
||||
for (let x = 1; x < w - 1; x++) {
|
||||
const p = y * w + x;
|
||||
|
||||
let otherX = dirX;
|
||||
if (x + otherX < 1) {
|
||||
otherX = 0;
|
||||
}
|
||||
if (x + otherX > w) {
|
||||
otherX = 0;
|
||||
}
|
||||
// Directional derivative = (cosθ * Gx + sinθ * Gy) • neighborhood(lum)
|
||||
let sx = 0,
|
||||
sy = 0;
|
||||
// unroll loop for speed
|
||||
sx += lum[p + OFF[0]] * Gx[0];
|
||||
sy += lum[p + OFF[0]] * Gy[0];
|
||||
sx += lum[p + OFF[1]] * Gx[1];
|
||||
sy += lum[p + OFF[1]] * Gy[1];
|
||||
sx += lum[p + OFF[2]] * Gx[2];
|
||||
sy += lum[p + OFF[2]] * Gy[2];
|
||||
sx += lum[p + OFF[3]] * Gx[3];
|
||||
sy += lum[p + OFF[3]] * Gy[3];
|
||||
// center has 0 weights in both Sobel masks; can skip if desired
|
||||
sx += lum[p + OFF[5]] * Gx[5];
|
||||
sy += lum[p + OFF[5]] * Gy[5];
|
||||
sx += lum[p + OFF[6]] * Gx[6];
|
||||
sy += lum[p + OFF[6]] * Gy[6];
|
||||
sx += lum[p + OFF[7]] * Gx[7];
|
||||
sy += lum[p + OFF[7]] * Gy[7];
|
||||
sx += lum[p + OFF[8]] * Gx[8];
|
||||
sy += lum[p + OFF[8]] * Gy[8];
|
||||
|
||||
const offsetOther = offsetYOther + (x - 1 + otherX) * 4;
|
||||
|
||||
const dR = data[offset] - data[offsetOther];
|
||||
const dG = data[offset + 1] - data[offsetOther + 1];
|
||||
const dB = data[offset + 2] - data[offsetOther + 2];
|
||||
|
||||
let dif = dR;
|
||||
const absDif = dif > 0 ? dif : -dif;
|
||||
|
||||
const absG = dG > 0 ? dG : -dG;
|
||||
const absB = dB > 0 ? dB : -dB;
|
||||
|
||||
if (absG > absDif) {
|
||||
dif = dG;
|
||||
}
|
||||
if (absB > absDif) {
|
||||
dif = dB;
|
||||
}
|
||||
|
||||
dif *= strength;
|
||||
const r = cx * sx + cy * sy; // directional response
|
||||
const outGray = clamp8(bias + r * SCALE); // biased, scaled, clamped
|
||||
|
||||
const o = p * 4;
|
||||
if (blend) {
|
||||
const r = data[offset] + dif;
|
||||
const g = data[offset + 1] + dif;
|
||||
const b = data[offset + 2] + dif;
|
||||
|
||||
data[offset] = r > 255 ? 255 : r < 0 ? 0 : r;
|
||||
data[offset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
|
||||
data[offset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
|
||||
// Add the emboss "relief" around chosen bias to original RGB
|
||||
const delta = outGray - bias; // symmetric around whiteLevel
|
||||
data[o] = clamp8(src[o] + delta);
|
||||
data[o + 1] = clamp8(src[o + 1] + delta);
|
||||
data[o + 2] = clamp8(src[o + 2] + delta);
|
||||
data[o + 3] = src[o + 3];
|
||||
} else {
|
||||
let grey = greyLevel - dif;
|
||||
if (grey < 0) {
|
||||
grey = 0;
|
||||
} else if (grey > 255) {
|
||||
grey = 255;
|
||||
// Grayscale embossed output
|
||||
data[o] = data[o + 1] = data[o + 2] = outGray;
|
||||
data[o + 3] = src[o + 3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data[offset] = data[offset + 1] = data[offset + 2] = grey;
|
||||
// Copy border (untouched) to keep edges clean
|
||||
// top & bottom rows
|
||||
for (let x = 0; x < w; x++) {
|
||||
let oTop = x * 4,
|
||||
oBot = ((h - 1) * w + x) * 4;
|
||||
data[oTop] = src[oTop];
|
||||
data[oTop + 1] = src[oTop + 1];
|
||||
data[oTop + 2] = src[oTop + 2];
|
||||
data[oTop + 3] = src[oTop + 3];
|
||||
data[oBot] = src[oBot];
|
||||
data[oBot + 1] = src[oBot + 1];
|
||||
data[oBot + 2] = src[oBot + 2];
|
||||
data[oBot + 3] = src[oBot + 3];
|
||||
}
|
||||
} while (--x);
|
||||
} while (--y);
|
||||
// left & right columns
|
||||
for (let y = 1; y < h - 1; y++) {
|
||||
let oL = y * w * 4,
|
||||
oR = (y * w + (w - 1)) * 4;
|
||||
data[oL] = src[oL];
|
||||
data[oL + 1] = src[oL + 1];
|
||||
data[oL + 2] = src[oL + 2];
|
||||
data[oL + 3] = src[oL + 3];
|
||||
data[oR] = src[oR];
|
||||
data[oR + 1] = src[oR + 1];
|
||||
data[oR + 2] = src[oR + 2];
|
||||
data[oR + 3] = src[oR + 3];
|
||||
}
|
||||
|
||||
return imageData;
|
||||
};
|
||||
|
||||
Factory.addGetterSetter(
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { Filter } from '../Node';
|
||||
/**
|
||||
* Solarize Filter
|
||||
* Pixastic Lib - Solarize filter - v0.1.0
|
||||
* Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
|
||||
* License: [http://www.pixastic.com/lib/license.txt]
|
||||
* @function
|
||||
* @name Solarize
|
||||
* @memberof Konva.Filters
|
||||
@@ -14,35 +11,19 @@ import { Filter } from '../Node';
|
||||
*/
|
||||
|
||||
export const Solarize: Filter = function (imageData) {
|
||||
const data = imageData.data,
|
||||
w = imageData.width,
|
||||
h = imageData.height,
|
||||
w4 = w * 4;
|
||||
|
||||
let y = h;
|
||||
|
||||
do {
|
||||
const offsetY = (y - 1) * w4;
|
||||
let x = w;
|
||||
do {
|
||||
const offset = offsetY + (x - 1) * 4;
|
||||
let r = data[offset];
|
||||
let g = data[offset + 1];
|
||||
let b = data[offset + 2];
|
||||
|
||||
if (r > 127) {
|
||||
r = 255 - r;
|
||||
const threshold = 128;
|
||||
const d = imageData.data;
|
||||
for (let i = 0; i < d.length; i += 4) {
|
||||
const r = d[i],
|
||||
g = d[i + 1],
|
||||
b = d[i + 2];
|
||||
// sRGB luma
|
||||
const L = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||
if (L >= threshold) {
|
||||
d[i] = 255 - r;
|
||||
d[i + 1] = 255 - g;
|
||||
d[i + 2] = 255 - b;
|
||||
}
|
||||
if (g > 127) {
|
||||
g = 255 - g;
|
||||
}
|
||||
if (b > 127) {
|
||||
b = 255 - b;
|
||||
}
|
||||
|
||||
data[offset] = r;
|
||||
data[offset + 1] = g;
|
||||
data[offset + 2] = b;
|
||||
} while (--x);
|
||||
} while (--y);
|
||||
return imageData;
|
||||
};
|
||||
|
||||
@@ -236,9 +236,24 @@
|
||||
|
||||
<!-- Default Solarize Controls -->
|
||||
<div id="solarize-controls-default" style="display: none">
|
||||
<p style="color: #666; margin: 0; font-size: 12px">
|
||||
No parameters for default Solarize filter
|
||||
</p>
|
||||
<div class="control-group">
|
||||
<label for="solarize-threshold-default"
|
||||
>Threshold:
|
||||
<span
|
||||
id="solarize-threshold-value-default"
|
||||
class="value-display"
|
||||
>127</span
|
||||
></label
|
||||
>
|
||||
<input
|
||||
type="range"
|
||||
id="solarize-threshold-default"
|
||||
min="0"
|
||||
max="255"
|
||||
value="127"
|
||||
step="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -332,34 +347,137 @@
|
||||
return imageData;
|
||||
}
|
||||
|
||||
function embossImageData(imageData, strength = 1) {
|
||||
const { data, width, height } = imageData;
|
||||
function embossImageData(imageData) {
|
||||
const data = imageData.data;
|
||||
const w = imageData.width;
|
||||
const h = imageData.height;
|
||||
|
||||
debugger;
|
||||
// Inputs from Konva node
|
||||
const strength01 = Math.min(
|
||||
1,
|
||||
Math.max(0, this.embossStrength?.() ?? 0.5)
|
||||
); // [0..1]
|
||||
const whiteLevel01 = Math.min(
|
||||
1,
|
||||
Math.max(0, this.embossWhiteLevel?.() ?? 0.5)
|
||||
); // [0..1]
|
||||
// Convert string direction to degrees
|
||||
const directionMap = {
|
||||
'top-left': 315,
|
||||
top: 270,
|
||||
'top-right': 225,
|
||||
right: 180,
|
||||
'bottom-right': 135,
|
||||
bottom: 90,
|
||||
'bottom-left': 45,
|
||||
left: 0,
|
||||
};
|
||||
const directionDeg =
|
||||
directionMap[this.embossDirection?.() ?? 'top-left'] ?? 315; // degrees
|
||||
const blend = !!(this.embossBlend?.() ?? false);
|
||||
|
||||
// Internal mapping:
|
||||
// - Pixastic "strength" was 0..10; we honor your 0..1 API and scale accordingly.
|
||||
// - Sobel directional response is roughly in [-1020..1020] for 8-bit luminance; scale to ~±128.
|
||||
const strength = strength01 * 10;
|
||||
const bias = whiteLevel01 * 255;
|
||||
const dirRad = (directionDeg * Math.PI) / 180;
|
||||
const cx = Math.cos(dirRad);
|
||||
const cy = Math.sin(dirRad);
|
||||
const SCALE = (128 / 1020) * strength; // ≈0.1255 * strength
|
||||
|
||||
// Precompute luminance (Rec.709)
|
||||
const src = new Uint8ClampedArray(data); // snapshot
|
||||
const k = [-2, -1, 0, -1, 1, 1, 0, 1, 2]; // sum = 1
|
||||
const lum = new Float32Array(w * h);
|
||||
for (let p = 0, i = 0; i < data.length; i += 4, p++) {
|
||||
lum[p] = 0.2126 * src[i] + 0.7152 * src[i + 1] + 0.0722 * src[i + 2];
|
||||
}
|
||||
|
||||
const clamp = (v) => (v < 0 ? 0 : v > 255 ? 255 : v);
|
||||
// Sobel kernels (flattened)
|
||||
const Gx = [-1, 0, 1, -2, 0, 2, -1, 0, 1];
|
||||
const Gy = [-1, -2, -1, 0, 0, 0, 1, 2, 1];
|
||||
|
||||
// leave a 1px border unchanged for simplicity
|
||||
for (let y = 1; y < height - 1; y++) {
|
||||
for (let x = 1; x < width - 1; x++) {
|
||||
let acc = 0;
|
||||
// grayscale luminance convolution for the emboss look
|
||||
for (let ky = -1; ky <= 1; ky++) {
|
||||
for (let kx = -1; kx <= 1; kx++) {
|
||||
const idx = ((y + ky) * width + (x + kx)) * 4;
|
||||
const lum =
|
||||
0.2126 * src[idx] +
|
||||
0.7152 * src[idx + 1] +
|
||||
0.0722 * src[idx + 2];
|
||||
acc += lum * k[(ky + 1) * 3 + (kx + 1)];
|
||||
// neighbor offsets around center pixel in lum space
|
||||
const OFF = [-w - 1, -w, -w + 1, -1, 0, 1, w - 1, w, w + 1];
|
||||
|
||||
// Helpers
|
||||
const clamp8 = (v) => (v < 0 ? 0 : v > 255 ? 255 : v);
|
||||
|
||||
// Process: leave a 1px border unchanged (faster/cleaner)
|
||||
for (let y = 1; y < h - 1; y++) {
|
||||
for (let x = 1; x < w - 1; x++) {
|
||||
const p = y * w + x;
|
||||
|
||||
// Directional derivative = (cosθ * Gx + sinθ * Gy) • neighborhood(lum)
|
||||
let sx = 0,
|
||||
sy = 0;
|
||||
// unroll loop for speed
|
||||
sx += lum[p + OFF[0]] * Gx[0];
|
||||
sy += lum[p + OFF[0]] * Gy[0];
|
||||
sx += lum[p + OFF[1]] * Gx[1];
|
||||
sy += lum[p + OFF[1]] * Gy[1];
|
||||
sx += lum[p + OFF[2]] * Gx[2];
|
||||
sy += lum[p + OFF[2]] * Gy[2];
|
||||
sx += lum[p + OFF[3]] * Gx[3];
|
||||
sy += lum[p + OFF[3]] * Gy[3];
|
||||
// center has 0 weights in both Sobel masks; can skip if desired
|
||||
sx += lum[p + OFF[5]] * Gx[5];
|
||||
sy += lum[p + OFF[5]] * Gy[5];
|
||||
sx += lum[p + OFF[6]] * Gx[6];
|
||||
sy += lum[p + OFF[6]] * Gy[6];
|
||||
sx += lum[p + OFF[7]] * Gx[7];
|
||||
sy += lum[p + OFF[7]] * Gy[7];
|
||||
sx += lum[p + OFF[8]] * Gx[8];
|
||||
sy += lum[p + OFF[8]] * Gy[8];
|
||||
|
||||
const r = cx * sx + cy * sy; // directional response
|
||||
const outGray = clamp8(bias + r * SCALE); // biased, scaled, clamped
|
||||
|
||||
const o = p * 4;
|
||||
if (blend) {
|
||||
// Add the emboss "relief" around chosen bias to original RGB
|
||||
const delta = outGray - bias; // symmetric around whiteLevel
|
||||
data[o] = clamp8(src[o] + delta);
|
||||
data[o + 1] = clamp8(src[o + 1] + delta);
|
||||
data[o + 2] = clamp8(src[o + 2] + delta);
|
||||
data[o + 3] = src[o + 3];
|
||||
} else {
|
||||
// Grayscale embossed output
|
||||
data[o] = data[o + 1] = data[o + 2] = outGray;
|
||||
data[o + 3] = src[o + 3];
|
||||
}
|
||||
}
|
||||
const out = clamp(acc * strength + 128); // bias to mid-gray
|
||||
const o = (y * width + x) * 4;
|
||||
data[o] = data[o + 1] = data[o + 2] = out;
|
||||
data[o + 3] = src[o + 3]; // keep alpha
|
||||
}
|
||||
|
||||
// Copy border (untouched) to keep edges clean
|
||||
// top & bottom rows
|
||||
for (let x = 0; x < w; x++) {
|
||||
let oTop = x * 4,
|
||||
oBot = ((h - 1) * w + x) * 4;
|
||||
data[oTop] = src[oTop];
|
||||
data[oTop + 1] = src[oTop + 1];
|
||||
data[oTop + 2] = src[oTop + 2];
|
||||
data[oTop + 3] = src[oTop + 3];
|
||||
data[oBot] = src[oBot];
|
||||
data[oBot + 1] = src[oBot + 1];
|
||||
data[oBot + 2] = src[oBot + 2];
|
||||
data[oBot + 3] = src[oBot + 3];
|
||||
}
|
||||
// left & right columns
|
||||
for (let y = 1; y < h - 1; y++) {
|
||||
let oL = y * w * 4,
|
||||
oR = (y * w + (w - 1)) * 4;
|
||||
data[oL] = src[oL];
|
||||
data[oL + 1] = src[oL + 1];
|
||||
data[oL + 2] = src[oL + 2];
|
||||
data[oL + 3] = src[oL + 3];
|
||||
data[oR] = src[oR];
|
||||
data[oR + 1] = src[oR + 1];
|
||||
data[oR + 2] = src[oR + 2];
|
||||
data[oR + 3] = src[oR + 3];
|
||||
}
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
||||
@@ -421,15 +539,19 @@
|
||||
draggable: true,
|
||||
});
|
||||
customImage.cache({ pixelRatio: 2 });
|
||||
customImage.filters([
|
||||
(imageData) =>
|
||||
embossImageData(
|
||||
imageData,
|
||||
parseFloat(
|
||||
document.getElementById('emboss-strength-custom').value
|
||||
)
|
||||
),
|
||||
]);
|
||||
customImage.embossStrength(
|
||||
parseFloat(document.getElementById('emboss-strength-default').value)
|
||||
);
|
||||
customImage.embossWhiteLevel(
|
||||
parseFloat(document.getElementById('emboss-white-default').value)
|
||||
);
|
||||
customImage.embossDirection(
|
||||
document.getElementById('emboss-direction-default').value
|
||||
);
|
||||
customImage.embossBlend(
|
||||
document.getElementById('emboss-blend-default').checked
|
||||
);
|
||||
customImage.filters([embossImageData]);
|
||||
customLayer.add(customImage);
|
||||
customLayer.draw();
|
||||
|
||||
@@ -458,22 +580,32 @@
|
||||
document.getElementById('emboss-blend-default').checked
|
||||
);
|
||||
} else {
|
||||
// Use custom solarize function for default filter to add threshold control
|
||||
defaultImage.filters([Konva.Filters.Solarize]);
|
||||
}
|
||||
defaultLayer.batchDraw();
|
||||
updateCustomFilter();
|
||||
}
|
||||
|
||||
function updateCustomFilter() {
|
||||
console.log(currentCustomFilter);
|
||||
if (currentCustomFilter === 'emboss') {
|
||||
customImage.filters([
|
||||
(imageData) =>
|
||||
embossImageData(
|
||||
imageData,
|
||||
customImage.embossStrength(
|
||||
parseFloat(
|
||||
document.getElementById('emboss-strength-custom').value
|
||||
document.getElementById('emboss-strength-default').value
|
||||
)
|
||||
),
|
||||
]);
|
||||
);
|
||||
customImage.embossWhiteLevel(
|
||||
parseFloat(document.getElementById('emboss-white-default').value)
|
||||
);
|
||||
customImage.embossDirection(
|
||||
document.getElementById('emboss-direction-default').value
|
||||
);
|
||||
customImage.embossBlend(
|
||||
document.getElementById('emboss-blend-default').checked
|
||||
);
|
||||
|
||||
customImage.filters([embossImageData]);
|
||||
} else {
|
||||
customImage.filters([
|
||||
(imageData) =>
|
||||
@@ -502,6 +634,7 @@
|
||||
document.getElementById('solarize-controls-default').style.display =
|
||||
'none';
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter();
|
||||
});
|
||||
|
||||
document
|
||||
@@ -517,6 +650,7 @@
|
||||
document.getElementById('emboss-controls-default').style.display =
|
||||
'none';
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter();
|
||||
});
|
||||
|
||||
// Custom filter button controls
|
||||
@@ -556,6 +690,7 @@
|
||||
'emboss-strength-value-default'
|
||||
).textContent = e.target.value;
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter;
|
||||
});
|
||||
|
||||
document
|
||||
@@ -564,14 +699,32 @@
|
||||
document.getElementById('emboss-white-value-default').textContent =
|
||||
e.target.value;
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter;
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById('emboss-direction-default')
|
||||
.addEventListener('change', updateDefaultFilter);
|
||||
.addEventListener('change', () => {
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter();
|
||||
});
|
||||
document
|
||||
.getElementById('emboss-blend-default')
|
||||
.addEventListener('change', updateDefaultFilter);
|
||||
.addEventListener('change', () => {
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter();
|
||||
});
|
||||
|
||||
// Default solarize controls
|
||||
document
|
||||
.getElementById('solarize-threshold-default')
|
||||
.addEventListener('input', (e) => {
|
||||
document.getElementById(
|
||||
'solarize-threshold-value-default'
|
||||
).textContent = e.target.value;
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter();
|
||||
});
|
||||
|
||||
// Custom filter controls
|
||||
document
|
||||
|
||||
Reference in New Issue
Block a user