You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, mood = "warm", intensity = 0.7) {
// Ensure the image is fully loaded to get correct dimensions
if (!originalImg.complete || originalImg.naturalWidth === 0) {
// This can happen if the Image object was just created and src set, but not yet loaded,
// or if it's an <img> tag in the DOM that hasn't finished loading.
await new Promise((resolve, reject) => {
// If the image is already in a failed state
if (originalImg.complete && (originalImg.naturalWidth === 0 || originalImg.naturalHeight === 0)) {
// This can also happen for invalid images or SVGs if not handled properly
// For this tool, we expect raster images.
reject(new Error("Image is complete but has zero dimensions, or is not a valid raster image."));
return;
}
originalImg.onload = () => {
if (originalImg.naturalWidth === 0 || originalImg.naturalHeight === 0) {
reject(new Error("Image loaded successfully but has zero dimensions."));
} else {
resolve();
}
};
originalImg.onerror = () => reject(new Error("Image failed to load. Check the image URL or source."));
// If src is not set, it might never load.
// This is more of a caller's responsibility, but a basic check:
if (!originalImg.src) {
reject(new Error("Image source is not set."));
}
});
}
const canvas = document.createElement('canvas');
// Optimization hint for frequent getImageData/putImageData calls
const ctx = canvas.getContext('2d', { willReadFrequently: true });
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// Ensure intensity is within [0, 1]
intensity = Math.max(0, Math.min(1, intensity));
if (mood === "none" || intensity === 0) {
// If no mood change is needed or intensity is zero,
// return the canvas with the original image drawn.
return canvas;
}
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// Alpha channel (data[i+3]) is preserved
let nr_effect = r; //最终红色通道值 用于本次循环
let ng_effect = g; //最终绿色通道值 用于本次循环
let nb_effect = b; //最终蓝色通道值 用于本次循环
switch (mood) {
case "warm":
nr_effect = r + 40; // Increase red
// ng_effect = g; // Green channel can be slightly increased for "sunnier" sometimes
nb_effect = b - 30; // Decrease blue
break;
case "cool":
nr_effect = r - 30; // Decrease red
// ng_effect = g;
nb_effect = b + 40; // Increase blue
break;
case "sepia":
nr_effect = 0.393 * r + 0.769 * g + 0.189 * b;
ng_effect = 0.349 * r + 0.686 * g + 0.168 * b;
nb_effect = 0.272 * r + 0.534 * g + 0.131 * b;
break;
case "grayscale":
const gray = 0.299 * r + 0.587 * g + 0.114 * b; // Luminance standard
nr_effect = ng_effect = nb_effect = gray;
break;
case "dramatic":
const contrastFactor = 1.8; // Define "full effect" contrast
let r_c = 128 + (r - 128) * contrastFactor;
let g_c = 128 + (g - 128) * contrastFactor;
let b_c = 128 + (b - 128) * contrastFactor;
// Clamp intermediate contrasted colors before further processing (like desaturation)
r_c = Math.max(0, Math.min(255, r_c));
g_c = Math.max(0, Math.min(255, g_c));
b_c = Math.max(0, Math.min(255, b_c));
const desatAmount = 0.6; // Define "full effect" desaturation (e.g., 60%)
const gray_c = 0.299 * r_c + 0.587 * g_c + 0.114 * b_c;
nr_effect = r_c * (1 - desatAmount) + gray_c * desatAmount;
ng_effect = g_c * (1 - desatAmount) + gray_c * desatAmount;
nb_effect = b_c * (1 - desatAmount) + gray_c * desatAmount;
break;
case "vibrant":
const satBoost = 1.8; // Define "full effect" saturation boost
const luma = 0.299 * r + 0.587 * g + 0.114 * b; // Luminance calculation
nr_effect = luma + (r - luma) * satBoost;
ng_effect = luma + (g - luma) * satBoost;
nb_effect = luma + (b - luma) * satBoost;
break;
case "invert":
nr_effect = 255 - r;
ng_effect = 255 - g;
nb_effect = 255 - b;
break;
default:
// If mood is unknown, nr_effect, ng_effect, nb_effect remain as original r, g, b.
// This effectively means no change, same as "none" or intensity 0 for this pixel.
break;
}
// Clamp the "full effect" color components to be within [0, 255] range.
// This is important as calculations might send values out of bounds.
nr_effect = Math.max(0, Math.min(255, nr_effect));
ng_effect = Math.max(0, Math.min(255, ng_effect));
nb_effect = Math.max(0, Math.min(255, nb_effect));
// Blend the original pixel color (r,g,b) with the "full effect" color
// (nr_effect, ng_effect, nb_effect) using the specified intensity.
// Math.round is used for cleaner integer values, though Uint8ClampedArray would also handle floats.
data[i] = Math.round(r * (1 - intensity) + nr_effect * intensity);
data[i+1] = Math.round(g * (1 - intensity) + ng_effect * intensity);
data[i+2] = Math.round(b * (1 - intensity) + nb_effect * intensity);
// data[i+3] (alpha) is 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!
Photo Mood Changer is an online tool that allows users to enhance their images by applying various mood effects. With this tool, you can transform your photos to evoke different feelings such as warmth, coolness, or dramatic flair. It supports a range of mood options including sepia, grayscale, vibrant, and inverted colors, allowing for creative adjustments. This utility is ideal for photographers, social media enthusiasts, and anyone looking to modify their images for artistic purposes or to better convey a specific emotion in their visuals.