apexify.js 4.9.25 → 4.9.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +358 -47
- package/dist/cjs/Canvas/ApexPainter.d.ts +189 -0
- package/dist/cjs/Canvas/ApexPainter.d.ts.map +1 -0
- package/dist/{esm/canvas → cjs/Canvas}/ApexPainter.js +461 -352
- package/dist/cjs/Canvas/ApexPainter.js.map +1 -0
- package/dist/cjs/Canvas/utils/Background/bg.d.ts +43 -0
- package/dist/cjs/Canvas/utils/Background/bg.d.ts.map +1 -0
- package/dist/cjs/Canvas/utils/Background/bg.js +228 -0
- package/dist/cjs/Canvas/utils/Background/bg.js.map +1 -0
- package/dist/cjs/{canvas → Canvas}/utils/Charts/charts.d.ts.map +1 -1
- package/dist/{esm/canvas → cjs/Canvas}/utils/Charts/charts.js.map +1 -1
- package/dist/cjs/{canvas → Canvas}/utils/Custom/customLines.d.ts.map +1 -1
- package/dist/{esm/canvas → cjs/Canvas}/utils/Custom/customLines.js +2 -2
- package/dist/cjs/Canvas/utils/Custom/customLines.js.map +1 -0
- package/dist/cjs/{canvas → Canvas}/utils/General/conversion.d.ts.map +1 -1
- package/dist/cjs/{canvas → Canvas}/utils/General/conversion.js.map +1 -1
- package/dist/cjs/{canvas → Canvas}/utils/General/general functions.d.ts.map +1 -1
- package/dist/{esm/canvas → cjs/Canvas}/utils/General/general functions.js.map +1 -1
- package/dist/cjs/Canvas/utils/Image/imageFilters.d.ts +11 -0
- package/dist/cjs/Canvas/utils/Image/imageFilters.d.ts.map +1 -0
- package/dist/cjs/Canvas/utils/Image/imageFilters.js +307 -0
- package/dist/cjs/Canvas/utils/Image/imageFilters.js.map +1 -0
- package/dist/cjs/Canvas/utils/Image/imageProperties.d.ts +50 -0
- package/dist/cjs/Canvas/utils/Image/imageProperties.d.ts.map +1 -0
- package/dist/cjs/Canvas/utils/Image/imageProperties.js +271 -0
- package/dist/cjs/Canvas/utils/Image/imageProperties.js.map +1 -0
- package/dist/cjs/Canvas/utils/Image/professionalImageFilters.d.ts +11 -0
- package/dist/cjs/Canvas/utils/Image/professionalImageFilters.d.ts.map +1 -0
- package/dist/cjs/Canvas/utils/Image/professionalImageFilters.js +351 -0
- package/dist/cjs/Canvas/utils/Image/professionalImageFilters.js.map +1 -0
- package/dist/cjs/Canvas/utils/Image/simpleProfessionalFilters.d.ts +11 -0
- package/dist/cjs/Canvas/utils/Image/simpleProfessionalFilters.d.ts.map +1 -0
- package/dist/cjs/Canvas/utils/Image/simpleProfessionalFilters.js +215 -0
- package/dist/cjs/Canvas/utils/Image/simpleProfessionalFilters.js.map +1 -0
- package/dist/cjs/Canvas/utils/Patterns/enhancedPatternRenderer.d.ts +71 -0
- package/dist/cjs/Canvas/utils/Patterns/enhancedPatternRenderer.d.ts.map +1 -0
- package/dist/cjs/Canvas/utils/Patterns/enhancedPatternRenderer.js +392 -0
- package/dist/cjs/Canvas/utils/Patterns/enhancedPatternRenderer.js.map +1 -0
- package/dist/cjs/Canvas/utils/Shapes/shapes.d.ts +29 -0
- package/dist/cjs/Canvas/utils/Shapes/shapes.d.ts.map +1 -0
- package/dist/cjs/Canvas/utils/Shapes/shapes.js +334 -0
- package/dist/cjs/Canvas/utils/Shapes/shapes.js.map +1 -0
- package/dist/cjs/Canvas/utils/Texts/enhancedTextRenderer.d.ts +127 -0
- package/dist/cjs/Canvas/utils/Texts/enhancedTextRenderer.d.ts.map +1 -0
- package/dist/cjs/Canvas/utils/Texts/enhancedTextRenderer.js +365 -0
- package/dist/cjs/Canvas/utils/Texts/enhancedTextRenderer.js.map +1 -0
- package/dist/cjs/{canvas → Canvas}/utils/Texts/textProperties.d.ts.map +1 -1
- package/dist/{esm/canvas → cjs/Canvas}/utils/Texts/textProperties.js.map +1 -1
- package/dist/{esm/canvas → cjs/Canvas}/utils/types.d.ts +227 -131
- package/dist/cjs/Canvas/utils/types.d.ts.map +1 -0
- package/dist/cjs/{canvas → Canvas}/utils/types.js +0 -1
- package/dist/cjs/Canvas/utils/types.js.map +1 -0
- package/dist/cjs/Canvas/utils/utils.d.ts +22 -0
- package/dist/cjs/Canvas/utils/utils.d.ts.map +1 -0
- package/dist/{esm/canvas → cjs/Canvas}/utils/utils.js +17 -7
- package/dist/cjs/Canvas/utils/utils.js.map +1 -0
- package/dist/cjs/index.d.ts +6 -3
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +8 -6
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/cjs/utils.d.ts +1 -1
- package/dist/cjs/utils.js +1 -1
- package/dist/esm/Canvas/ApexPainter.d.ts +189 -0
- package/dist/esm/Canvas/ApexPainter.d.ts.map +1 -0
- package/dist/{cjs/canvas → esm/Canvas}/ApexPainter.js +461 -352
- package/dist/esm/Canvas/ApexPainter.js.map +1 -0
- package/dist/esm/Canvas/utils/Background/bg.d.ts +43 -0
- package/dist/esm/Canvas/utils/Background/bg.d.ts.map +1 -0
- package/dist/esm/Canvas/utils/Background/bg.js +228 -0
- package/dist/esm/Canvas/utils/Background/bg.js.map +1 -0
- package/dist/esm/{canvas → Canvas}/utils/Charts/charts.d.ts.map +1 -1
- package/dist/{cjs/canvas → esm/Canvas}/utils/Charts/charts.js.map +1 -1
- package/dist/esm/{canvas → Canvas}/utils/Custom/customLines.d.ts.map +1 -1
- package/dist/{cjs/canvas → esm/Canvas}/utils/Custom/customLines.js +2 -2
- package/dist/esm/Canvas/utils/Custom/customLines.js.map +1 -0
- package/dist/esm/{canvas → Canvas}/utils/General/conversion.d.ts.map +1 -1
- package/dist/esm/{canvas → Canvas}/utils/General/conversion.js.map +1 -1
- package/dist/esm/{canvas → Canvas}/utils/General/general functions.d.ts.map +1 -1
- package/dist/{cjs/canvas → esm/Canvas}/utils/General/general functions.js.map +1 -1
- package/dist/esm/Canvas/utils/Image/imageFilters.d.ts +11 -0
- package/dist/esm/Canvas/utils/Image/imageFilters.d.ts.map +1 -0
- package/dist/esm/Canvas/utils/Image/imageFilters.js +307 -0
- package/dist/esm/Canvas/utils/Image/imageFilters.js.map +1 -0
- package/dist/esm/Canvas/utils/Image/imageProperties.d.ts +50 -0
- package/dist/esm/Canvas/utils/Image/imageProperties.d.ts.map +1 -0
- package/dist/esm/Canvas/utils/Image/imageProperties.js +271 -0
- package/dist/esm/Canvas/utils/Image/imageProperties.js.map +1 -0
- package/dist/esm/Canvas/utils/Image/professionalImageFilters.d.ts +11 -0
- package/dist/esm/Canvas/utils/Image/professionalImageFilters.d.ts.map +1 -0
- package/dist/esm/Canvas/utils/Image/professionalImageFilters.js +351 -0
- package/dist/esm/Canvas/utils/Image/professionalImageFilters.js.map +1 -0
- package/dist/esm/Canvas/utils/Image/simpleProfessionalFilters.d.ts +11 -0
- package/dist/esm/Canvas/utils/Image/simpleProfessionalFilters.d.ts.map +1 -0
- package/dist/esm/Canvas/utils/Image/simpleProfessionalFilters.js +215 -0
- package/dist/esm/Canvas/utils/Image/simpleProfessionalFilters.js.map +1 -0
- package/dist/esm/Canvas/utils/Patterns/enhancedPatternRenderer.d.ts +71 -0
- package/dist/esm/Canvas/utils/Patterns/enhancedPatternRenderer.d.ts.map +1 -0
- package/dist/esm/Canvas/utils/Patterns/enhancedPatternRenderer.js +392 -0
- package/dist/esm/Canvas/utils/Patterns/enhancedPatternRenderer.js.map +1 -0
- package/dist/esm/Canvas/utils/Shapes/shapes.d.ts +29 -0
- package/dist/esm/Canvas/utils/Shapes/shapes.d.ts.map +1 -0
- package/dist/esm/Canvas/utils/Shapes/shapes.js +334 -0
- package/dist/esm/Canvas/utils/Shapes/shapes.js.map +1 -0
- package/dist/esm/Canvas/utils/Texts/enhancedTextRenderer.d.ts +127 -0
- package/dist/esm/Canvas/utils/Texts/enhancedTextRenderer.d.ts.map +1 -0
- package/dist/esm/Canvas/utils/Texts/enhancedTextRenderer.js +365 -0
- package/dist/esm/Canvas/utils/Texts/enhancedTextRenderer.js.map +1 -0
- package/dist/esm/{canvas → Canvas}/utils/Texts/textProperties.d.ts.map +1 -1
- package/dist/{cjs/canvas → esm/Canvas}/utils/Texts/textProperties.js.map +1 -1
- package/dist/{cjs/canvas → esm/Canvas}/utils/types.d.ts +227 -131
- package/dist/esm/Canvas/utils/types.d.ts.map +1 -0
- package/dist/esm/{canvas → Canvas}/utils/types.js +0 -1
- package/dist/esm/Canvas/utils/types.js.map +1 -0
- package/dist/esm/Canvas/utils/utils.d.ts +22 -0
- package/dist/esm/Canvas/utils/utils.d.ts.map +1 -0
- package/dist/{cjs/canvas → esm/Canvas}/utils/utils.js +17 -7
- package/dist/esm/Canvas/utils/utils.js.map +1 -0
- package/dist/esm/index.d.ts +6 -3
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +8 -6
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/esm/utils.d.ts +1 -1
- package/dist/esm/utils.js +1 -1
- package/lib/{canvas → Canvas}/ApexPainter.ts +1325 -1218
- package/lib/Canvas/utils/Background/bg.ts +285 -0
- package/lib/{canvas → Canvas}/utils/Custom/customLines.ts +3 -3
- package/lib/Canvas/utils/Image/imageFilters.ts +356 -0
- package/lib/Canvas/utils/Image/imageProperties.ts +382 -0
- package/lib/Canvas/utils/Image/professionalImageFilters.ts +391 -0
- package/lib/Canvas/utils/Image/simpleProfessionalFilters.ts +229 -0
- package/lib/Canvas/utils/Patterns/enhancedPatternRenderer.ts +444 -0
- package/lib/Canvas/utils/Shapes/shapes.ts +528 -0
- package/lib/Canvas/utils/Texts/enhancedTextRenderer.ts +478 -0
- package/lib/{canvas → Canvas}/utils/types.ts +301 -117
- package/lib/{canvas → Canvas}/utils/utils.ts +85 -72
- package/lib/index.ts +8 -9
- package/lib/utils.ts +1 -1
- package/package.json +107 -191
- package/dist/cjs/canvas/ApexPainter.d.ts +0 -145
- package/dist/cjs/canvas/ApexPainter.d.ts.map +0 -1
- package/dist/cjs/canvas/ApexPainter.js.map +0 -1
- package/dist/cjs/canvas/utils/Background/bg.d.ts +0 -31
- package/dist/cjs/canvas/utils/Background/bg.d.ts.map +0 -1
- package/dist/cjs/canvas/utils/Background/bg.js +0 -161
- package/dist/cjs/canvas/utils/Background/bg.js.map +0 -1
- package/dist/cjs/canvas/utils/Custom/customLines.js.map +0 -1
- package/dist/cjs/canvas/utils/Image/imageProperties.d.ts +0 -115
- package/dist/cjs/canvas/utils/Image/imageProperties.d.ts.map +0 -1
- package/dist/cjs/canvas/utils/Image/imageProperties.js +0 -602
- package/dist/cjs/canvas/utils/Image/imageProperties.js.map +0 -1
- package/dist/cjs/canvas/utils/types.d.ts.map +0 -1
- package/dist/cjs/canvas/utils/types.js.map +0 -1
- package/dist/cjs/canvas/utils/utils.d.ts +0 -19
- package/dist/cjs/canvas/utils/utils.d.ts.map +0 -1
- package/dist/cjs/canvas/utils/utils.js.map +0 -1
- package/dist/esm/canvas/ApexPainter.d.ts +0 -145
- package/dist/esm/canvas/ApexPainter.d.ts.map +0 -1
- package/dist/esm/canvas/ApexPainter.js.map +0 -1
- package/dist/esm/canvas/utils/Background/bg.d.ts +0 -31
- package/dist/esm/canvas/utils/Background/bg.d.ts.map +0 -1
- package/dist/esm/canvas/utils/Background/bg.js +0 -161
- package/dist/esm/canvas/utils/Background/bg.js.map +0 -1
- package/dist/esm/canvas/utils/Custom/customLines.js.map +0 -1
- package/dist/esm/canvas/utils/Image/imageProperties.d.ts +0 -115
- package/dist/esm/canvas/utils/Image/imageProperties.d.ts.map +0 -1
- package/dist/esm/canvas/utils/Image/imageProperties.js +0 -602
- package/dist/esm/canvas/utils/Image/imageProperties.js.map +0 -1
- package/dist/esm/canvas/utils/types.d.ts.map +0 -1
- package/dist/esm/canvas/utils/types.js.map +0 -1
- package/dist/esm/canvas/utils/utils.d.ts +0 -19
- package/dist/esm/canvas/utils/utils.d.ts.map +0 -1
- package/dist/esm/canvas/utils/utils.js.map +0 -1
- package/lib/canvas/utils/Background/bg.ts +0 -211
- package/lib/canvas/utils/Image/imageProperties.ts +0 -835
- /package/dist/cjs/{canvas → Canvas}/utils/Charts/charts.d.ts +0 -0
- /package/dist/cjs/{canvas → Canvas}/utils/Charts/charts.js +0 -0
- /package/dist/cjs/{canvas → Canvas}/utils/Custom/customLines.d.ts +0 -0
- /package/dist/cjs/{canvas → Canvas}/utils/General/conversion.d.ts +0 -0
- /package/dist/cjs/{canvas → Canvas}/utils/General/conversion.js +0 -0
- /package/dist/cjs/{canvas → Canvas}/utils/General/general functions.d.ts +0 -0
- /package/dist/cjs/{canvas → Canvas}/utils/General/general functions.js +0 -0
- /package/dist/cjs/{canvas → Canvas}/utils/Texts/textProperties.d.ts +0 -0
- /package/dist/cjs/{canvas → Canvas}/utils/Texts/textProperties.js +0 -0
- /package/dist/esm/{canvas → Canvas}/utils/Charts/charts.d.ts +0 -0
- /package/dist/esm/{canvas → Canvas}/utils/Charts/charts.js +0 -0
- /package/dist/esm/{canvas → Canvas}/utils/Custom/customLines.d.ts +0 -0
- /package/dist/esm/{canvas → Canvas}/utils/General/conversion.d.ts +0 -0
- /package/dist/esm/{canvas → Canvas}/utils/General/conversion.js +0 -0
- /package/dist/esm/{canvas → Canvas}/utils/General/general functions.d.ts +0 -0
- /package/dist/esm/{canvas → Canvas}/utils/General/general functions.js +0 -0
- /package/dist/esm/{canvas → Canvas}/utils/Texts/textProperties.d.ts +0 -0
- /package/dist/esm/{canvas → Canvas}/utils/Texts/textProperties.js +0 -0
- /package/lib/{canvas → Canvas}/utils/Charts/charts.ts +0 -0
- /package/lib/{canvas → Canvas}/utils/General/conversion.ts +0 -0
- /package/lib/{canvas → Canvas}/utils/General/general functions.ts +0 -0
- /package/lib/{canvas → Canvas}/utils/Texts/textProperties.ts +0 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import { SKRSContext2D } from '@napi-rs/canvas';
|
|
2
|
+
import { ImageFilter } from '../types';
|
|
3
|
+
import sharp from 'sharp';
|
|
4
|
+
import { Jimp } from 'jimp';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Applies professional image filters using Sharp and Jimp
|
|
8
|
+
* @param ctx Canvas 2D context
|
|
9
|
+
* @param filters Array of filters to apply
|
|
10
|
+
* @param width Canvas width
|
|
11
|
+
* @param height Canvas height
|
|
12
|
+
*/
|
|
13
|
+
export async function applyProfessionalImageFilters(
|
|
14
|
+
ctx: SKRSContext2D,
|
|
15
|
+
filters: ImageFilter[],
|
|
16
|
+
width: number,
|
|
17
|
+
height: number
|
|
18
|
+
): Promise<void> {
|
|
19
|
+
if (!filters || filters.length === 0) return;
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
// Get current canvas data
|
|
23
|
+
const imageData = ctx.getImageData(0, 0, width, height);
|
|
24
|
+
const buffer = Buffer.from(new Uint8Array(imageData.data.buffer));
|
|
25
|
+
|
|
26
|
+
// Convert to Sharp-compatible format
|
|
27
|
+
let sharpImage = sharp(buffer, {
|
|
28
|
+
raw: {
|
|
29
|
+
width: width,
|
|
30
|
+
height: height,
|
|
31
|
+
channels: 4
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Apply each filter using Sharp
|
|
36
|
+
for (const filter of filters) {
|
|
37
|
+
switch (filter.type) {
|
|
38
|
+
case 'gaussianBlur':
|
|
39
|
+
sharpImage = await applyGaussianBlurSharp(sharpImage, filter.intensity || 0);
|
|
40
|
+
break;
|
|
41
|
+
case 'motionBlur':
|
|
42
|
+
sharpImage = await applyMotionBlurSharp(sharpImage, filter.intensity || 0, filter.angle || 0);
|
|
43
|
+
break;
|
|
44
|
+
case 'radialBlur':
|
|
45
|
+
sharpImage = await applyRadialBlurSharp(sharpImage, filter.intensity || 0, filter.centerX || width/2, filter.centerY || height/2);
|
|
46
|
+
break;
|
|
47
|
+
case 'sharpen':
|
|
48
|
+
sharpImage = await applySharpenSharp(sharpImage, filter.intensity || 0);
|
|
49
|
+
break;
|
|
50
|
+
case 'brightness':
|
|
51
|
+
sharpImage = await applyBrightnessSharp(sharpImage, filter.value || 0);
|
|
52
|
+
break;
|
|
53
|
+
case 'contrast':
|
|
54
|
+
sharpImage = await applyContrastSharp(sharpImage, filter.value || 0);
|
|
55
|
+
break;
|
|
56
|
+
case 'saturation':
|
|
57
|
+
sharpImage = await applySaturationSharp(sharpImage, filter.value || 0);
|
|
58
|
+
break;
|
|
59
|
+
case 'hueShift':
|
|
60
|
+
sharpImage = await applyHueShiftSharp(sharpImage, filter.value || 0);
|
|
61
|
+
break;
|
|
62
|
+
case 'grayscale':
|
|
63
|
+
sharpImage = await applyGrayscaleSharp(sharpImage);
|
|
64
|
+
break;
|
|
65
|
+
case 'sepia':
|
|
66
|
+
sharpImage = await applySepiaSharp(sharpImage);
|
|
67
|
+
break;
|
|
68
|
+
case 'invert':
|
|
69
|
+
sharpImage = await applyInvertSharp(sharpImage);
|
|
70
|
+
break;
|
|
71
|
+
case 'posterize':
|
|
72
|
+
sharpImage = await applyPosterizeSharp(sharpImage, filter.levels || 4);
|
|
73
|
+
break;
|
|
74
|
+
case 'pixelate':
|
|
75
|
+
sharpImage = await applyPixelateSharp(sharpImage, filter.size || 10);
|
|
76
|
+
break;
|
|
77
|
+
case 'noise':
|
|
78
|
+
sharpImage = await applyNoiseSharp(sharpImage, filter.intensity || 0.1);
|
|
79
|
+
break;
|
|
80
|
+
case 'grain':
|
|
81
|
+
sharpImage = await applyGrainSharp(sharpImage, filter.intensity || 0.05);
|
|
82
|
+
break;
|
|
83
|
+
case 'edgeDetection':
|
|
84
|
+
sharpImage = await applyEdgeDetectionSharp(sharpImage, filter.intensity || 1);
|
|
85
|
+
break;
|
|
86
|
+
case 'emboss':
|
|
87
|
+
sharpImage = await applyEmbossSharp(sharpImage, filter.intensity || 1);
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Convert back to canvas format
|
|
93
|
+
const { data } = await sharpImage.raw().toBuffer({ resolveWithObject: true });
|
|
94
|
+
const newImageData = new ImageData(new Uint8ClampedArray(data), width, height);
|
|
95
|
+
ctx.putImageData(newImageData, 0, 0);
|
|
96
|
+
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error('Error applying professional filters:', error);
|
|
99
|
+
// Fallback to basic filters if Sharp fails
|
|
100
|
+
applyBasicFilters(ctx, filters, width, height);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Sharp-based filter implementations
|
|
105
|
+
async function applyGaussianBlurSharp(image: sharp.Sharp, intensity: number): Promise<sharp.Sharp> {
|
|
106
|
+
if (intensity > 0) {
|
|
107
|
+
return image.blur(intensity);
|
|
108
|
+
}
|
|
109
|
+
return image;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function applyMotionBlurSharp(image: sharp.Sharp, intensity: number, angle: number): Promise<sharp.Sharp> {
|
|
113
|
+
if (intensity > 0) {
|
|
114
|
+
// Motion blur using convolution
|
|
115
|
+
const kernel = createMotionBlurKernel(intensity, angle);
|
|
116
|
+
return image.convolve(kernel);
|
|
117
|
+
}
|
|
118
|
+
return image;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function applyRadialBlurSharp(image: sharp.Sharp, intensity: number, centerX: number, centerY: number): Promise<sharp.Sharp> {
|
|
122
|
+
if (intensity > 0) {
|
|
123
|
+
// Radial blur using custom kernel
|
|
124
|
+
const kernel = createRadialBlurKernel(intensity, centerX, centerY);
|
|
125
|
+
return image.convolve(kernel);
|
|
126
|
+
}
|
|
127
|
+
return image;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function applySharpenSharp(image: sharp.Sharp, intensity: number): Promise<sharp.Sharp> {
|
|
131
|
+
if (intensity > 0) {
|
|
132
|
+
return image.sharpen(intensity, 1, 2);
|
|
133
|
+
}
|
|
134
|
+
return image;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function applyBrightnessSharp(image: sharp.Sharp, value: number): Promise<sharp.Sharp> {
|
|
138
|
+
if (value !== 0) {
|
|
139
|
+
const brightness = Math.max(0, Math.min(2, 1 + value / 100));
|
|
140
|
+
return image.modulate({ brightness });
|
|
141
|
+
}
|
|
142
|
+
return image;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function applyContrastSharp(image: sharp.Sharp, value: number): Promise<sharp.Sharp> {
|
|
146
|
+
if (value !== 0) {
|
|
147
|
+
const contrast = Math.max(0, Math.min(2, 1 + value / 100));
|
|
148
|
+
return image.linear(contrast, -(128 * contrast) + 128);
|
|
149
|
+
}
|
|
150
|
+
return image;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function applySaturationSharp(image: sharp.Sharp, value: number): Promise<sharp.Sharp> {
|
|
154
|
+
if (value !== 0) {
|
|
155
|
+
const saturation = Math.max(0, Math.min(2, 1 + value / 100));
|
|
156
|
+
return image.modulate({ saturation });
|
|
157
|
+
}
|
|
158
|
+
return image;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function applyHueShiftSharp(image: sharp.Sharp, value: number): Promise<sharp.Sharp> {
|
|
162
|
+
if (value !== 0) {
|
|
163
|
+
return image.modulate({ hue: value });
|
|
164
|
+
}
|
|
165
|
+
return image;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function applyGrayscaleSharp(image: sharp.Sharp): Promise<sharp.Sharp> {
|
|
169
|
+
return image.grayscale();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function applySepiaSharp(image: sharp.Sharp): Promise<sharp.Sharp> {
|
|
173
|
+
return image.recomb([
|
|
174
|
+
[0.393, 0.769, 0.189],
|
|
175
|
+
[0.349, 0.686, 0.168],
|
|
176
|
+
[0.272, 0.534, 0.131]
|
|
177
|
+
]);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function applyInvertSharp(image: sharp.Sharp): Promise<sharp.Sharp> {
|
|
181
|
+
return image.negate();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function applyPosterizeSharp(image: sharp.Sharp, levels: number): Promise<sharp.Sharp> {
|
|
185
|
+
if (levels > 1) {
|
|
186
|
+
const step = 255 / (levels - 1);
|
|
187
|
+
return image.threshold(128).modulate({ saturation: 0 });
|
|
188
|
+
}
|
|
189
|
+
return image;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async function applyPixelateSharp(image: sharp.Sharp, size: number): Promise<sharp.Sharp> {
|
|
193
|
+
if (size > 1) {
|
|
194
|
+
const { width, height } = await image.metadata();
|
|
195
|
+
const scale = Math.max(1, Math.floor(Math.min(width || 1, height || 1) / size));
|
|
196
|
+
return image.resize({ width: scale, height: scale, kernel: sharp.kernel.nearest })
|
|
197
|
+
.resize({ width: width, height: height, kernel: sharp.kernel.nearest });
|
|
198
|
+
}
|
|
199
|
+
return image;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async function applyNoiseSharp(image: sharp.Sharp, intensity: number): Promise<sharp.Sharp> {
|
|
203
|
+
if (intensity > 0) {
|
|
204
|
+
// Add noise using Jimp for better control
|
|
205
|
+
const buffer = await image.png().toBuffer();
|
|
206
|
+
const jimpImage = await Jimp.read(buffer);
|
|
207
|
+
|
|
208
|
+
jimpImage.scan(0, 0, jimpImage.width, jimpImage.height, function (this: any, x: number, y: number, idx: number) {
|
|
209
|
+
const noise = (Math.random() - 0.5) * intensity * 255;
|
|
210
|
+
this.bitmap.data[idx] = Math.max(0, Math.min(255, this.bitmap.data[idx] + noise)); // R
|
|
211
|
+
this.bitmap.data[idx + 1] = Math.max(0, Math.min(255, this.bitmap.data[idx + 1] + noise)); // G
|
|
212
|
+
this.bitmap.data[idx + 2] = Math.max(0, Math.min(255, this.bitmap.data[idx + 2] + noise)); // B
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const jimpBuffer = await jimpImage.getBuffer('image/png');
|
|
216
|
+
return sharp(jimpBuffer);
|
|
217
|
+
}
|
|
218
|
+
return image;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function applyGrainSharp(image: sharp.Sharp, intensity: number): Promise<sharp.Sharp> {
|
|
222
|
+
if (intensity > 0) {
|
|
223
|
+
// Add grain using Jimp
|
|
224
|
+
const buffer = await image.png().toBuffer();
|
|
225
|
+
const jimpImage = await Jimp.read(buffer);
|
|
226
|
+
|
|
227
|
+
jimpImage.scan(0, 0, jimpImage.width, jimpImage.height, function (this: any, x: number, y: number, idx: number) {
|
|
228
|
+
const grain = (Math.random() - 0.5) * intensity * 100;
|
|
229
|
+
this.bitmap.data[idx] = Math.max(0, Math.min(255, this.bitmap.data[idx] + grain)); // R
|
|
230
|
+
this.bitmap.data[idx + 1] = Math.max(0, Math.min(255, this.bitmap.data[idx + 1] + grain)); // G
|
|
231
|
+
this.bitmap.data[idx + 2] = Math.max(0, Math.min(255, this.bitmap.data[idx + 2] + grain)); // B
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const jimpBuffer = await jimpImage.getBuffer('image/png');
|
|
235
|
+
return sharp(jimpBuffer);
|
|
236
|
+
}
|
|
237
|
+
return image;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async function applyEdgeDetectionSharp(image: sharp.Sharp, intensity: number): Promise<sharp.Sharp> {
|
|
241
|
+
if (intensity > 0) {
|
|
242
|
+
// Edge detection using Sobel kernel
|
|
243
|
+
const kernel = createSobelKernel(intensity);
|
|
244
|
+
return image.convolve(kernel).grayscale();
|
|
245
|
+
}
|
|
246
|
+
return image;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async function applyEmbossSharp(image: sharp.Sharp, intensity: number): Promise<sharp.Sharp> {
|
|
250
|
+
if (intensity > 0) {
|
|
251
|
+
// Emboss using custom kernel
|
|
252
|
+
const kernel = createEmbossKernel(intensity);
|
|
253
|
+
return image.convolve(kernel);
|
|
254
|
+
}
|
|
255
|
+
return image;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Kernel creation functions
|
|
259
|
+
function createMotionBlurKernel(intensity: number, angle: number): any {
|
|
260
|
+
const size = Math.max(3, Math.floor(intensity));
|
|
261
|
+
const kernel = Array(size * size).fill(0);
|
|
262
|
+
const center = Math.floor(size / 2);
|
|
263
|
+
|
|
264
|
+
// Create motion blur kernel based on angle
|
|
265
|
+
const radians = (angle * Math.PI) / 180;
|
|
266
|
+
const dx = Math.cos(radians);
|
|
267
|
+
const dy = Math.sin(radians);
|
|
268
|
+
|
|
269
|
+
for (let i = 0; i < size; i++) {
|
|
270
|
+
const x = Math.round(center + dx * (i - center));
|
|
271
|
+
const y = Math.round(center + dy * (i - center));
|
|
272
|
+
if (x >= 0 && x < size && y >= 0 && y < size) {
|
|
273
|
+
kernel[y * size + x] = 1 / size;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
width: size,
|
|
279
|
+
height: size,
|
|
280
|
+
kernel: kernel,
|
|
281
|
+
scale: 1,
|
|
282
|
+
offset: 0
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function createRadialBlurKernel(intensity: number, centerX: number, centerY: number): any {
|
|
287
|
+
const size = Math.max(3, Math.floor(intensity));
|
|
288
|
+
const kernel = Array(size * size).fill(0);
|
|
289
|
+
const center = Math.floor(size / 2);
|
|
290
|
+
|
|
291
|
+
for (let y = 0; y < size; y++) {
|
|
292
|
+
for (let x = 0; x < size; x++) {
|
|
293
|
+
const distance = Math.sqrt((x - center) ** 2 + (y - center) ** 2);
|
|
294
|
+
const weight = Math.max(0, 1 - distance / center);
|
|
295
|
+
kernel[y * size + x] = weight;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Normalize kernel
|
|
300
|
+
const sum = kernel.reduce((a, b) => a + b, 0);
|
|
301
|
+
for (let i = 0; i < kernel.length; i++) {
|
|
302
|
+
kernel[i] /= sum;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
width: size,
|
|
307
|
+
height: size,
|
|
308
|
+
kernel: kernel,
|
|
309
|
+
scale: 1,
|
|
310
|
+
offset: 0
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function createSobelKernel(intensity: number): any {
|
|
315
|
+
// Sobel X kernel for edge detection
|
|
316
|
+
const kernel = [
|
|
317
|
+
-1, 0, 1,
|
|
318
|
+
-2, 0, 2,
|
|
319
|
+
-1, 0, 1
|
|
320
|
+
].map(v => v * intensity);
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
width: 3,
|
|
324
|
+
height: 3,
|
|
325
|
+
kernel: kernel,
|
|
326
|
+
scale: 1,
|
|
327
|
+
offset: 128
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function createEmbossKernel(intensity: number): any {
|
|
332
|
+
const kernel = [
|
|
333
|
+
-2, -1, 0,
|
|
334
|
+
-1, 1, 1,
|
|
335
|
+
0, 1, 2
|
|
336
|
+
].map(v => v * intensity);
|
|
337
|
+
|
|
338
|
+
return {
|
|
339
|
+
width: 3,
|
|
340
|
+
height: 3,
|
|
341
|
+
kernel: kernel,
|
|
342
|
+
scale: 1,
|
|
343
|
+
offset: 128
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Fallback basic filters
|
|
348
|
+
function applyBasicFilters(ctx: SKRSContext2D, filters: ImageFilter[], width: number, height: number): void {
|
|
349
|
+
ctx.save();
|
|
350
|
+
|
|
351
|
+
for (const filter of filters) {
|
|
352
|
+
switch (filter.type) {
|
|
353
|
+
case 'gaussianBlur':
|
|
354
|
+
if (filter.intensity && filter.intensity > 0) {
|
|
355
|
+
ctx.filter = `blur(${filter.intensity}px)`;
|
|
356
|
+
}
|
|
357
|
+
break;
|
|
358
|
+
case 'brightness':
|
|
359
|
+
if (filter.value !== undefined) {
|
|
360
|
+
ctx.filter = `brightness(${100 + filter.value}%)`;
|
|
361
|
+
}
|
|
362
|
+
break;
|
|
363
|
+
case 'contrast':
|
|
364
|
+
if (filter.value !== undefined) {
|
|
365
|
+
ctx.filter = `contrast(${100 + filter.value}%)`;
|
|
366
|
+
}
|
|
367
|
+
break;
|
|
368
|
+
case 'saturation':
|
|
369
|
+
if (filter.value !== undefined) {
|
|
370
|
+
ctx.filter = `saturate(${100 + filter.value}%)`;
|
|
371
|
+
}
|
|
372
|
+
break;
|
|
373
|
+
case 'hueShift':
|
|
374
|
+
if (filter.value !== undefined) {
|
|
375
|
+
ctx.filter = `hue-rotate(${filter.value}deg)`;
|
|
376
|
+
}
|
|
377
|
+
break;
|
|
378
|
+
case 'grayscale':
|
|
379
|
+
ctx.filter = 'grayscale(100%)';
|
|
380
|
+
break;
|
|
381
|
+
case 'sepia':
|
|
382
|
+
ctx.filter = 'sepia(100%)';
|
|
383
|
+
break;
|
|
384
|
+
case 'invert':
|
|
385
|
+
ctx.filter = 'invert(100%)';
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
ctx.restore();
|
|
391
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { SKRSContext2D } from '@napi-rs/canvas';
|
|
2
|
+
import { ImageFilter } from '../types';
|
|
3
|
+
import sharp from 'sharp';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Applies professional image filters using Sharp (simplified version)
|
|
7
|
+
* @param ctx Canvas 2D context
|
|
8
|
+
* @param filters Array of filters to apply
|
|
9
|
+
* @param width Canvas width
|
|
10
|
+
* @param height Canvas height
|
|
11
|
+
*/
|
|
12
|
+
export async function applySimpleProfessionalFilters(
|
|
13
|
+
ctx: SKRSContext2D,
|
|
14
|
+
filters: ImageFilter[],
|
|
15
|
+
width: number,
|
|
16
|
+
height: number
|
|
17
|
+
): Promise<void> {
|
|
18
|
+
if (!filters || filters.length === 0) return;
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
// Get current canvas data
|
|
22
|
+
const imageData = ctx.getImageData(0, 0, width, height);
|
|
23
|
+
// Convert Uint8ClampedArray to Buffer for Sharp
|
|
24
|
+
const buffer = Buffer.from(new Uint8Array(imageData.data.buffer));
|
|
25
|
+
|
|
26
|
+
// Convert to Sharp-compatible format
|
|
27
|
+
let sharpImage = sharp(buffer, {
|
|
28
|
+
raw: {
|
|
29
|
+
width: width,
|
|
30
|
+
height: height,
|
|
31
|
+
channels: 4
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Apply each filter using Sharp
|
|
36
|
+
for (const filter of filters) {
|
|
37
|
+
switch (filter.type) {
|
|
38
|
+
case 'gaussianBlur':
|
|
39
|
+
if (filter.intensity && filter.intensity > 0) {
|
|
40
|
+
sharpImage = sharpImage.blur(filter.intensity);
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
case 'sharpen':
|
|
44
|
+
if (filter.intensity && filter.intensity > 0) {
|
|
45
|
+
sharpImage = sharpImage.sharpen(filter.intensity);
|
|
46
|
+
}
|
|
47
|
+
break;
|
|
48
|
+
case 'brightness':
|
|
49
|
+
if (filter.value !== undefined && filter.value !== 0) {
|
|
50
|
+
const brightness = Math.max(0, Math.min(2, 1 + filter.value / 100));
|
|
51
|
+
sharpImage = sharpImage.modulate({ brightness });
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
case 'contrast':
|
|
55
|
+
if (filter.value !== undefined && filter.value !== 0) {
|
|
56
|
+
const contrast = Math.max(0, Math.min(2, 1 + filter.value / 100));
|
|
57
|
+
sharpImage = sharpImage.linear(contrast, -(128 * contrast) + 128);
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
case 'saturation':
|
|
61
|
+
if (filter.value !== undefined && filter.value !== 0) {
|
|
62
|
+
const saturation = Math.max(0, Math.min(2, 1 + filter.value / 100));
|
|
63
|
+
sharpImage = sharpImage.modulate({ saturation });
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
case 'hueShift':
|
|
67
|
+
if (filter.value !== undefined && filter.value !== 0) {
|
|
68
|
+
sharpImage = sharpImage.modulate({ hue: filter.value });
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
case 'grayscale':
|
|
72
|
+
sharpImage = sharpImage.grayscale();
|
|
73
|
+
break;
|
|
74
|
+
case 'sepia':
|
|
75
|
+
sharpImage = sharpImage.recomb([
|
|
76
|
+
[0.393, 0.769, 0.189],
|
|
77
|
+
[0.349, 0.686, 0.168],
|
|
78
|
+
[0.272, 0.534, 0.131]
|
|
79
|
+
]);
|
|
80
|
+
break;
|
|
81
|
+
case 'invert':
|
|
82
|
+
sharpImage = sharpImage.negate();
|
|
83
|
+
break;
|
|
84
|
+
case 'posterize':
|
|
85
|
+
if (filter.levels && filter.levels > 1) {
|
|
86
|
+
sharpImage = sharpImage.threshold(128);
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
case 'pixelate':
|
|
90
|
+
if (filter.size && filter.size > 1) {
|
|
91
|
+
const { width: imgWidth, height: imgHeight } = await sharpImage.metadata();
|
|
92
|
+
const scale = Math.max(1, Math.floor(Math.min(imgWidth || 1, imgHeight || 1) / filter.size));
|
|
93
|
+
sharpImage = sharpImage.resize({ width: scale, height: scale, kernel: sharp.kernel.nearest })
|
|
94
|
+
.resize({ width: imgWidth, height: imgHeight, kernel: sharp.kernel.nearest });
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
case 'motionBlur':
|
|
98
|
+
case 'radialBlur':
|
|
99
|
+
case 'noise':
|
|
100
|
+
case 'grain':
|
|
101
|
+
case 'edgeDetection':
|
|
102
|
+
case 'emboss':
|
|
103
|
+
// Use basic canvas filters for complex effects
|
|
104
|
+
applyBasicCanvasFilter(ctx, filter, width, height);
|
|
105
|
+
return; // Skip Sharp processing for these
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Convert back to canvas format
|
|
110
|
+
const { data } = await sharpImage.raw().toBuffer({ resolveWithObject: true });
|
|
111
|
+
const newImageData = ctx.createImageData(width, height);
|
|
112
|
+
newImageData.data.set(new Uint8ClampedArray(data));
|
|
113
|
+
ctx.putImageData(newImageData, 0, 0);
|
|
114
|
+
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.error('Error applying professional filters:', error);
|
|
117
|
+
// Fallback to basic filters if Sharp fails
|
|
118
|
+
applyBasicCanvasFilters(ctx, filters, width, height);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Basic canvas filter implementations for complex effects
|
|
123
|
+
function applyBasicCanvasFilter(ctx: SKRSContext2D, filter: ImageFilter, width: number, height: number): void {
|
|
124
|
+
ctx.save();
|
|
125
|
+
|
|
126
|
+
switch (filter.type) {
|
|
127
|
+
case 'motionBlur':
|
|
128
|
+
if (filter.intensity && filter.intensity > 0) {
|
|
129
|
+
const radians = ((filter.angle || 0) * Math.PI) / 180;
|
|
130
|
+
const blurX = Math.cos(radians) * filter.intensity;
|
|
131
|
+
const blurY = Math.sin(radians) * filter.intensity;
|
|
132
|
+
ctx.filter = `blur(${Math.abs(blurX)}px ${Math.abs(blurY)}px)`;
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
case 'radialBlur':
|
|
136
|
+
if (filter.intensity && filter.intensity > 0) {
|
|
137
|
+
ctx.filter = `blur(${filter.intensity}px)`;
|
|
138
|
+
}
|
|
139
|
+
break;
|
|
140
|
+
case 'noise':
|
|
141
|
+
if (filter.intensity && filter.intensity > 0) {
|
|
142
|
+
const imageData = ctx.getImageData(0, 0, width, height);
|
|
143
|
+
const data = imageData.data;
|
|
144
|
+
|
|
145
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
146
|
+
const noise = (Math.random() - 0.5) * filter.intensity * 255;
|
|
147
|
+
data[i] = Math.max(0, Math.min(255, data[i] + noise)); // R
|
|
148
|
+
data[i + 1] = Math.max(0, Math.min(255, data[i + 1] + noise)); // G
|
|
149
|
+
data[i + 2] = Math.max(0, Math.min(255, data[i + 2] + noise)); // B
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
ctx.putImageData(imageData, 0, 0);
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
case 'grain':
|
|
156
|
+
if (filter.intensity && filter.intensity > 0) {
|
|
157
|
+
const imageData = ctx.getImageData(0, 0, width, height);
|
|
158
|
+
const data = imageData.data;
|
|
159
|
+
|
|
160
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
161
|
+
const grain = (Math.random() - 0.5) * filter.intensity * 100;
|
|
162
|
+
data[i] = Math.max(0, Math.min(255, data[i] + grain)); // R
|
|
163
|
+
data[i + 1] = Math.max(0, Math.min(255, data[i + 1] + grain)); // G
|
|
164
|
+
data[i + 2] = Math.max(0, Math.min(255, data[i + 2] + grain)); // B
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
ctx.putImageData(imageData, 0, 0);
|
|
168
|
+
}
|
|
169
|
+
break;
|
|
170
|
+
case 'edgeDetection':
|
|
171
|
+
if (filter.intensity && filter.intensity > 0) {
|
|
172
|
+
ctx.filter = `contrast(${100 + filter.intensity * 50}%) brightness(${100 - filter.intensity * 20}%)`;
|
|
173
|
+
}
|
|
174
|
+
break;
|
|
175
|
+
case 'emboss':
|
|
176
|
+
if (filter.intensity && filter.intensity > 0) {
|
|
177
|
+
ctx.filter = `contrast(${100 + filter.intensity * 30}%) brightness(${100 + filter.intensity * 10}%)`;
|
|
178
|
+
}
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
ctx.restore();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Fallback basic filters
|
|
186
|
+
function applyBasicCanvasFilters(ctx: SKRSContext2D, filters: ImageFilter[], width: number, height: number): void {
|
|
187
|
+
ctx.save();
|
|
188
|
+
|
|
189
|
+
for (const filter of filters) {
|
|
190
|
+
switch (filter.type) {
|
|
191
|
+
case 'gaussianBlur':
|
|
192
|
+
if (filter.intensity && filter.intensity > 0) {
|
|
193
|
+
ctx.filter = `blur(${filter.intensity}px)`;
|
|
194
|
+
}
|
|
195
|
+
break;
|
|
196
|
+
case 'brightness':
|
|
197
|
+
if (filter.value !== undefined) {
|
|
198
|
+
ctx.filter = `brightness(${100 + filter.value}%)`;
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
case 'contrast':
|
|
202
|
+
if (filter.value !== undefined) {
|
|
203
|
+
ctx.filter = `contrast(${100 + filter.value}%)`;
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
case 'saturation':
|
|
207
|
+
if (filter.value !== undefined) {
|
|
208
|
+
ctx.filter = `saturate(${100 + filter.value}%)`;
|
|
209
|
+
}
|
|
210
|
+
break;
|
|
211
|
+
case 'hueShift':
|
|
212
|
+
if (filter.value !== undefined) {
|
|
213
|
+
ctx.filter = `hue-rotate(${filter.value}deg)`;
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
case 'grayscale':
|
|
217
|
+
ctx.filter = 'grayscale(100%)';
|
|
218
|
+
break;
|
|
219
|
+
case 'sepia':
|
|
220
|
+
ctx.filter = 'sepia(100%)';
|
|
221
|
+
break;
|
|
222
|
+
case 'invert':
|
|
223
|
+
ctx.filter = 'invert(100%)';
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
ctx.restore();
|
|
229
|
+
}
|