Please bookmark this page to avoid losing your image tool!

Photo Mood Changer

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
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!

Description

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.

Leave a Reply

Your email address will not be published. Required fields are marked *