You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, posterLevels = 5, saturationBoost = 0.4, warmth = 0.1) {
// Helper function: Convert RGB to HSL
// r, g, b are 0-255. Outputs h, s, l are 0-1.
function rgbToHsl(r, g, b) {
r /= 255; g /= 255; b /= 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0; // achromatic
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
if (h === undefined) h = 0; // Should not happen with valid r,g,b
h /= 6;
}
return [h, s, l];
}
// Helper function: Convert HSL to RGB
// h, s, l are 0-1. Outputs r, g, b are 0-255.
function hslToRgb(h, s, l) {
let r, g, b;
if (s === 0) {
r = g = b = l; // achromatic
} else {
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = originalImg.naturalWidth || originalImg.width;
canvas.height = originalImg.naturalHeight || originalImg.height;
if (canvas.width === 0 || canvas.height === 0) {
console.warn("Image has zero dimensions. Returning empty_canvas.");
return canvas;
}
try {
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
} catch (e) {
console.error("Error drawing image to canvas: ", e);
return canvas; // Return canvas, possibly empty or with error indication
}
let imageData;
try {
imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
} catch (e) {
console.error("Could not getImageData (cross-origin issue?): ", e);
// Return the canvas with the original image drawn, as processing is not possible
return canvas;
}
const data = imageData.data;
// Validate and clamp parameters
// PosterLevels: 2 means 2 levels (e.g., 0 and 255), up to 16 levels
posterLevels = Math.max(2, Math.min(16, Math.floor(posterLevels)));
// SaturationBoost: 0 means no change, 1 means 100% boost. Max 200% boost.
saturationBoost = Math.max(0, Math.min(2, Number(saturationBoost)));
// Warmth: 0 means no change. Max 1 for strong warmth.
warmth = Math.max(0, Math.min(1, Number(warmth)));
const posterFactor = 255 / (posterLevels - 1);
for (let i = 0; i < data.length; i += 4) {
let r = data[i];
let g = data[i + 1];
let b = data[i + 2];
// 1. Posterization
// Applied if posterLevels >= 2 (guaranteed by clamping)
r = Math.round(r / posterFactor) * posterFactor;
g = Math.round(g / posterFactor) * posterFactor;
b = Math.round(b / posterFactor) * posterFactor;
r = Math.max(0, Math.min(255, r));
g = Math.max(0, Math.min(255, g));
b = Math.max(0, Math.min(255, b));
// 2. Saturation Boost
if (saturationBoost > 0) { // Only apply if there's a boost
const hsl = rgbToHsl(r, g, b);
hsl[1] = Math.min(1, hsl[1] * (1 + saturationBoost)); // Boost S
const rgbSaturated = hslToRgb(hsl[0], hsl[1], hsl[2]);
r = rgbSaturated[0];
g = rgbSaturated[1];
b = rgbSaturated[2];
}
// 3. Warmth
if (warmth > 0) {
// Additive warmth scaled by the 'warmth' parameter.
// Max additive values for r, g channels when warmth = 1
const rAdd = 50 * warmth; // Max 50 added to Red
const gAdd = 25 * warmth; // Max 25 added to Green
// Optional: const bSub = 15 * warmth; // Max 15 subtracted from Blue
r = Math.min(255, r + rAdd);
g = Math.min(255, g + gAdd);
// b = Math.max(0, b - bSub); // Uncomment for blue reduction part of warmth
}
data[i] = Math.round(r);
data[i + 1] = Math.round(g);
data[i + 2] = Math.round(b);
// Alpha (data[i+3]) remains unchanged
}
ctx.putImageData(imageData, 0, 0);
return canvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Tibetan Thangka Filter Effect Tool applies a unique artistic filter to images, inspired by traditional Tibetan thangka art. Users can enhance their images by adjusting posterization levels, boosting saturation, and modifying warmth. This tool is ideal for artists and designers looking to create stylized images for various projects, such as digital art, presentations, and social media posts, where a vibrant and culturally rich aesthetic is desired.