-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
105 lines (94 loc) · 3.06 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
interface iconColorChangeUtilProps {
iconUrl: string;
newColor: string;
type: 'data-png' | string;
callback?: (data: ImageData | string) => void;
width?: number;
height?: number;
}
const iconColorChangeUtil = (props: iconColorChangeUtilProps) => {
return new Promise((resolve, reject) => {
const { iconUrl, newColor, width, height } = props;
let { type, callback } = props;
if (!callback && typeof type == 'function') {
callback = type;
type = 'image-data';
}
let canvas: HTMLCanvasElement;
let context: CanvasRenderingContext2D | null;
getContext();
const iconElement = document.createElement('img');
iconElement.addEventListener('load', imageReady);
iconElement.addEventListener('error', () => {
reject('error');
});
if (width) iconElement.width = width;
if (height) iconElement.height = height;
iconElement.src = iconUrl;
function getCanvas() {
if (!canvas) {
canvas = document.createElement('canvas'); // shared instance
context = canvas.getContext('2d');
}
}
function getContext() {
if (!context) {
getCanvas();
}
}
function desaturate() {
if (!context) return;
const imageData = context.getImageData(0, 0, canvas.width, canvas.height),
pixels = imageData.data;
let i, l, r, g, b, a, average;
for (i = 0, l = pixels?.length; i < l; i += 4) {
a = pixels[i + 3];
if (a === 0) {
continue;
} // skip if pixel is transparent
r = pixels[i];
g = pixels[i + 1];
b = pixels[i + 2];
average = ((r + g + b) / 3) >>> 0; // quick floor
pixels[i] = pixels[i + 1] = pixels[i + 2] = average;
}
context.putImageData(imageData, 0, 0);
}
function colorize(color: string, alpha: number) {
if (!context) return;
context.globalCompositeOperation = 'source-atop';
context.globalAlpha = alpha;
context.fillStyle = color;
context.fillRect(0, 0, canvas.width, canvas.height);
// reset
context.globalCompositeOperation = 'source-over';
context.globalAlpha = 1.0;
}
function changeColor(color: string, alpha: number) {
getContext();
context?.clearRect(0, 0, canvas.width, canvas.height);
context?.drawImage(iconElement, 0, 0, canvas.width, canvas.height);
desaturate();
colorize(color, alpha);
}
function imageReady() {
canvas.width = iconElement.width;
canvas.height = iconElement.height;
changeColor(newColor, 1);
let result: string | ImageData;
if (type === 'data-png') {
const dataURL: string = canvas.toDataURL('image/png', 1);
callback?.(dataURL);
result = dataURL;
} /* if (type == 'image-data') */ else {
const imageData: ImageData = context?.getImageData(0, 0, canvas.width, canvas.height);
callback?.(imageData);
result = imageData;
}
resolve(result);
iconElement.remove();
}
});
};
export { iconColorChangeUtil };
export default iconColorChangeUtil;