You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, pinkHighlightColorStr = "255,182,193", blueShadowColorStr = "173,216,230", effectIntensity = 0.7, softnessAmount = 1) {
/**
* Parses a color string (e.g., "255,100,50") into an RGB array.
* @param {string} colorStr The color string.
* @param {Array<number>} defaultColorArray The default color array to return if parsing fails.
* @returns {Array<number>} The parsed RGB array or the default.
*/
function _parseColorString(colorStr, defaultColorArray) {
if (typeof colorStr !== 'string') {
return defaultColorArray;
}
const parts = colorStr.split(',');
if (parts.length === 3) {
const rgb = parts.map(s => parseInt(s.trim(), 10));
if (rgb.every(val => !isNaN(val) && val >= 0 && val <= 255)) {
return rgb;
}
}
return defaultColorArray;
}
// Validate originalImg object
if (!originalImg || typeof originalImg.naturalWidth === 'undefined' || originalImg.naturalWidth === 0 || originalImg.naturalHeight === 0) {
console.warn("Original image is invalid, not loaded, or has zero dimensions. Returning a 1x1 gray canvas.");
const errCanvas = document.createElement('canvas');
errCanvas.width = 1;
errCanvas.height = 1;
const errCtx = errCanvas.getContext('2d');
if (errCtx) {
errCtx.fillStyle = 'rgb(128,128,128)'; // Gray
errCtx.fillRect(0, 0, 1, 1);
}
return errCanvas;
}
// Validate and parse parameters
const defaultPink = [255, 182, 193]; // Default: LightPink
const defaultBlue = [173, 216, 230]; // Default: LightBlue
const finalPinkRGB = _parseColorString(pinkHighlightColorStr, defaultPink);
const finalBlueRGB = _parseColorString(blueShadowColorStr, defaultBlue);
let finalEffectIntensity = Number(effectIntensity);
if (isNaN(finalEffectIntensity) || finalEffectIntensity < 0 || finalEffectIntensity > 1) {
finalEffectIntensity = 0.7; // Default intensity if invalid
}
let finalSoftnessAmount = Number(softnessAmount);
if (isNaN(finalSoftnessAmount) || finalSoftnessAmount < 0) {
finalSoftnessAmount = 1; // Default softness if invalid
}
finalSoftnessAmount = Math.min(finalSoftnessAmount, 20); // Cap softness to a reasonable maximum (e.g., 20px)
// 1. Create canvas and context
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Set canvas dimensions (use Math.round for robustness with potential fractional naturalW/H)
canvas.width = Math.round(originalImg.naturalWidth);
canvas.height = Math.round(originalImg.naturalHeight);
// 2. Apply softness (blur) if specified, then draw the original image
if (finalSoftnessAmount > 0) {
ctx.filter = `blur(${finalSoftnessAmount}px)`;
}
// Draw the image, ensuring it fits the canvas dimensions.
// If canvas W/H matches natural W/H, this is equivalent to ctx.drawImage(originalImg, 0, 0).
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// Reset filter after drawing so it doesn't affect subsequent operations like getImageData/putImageData
// or if nothing else would be drawn to this context.
if (finalSoftnessAmount > 0) {
ctx.filter = 'none';
}
// 3. Get image data
let imageData;
try {
imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
} catch (e) {
console.error("Could not get image data. This might be due to cross-origin restrictions if the image source is from a different domain and lacks CORS headers. Error: " + e.message);
// Return the canvas as is (original image, possibly blurred).
return canvas;
}
const data = imageData.data;
// 4. Iterate through pixels to apply the color effect
for (let i = 0; i < data.length; i += 4) {
const r_orig = data[i];
const g_orig = data[i + 1];
const b_orig = data[i + 2];
// Calculate luminance (perceived brightness) using Rec. 709 formula
const luminance = 0.2126 * r_orig + 0.7152 * g_orig + 0.0722 * b_orig;
const normLuminance = luminance / 255; // Normalize to [0, 1]
// Calculate duotone color:
// Darker parts (low luminance) tend towards blueShadowColor.
// Lighter parts (high luminance) tend towards pinkHighlightColor.
const duotone_r = (1 - normLuminance) * finalBlueRGB[0] + normLuminance * finalPinkRGB[0];
const duotone_g = (1 - normLuminance) * finalBlueRGB[1] + normLuminance * finalPinkRGB[1];
const duotone_b = (1 - normLuminance) * finalBlueRGB[2] + normLuminance * finalPinkRGB[2];
// Blend the duotone color with the original pixel color using effectIntensity
let new_r = r_orig * (1 - finalEffectIntensity) + duotone_r * finalEffectIntensity;
let new_g = g_orig * (1 - finalEffectIntensity) + duotone_g * finalEffectIntensity;
let new_b = b_orig * (1 - finalEffectIntensity) + duotone_b * finalEffectIntensity;
// Assign new RGB values, ensuring they are integers and clamped to [0, 255]
data[i] = Math.round(Math.max(0, Math.min(255, new_r)));
data[i + 1] = Math.round(Math.max(0, Math.min(255, new_g)));
data[i + 2] = Math.round(Math.max(0, Math.min(255, new_b)));
// Alpha channel (data[i + 3]) remains unchanged
}
// 5. Put the modified image data back onto the canvas
ctx.putImageData(imageData, 0, 0);
// 6. Return the processed canvas
return canvas;
}
Apply Changes