You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, sketchBlur = 2, lineColorIntensity = 0.8, imageSaturation = 0.4, paperMix = 0.3, paperColorRGB = "245,245,220") {
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
if (width === 0 || height === 0) {
// Return an empty canvas or throw an error for invalid image dimensions
const emptyCanvas = document.createElement('canvas');
emptyCanvas.width = 1;
emptyCanvas.height = 1;
return emptyCanvas;
}
// 1. Parse paperColorRGB
const [pR, pG, pB] = paperColorRGB.split(',').map(s => parseInt(s.trim(), 10));
// 2. Create utility function for canvases
const createCanvas = (w, h) => {
const c = document.createElement('canvas');
c.width = w;
c.height = h;
return c;
};
// Create canvases
const grayCanvas = createCanvas(width, height);
const ctxGray = grayCanvas.getContext('2d');
const tempInvertedCanvas = createCanvas(width, height);
const ctxTempInverted = tempInvertedCanvas.getContext('2d');
const invertedBlurCanvas = createCanvas(width, height);
const ctxInvertedBlur = invertedBlurCanvas.getContext('2d');
const sketchCanvas = createCanvas(width, height);
const ctxSketch = sketchCanvas.getContext('2d');
const resultCanvas = createCanvas(width, height);
const ctxResult = resultCanvas.getContext('2d');
// 3. Create grayscale version of original image (grayCanvas)
ctxGray.filter = 'grayscale(100%)';
ctxGray.drawImage(originalImg, 0, 0, width, height);
// 4. Create inverted grayscale (tempInvertedCanvas)
ctxTempInverted.filter = 'invert(100%)';
ctxTempInverted.drawImage(grayCanvas, 0, 0, width, height);
// 5. Blur the inverted grayscale image (target: invertedBlurCanvas)
// This invertedBlurCanvas is the one used in Color Dodge
// A blur of 0px is often a no-op or invalid, so ensure a minimum small blur.
const blurRadius = Math.max(0.1, parseFloat(sketchBlur));
ctxInvertedBlur.filter = `blur(${blurRadius}px)`;
ctxInvertedBlur.drawImage(tempInvertedCanvas, 0, 0, width, height);
// 6. Create sketch lines using Color Dodge (sketchCanvas)
// This technique results in a mostly white image with dark lines.
ctxSketch.drawImage(grayCanvas, 0, 0, width, height); // Base for color dodge
ctxSketch.globalCompositeOperation = 'color-dodge';
ctxSketch.drawImage(invertedBlurCanvas, 0, 0, width, height); // Layer to dodge with
ctxSketch.globalCompositeOperation = 'source-over'; // Reset composite operation
// 7. Prepare the colored base layer on resultCanvas (stylized original)
ctxResult.drawImage(originalImg, 0, 0, width, height);
const imageData = ctxResult.getImageData(0, 0, width, height);
const data = imageData.data;
const sat = Math.max(0, Math.min(1, parseFloat(imageSaturation)));
const mix = Math.max(0, Math.min(1, parseFloat(paperMix)));
for (let i = 0; i < data.length; i += 4) {
let r = data[i];
let g = data[i+1];
let b = data[i+2];
// Alpha (data[i+3]) is preserved
// Apply saturation adjustment
const lum = 0.299 * r + 0.587 * g + 0.114 * b;
r = lum + sat * (r - lum);
g = lum + sat * (g - lum);
b = lum + sat * (b - lum);
// Apply paper color mix (linear interpolation)
r = r * (1 - mix) + pR * mix;
g = g * (1 - mix) + pG * mix;
b = b * (1 - mix) + pB * mix;
data[i] = Math.min(255, Math.max(0, r));
data[i+1] = Math.min(255, Math.max(0, g));
data[i+2] = Math.min(255, Math.max(0, b));
}
ctxResult.putImageData(imageData, 0, 0);
// resultCanvas now has the desaturated, paper-tinted color base.
// 8. Composite sketch lines onto the colored base
ctxResult.globalAlpha = Math.max(0, Math.min(1, parseFloat(lineColorIntensity)));
ctxResult.globalCompositeOperation = 'multiply';
ctxResult.drawImage(sketchCanvas, 0, 0, width, height);
// Reset context properties
ctxResult.globalAlpha = 1.0;
ctxResult.globalCompositeOperation = 'source-over';
return resultCanvas;
}
Apply Changes