You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, colorLevels = 4, outlineColorStr = "black", outlineThickness = 2, shadowOffset = 2, shadowColorStr = "rgba(0,0,0,0.3)") {
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
if (width === 0 || height === 0) {
console.error("Image has zero dimensions. Ensure it is loaded correctly before processing.");
const errCanvas = document.createElement('canvas');
errCanvas.width = 1;
errCanvas.height = 1;
return errCanvas; // Return a minimal canvas
}
// Ensure colorLevels is an integer and at least 2
const numLevels = Math.max(2, parseInt(colorLevels, 10) || 2);
// Output canvas
const outCanvas = document.createElement('canvas');
outCanvas.width = width;
outCanvas.height = height;
const outCtx = outCanvas.getContext('2d');
if (!outCtx) {
console.error("Could not get 2D context for the output canvas.");
return document.createElement('canvas'); // Return an empty canvas
}
// Temporary canvas for posterization
const postCanvas = document.createElement('canvas');
postCanvas.width = width;
postCanvas.height = height;
const postCtx = postCanvas.getContext('2d');
if (!postCtx) {
console.error("Could not get 2D context for the posterization canvas.");
// Fallback: draw original image on outCanvas and return
outCtx.drawImage(originalImg, 0, 0, width, height);
return outCanvas;
}
postCtx.drawImage(originalImg, 0, 0, width, height);
let imageData;
try {
imageData = postCtx.getImageData(0, 0, width, height);
} catch (e) {
console.error("Could not get image data. This might be due to cross-origin restrictions if the image is not hosted on the same domain or if appropriate CORP/CORS headers are not set.", e);
// Fallback: draw original image and return
outCtx.drawImage(originalImg, 0, 0, width, height);
return outCanvas;
}
const data = imageData.data;
const factor = 255 / (numLevels - 1);
for (let i = 0; i < data.length; i += 4) {
data[i] = Math.round(data[i] / factor) * factor; // R
data[i+1] = Math.round(data[i+1] / factor) * factor; // G
data[i+2] = Math.round(data[i+2] / factor) * factor; // B
// Alpha (data[i+3]) is preserved
}
postCtx.putImageData(imageData, 0, 0); // postCanvas now holds the posterized image
// 1. Draw Shadow Layer
const sOffset = parseFloat(shadowOffset);
if (sOffset > 0) {
const shadowCanvas = document.createElement('canvas');
shadowCanvas.width = width;
shadowCanvas.height = height;
const shadowCtx = shadowCanvas.getContext('2d');
if (shadowCtx) {
shadowCtx.drawImage(postCanvas, 0, 0); // Draw posterized image (with its alpha)
shadowCtx.globalCompositeOperation = 'source-in'; // Keep existing alpha, fill color
shadowCtx.fillStyle = shadowColorStr;
shadowCtx.fillRect(0, 0, width, height);
// Draw this shadow silhouette offset on the output canvas
outCtx.drawImage(shadowCanvas, sOffset, sOffset);
// Reset composite operation for outCtx is not needed as it was not set on outCtx
} else {
console.warn("Could not create shadow canvas context. Skipping shadow.");
}
}
// 2. Draw Outline Layer
const oThickness = parseFloat(outlineThickness);
if (oThickness > 0) {
const outlineShapeCanvas = document.createElement('canvas');
outlineShapeCanvas.width = width;
outlineShapeCanvas.height = height;
const outlineShapeCtx = outlineShapeCanvas.getContext('2d');
if (outlineShapeCtx) {
outlineShapeCtx.drawImage(postCanvas, 0, 0); // Posterized image (with its alpha)
outlineShapeCtx.globalCompositeOperation = 'source-in'; // Keep existing alpha, fill color
outlineShapeCtx.fillStyle = outlineColorStr;
outlineShapeCtx.fillRect(0, 0, width, height);
// outlineShapeCanvas now contains the posterized shapes, filled with outlineColorStr, preserving alpha
// Define offsets for drawing the outline shape to create thickness
const directions = [
[-oThickness, -oThickness], [0, -oThickness], [oThickness, -oThickness],
[-oThickness, 0], [oThickness, 0],
[-oThickness, oThickness], [0, oThickness], [oThickness, oThickness]
];
for (const [dx, dy] of directions) {
outCtx.drawImage(outlineShapeCanvas, dx, dy);
}
} else {
console.warn("Could not create outline shape canvas context. Skipping outlines.");
}
}
// 3. Draw Main Posterized Image on top
// This will draw the colored posterized image over the shadow and outlines
outCtx.drawImage(postCanvas, 0, 0);
return outCanvas;
}
Apply Changes