- Image is created in a worker :D - Dragging is glitchy on mobile - Share throws a PermissionDenied error but it's in the same callback as an onclick handler idks
81 lines
2.1 KiB
JavaScript
81 lines
2.1 KiB
JavaScript
/**
|
|
* @param {number} color1
|
|
* @param {number} color2
|
|
*/
|
|
export function imageTwoTone(color1, color2, ctx) {
|
|
const dark = color1 % 0x1000000
|
|
const light = color2 % 0x1000000
|
|
pixelLevelFilter(ctx, (r, g, b, a) => {
|
|
const avg = (r + g + b) / 3 / 255
|
|
r = Math.round(lerp(
|
|
getChannel('red', dark),
|
|
getChannel('red', light),
|
|
avg
|
|
))
|
|
g = Math.round(lerp(
|
|
getChannel('green', dark),
|
|
getChannel('green', light),
|
|
avg
|
|
))
|
|
b = Math.round(lerp(
|
|
getChannel('blue', dark),
|
|
getChannel('blue', light),
|
|
avg
|
|
))
|
|
return [r, g, b, a]
|
|
})
|
|
}
|
|
|
|
/**
|
|
* @param {CanvasRenderingContext2D} ctx
|
|
* @param {(r: number, g: number, b: number, a: number) => [number, number, number, number]} fn
|
|
*/
|
|
function pixelLevelFilter(ctx, fn) {
|
|
const imageData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height)
|
|
const data = imageData.data
|
|
|
|
for (let i = 0; i < data.length; i += 4) {
|
|
const [r, g, b, a] = fn(
|
|
data[i + 0], // Red
|
|
data[i + 1], // Green
|
|
data[i + 2], // Blue
|
|
data[i + 3] // Alpha
|
|
)
|
|
data[i + 0] = r
|
|
data[i + 1] = g
|
|
data[i + 2] = b
|
|
data[i + 3] = a
|
|
}
|
|
|
|
ctx.putImageData(imageData, 0, 0)
|
|
}
|
|
|
|
function getChannel(channel, hex) {
|
|
switch (channel) {
|
|
case 'red':
|
|
return Math.floor(hex / 0x10000)
|
|
case 'green':
|
|
return Math.floor((hex % 0x10000) / 0x100)
|
|
case 'blue':
|
|
return Math.floor(hex % 0x100)
|
|
|
|
default: throw Error('Invalid channel')
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Interpolates a value given two other values and a scale of one to the other
|
|
* @param {number} v0 The inital value (at x = 0)
|
|
* @param {number} v1 The final value (at x = 1)
|
|
* @param {number} x The x for the new value; the interpolation factor
|
|
* @returns {number} The interpolated value
|
|
* @example
|
|
* // A random value between 5 and 10
|
|
* lerp(5, 10, Math.random())
|
|
* @author MindfulMinun
|
|
* @since 2020-07-05
|
|
*/
|
|
function lerp(v0, v1, x) {
|
|
return (1 - x) * v0 + x * v1
|
|
}
|