Please bookmark this page to avoid losing your image tool!

Fairytale Tourist Image Generator

(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.
/**
 * Fairytale Tourist Image Generator
 * Generates a magical, stylized "fairytale" portrait from the given image. 
 * Converts the image into a soft-edged magical mirror reflection enveloped in fantasy elements.
 * 
 * @param {HTMLImageElement} originalImg - The source photo.
 * @param {string} captionText - The text displayed at the bottom of the image.
 * @param {number|string} magicHue - Base hue (0-360) for the magical atmosphere (default 280 = Purple).
 * @param {number|string} glowIntensity - Scale of the sparkle and magical bloom (default 1.0).
 * @returns {HTMLCanvasElement} - The created fairytale canvas.
 */
async function processImage(originalImg, captionText = "Турист из сказки", magicHue = 280, glowIntensity = 1.0) {
    const hue = parseFloat(magicHue) || 280;
    const intensity = parseFloat(glowIntensity) || 1.0;

    // 1. Dynamically load a beautiful "fairytale" font that supports Cyrillic & Latin
    const fontName = 'Marck Script';
    try {
        if (!document.getElementById('fairytale-font-style')) {
            const style = document.createElement('style');
            style.id = 'fairytale-font-style';
            style.innerHTML = `@import url('https://fonts.googleapis.com/css2?family=Marck+Script&display=swap');`;
            document.head.appendChild(style);
        }
        // Give the font a moment to stream and parse if not cached
        await new Promise(resolve => setTimeout(resolve, 800));
    } catch (e) {
        console.warn('Could not load Google Font. Falling back to default cursive.', e);
    }

    // 2. Setup Dimensions
    const maxImgSize = 600;
    let scale = 1;
    if (originalImg.width > maxImgSize || originalImg.height > maxImgSize) {
        scale = Math.min(maxImgSize / originalImg.width, maxImgSize / originalImg.height);
    }
    const imgW = originalImg.width * scale;
    const imgH = originalImg.height * scale;

    const horizontalPadding = 100;
    const topPadding = 100;
    const bottomPadding = 180; // Extra space for text

    const canvas = document.createElement('canvas');
    canvas.width = imgW + (horizontalPadding * 2);
    canvas.height = imgH + topPadding + bottomPadding;
    const ctx = canvas.getContext('2d');

    // 3. Draw Magical Night/Fantasy Background
    const cx = canvas.width / 2;
    const cy = topPadding + (imgH / 2);
    const bgGradient = ctx.createRadialGradient(cx, cy, imgW * 0.2, cx, cy, canvas.width * 0.8);
    bgGradient.addColorStop(0, `hsl(${hue}, 40%, 20%)`);
    bgGradient.addColorStop(0.6, `hsl(${hue - 20}, 60%, 8%)`);
    bgGradient.addColorStop(1, `#050510`);
    
    ctx.fillStyle = bgGradient;
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // 4. Create Soft Edge Mask for the Portrait
    const offCanvas = document.createElement('canvas');
    offCanvas.width = imgW;
    offCanvas.height = imgH;
    const octx = offCanvas.getContext('2d');

    // Draw an elliptical fuzzy mask
    const ellipseRadiusX = (imgW / 2) - 40;
    const ellipseRadiusY = (imgH / 2) - 40;
    
    octx.shadowColor = 'black';
    octx.shadowBlur = 40;
    octx.fillStyle = 'black';
    octx.beginPath();
    octx.ellipse(imgW / 2, imgH / 2, Math.max(1, ellipseRadiusX), Math.max(1, ellipseRadiusY), 0, 0, Math.PI * 2);
    octx.fill();

    // Map original image onto the alpha of the fuzzy ellipse
    octx.globalCompositeOperation = 'source-in';
    octx.shadowBlur = 0; // Turn off shadow so it doesn't double-apply to image
    octx.drawImage(originalImg, 0, 0, imgW, imgH);

    // 5. Apply the Portrait to Main Canvas
    // Base portrait
    ctx.drawImage(offCanvas, horizontalPadding, topPadding);

    // Magical bloom / glow overlay
    ctx.save();
    ctx.globalCompositeOperation = 'screen';
    ctx.filter = `blur(${10 * intensity}px)`;
    ctx.globalAlpha = 0.5 * intensity;
    ctx.drawImage(offCanvas, horizontalPadding, topPadding);
    ctx.restore();

    // 6. Draw Magical Frame/Aura around Portrait
    ctx.save();
    ctx.beginPath();
    ctx.ellipse(cx, cy, Math.max(1, ellipseRadiusX + 5), Math.max(1, ellipseRadiusY + 5), 0, 0, Math.PI * 2);
    ctx.strokeStyle = `rgba(255, 230, 150, 0.4)`;
    ctx.lineWidth = 2;
    ctx.shadowColor = `hsl(${hue + 40}, 100%, 70%)`;
    ctx.shadowBlur = 15 * intensity;
    ctx.stroke();
    
    ctx.beginPath();
    ctx.ellipse(cx, cy, Math.max(1, ellipseRadiusX + 25), Math.max(1, ellipseRadiusY + 25), 0, 0, Math.PI * 2);
    ctx.strokeStyle = `rgba(255, 255, 255, 0.1)`;
    ctx.lineWidth = 1;
    ctx.stroke();
    ctx.restore();

    // 7. Add Procedural Fairytale Elements (Fairy Dust & Sparkles)
    const drawSparkle = (x, y, size) => {
        ctx.save();
        ctx.translate(x, y);
        ctx.beginPath();
        ctx.moveTo(0, -size);
        ctx.quadraticCurveTo(0, 0, size, 0);
        ctx.quadraticCurveTo(0, 0, 0, size);
        ctx.quadraticCurveTo(0, 0, -size, 0);
        ctx.quadraticCurveTo(0, 0, 0, -size);
        ctx.fillStyle = '#FFF2D8';
        ctx.shadowColor = '#FFFFFF';
        ctx.shadowBlur = 10 * intensity;
        ctx.fill();
        ctx.restore();
    };

    // Fairy dust dots
    const numDust = 80 * intensity;
    for (let i = 0; i < numDust; i++) {
        const x = Math.random() * canvas.width;
        const y = Math.random() * canvas.height;
        const radius = Math.random() * 2 + 0.5;
        ctx.beginPath();
        ctx.arc(x, y, radius, 0, Math.PI * 2);
        ctx.fillStyle = Math.random() > 0.5 ? '#ffffff' : `hsl(${hue + 30}, 100%, 80%)`;
        ctx.globalAlpha = Math.random() * 0.8 + 0.2;
        ctx.shadowBlur = 5;
        ctx.shadowColor = ctx.fillStyle;
        ctx.fill();
    }
    ctx.globalAlpha = 1.0;
    ctx.shadowBlur = 0;

    // Glowing Star Sparkles
    const numSparkles = 20 * intensity;
    for (let i = 0; i < numSparkles; i++) {
        const x = Math.random() * canvas.width;
        const y = Math.random() * canvas.height;
        const size = Math.random() * 12 + 4;
        
        // Avoid drawing huge sparkles right over the main face area
        const distToCenter = Math.hypot(x - cx, y - cy);
        if (distToCenter > (imgW / 4)) {
            drawSparkle(x, y, size);
        }
    }

    // 8. Draw Fairytale Typography (Caption)
    const textY = canvas.height - (bottomPadding * 0.5);
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.font = `56px "${fontName}", cursive`;

    // Text Glow
    ctx.shadowColor = `hsl(${hue}, 80%, 30%)`;
    ctx.shadowBlur = 20;

    // Gradient Gold Text Fill
    const textGradient = ctx.createLinearGradient(0, textY - 30, 0, textY + 30);
    textGradient.addColorStop(0, '#FFE891');
    textGradient.addColorStop(0.5, '#FBBF24');
    textGradient.addColorStop(1, '#B45309');

    ctx.fillStyle = textGradient;
    ctx.fillText(captionText, cx, textY);
    
    // Slight bright overlay to make text pop
    ctx.shadowBlur = 0;
    ctx.globalCompositeOperation = 'screen';
    ctx.fillStyle = 'rgba(255, 255, 255, 0.15)';
    ctx.fillText(captionText, cx, textY - 2);
    ctx.globalCompositeOperation = 'source-over';

    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

The Fairytale Tourist Image Generator transforms standard photos into magical, stylized portraits. It applies a soft-edged, elliptical mask to your image, embedding it within a fantasy-themed background featuring radial gradients, glowing auras, and procedural elements like fairy dust and sparkling stars. Users can customize the magical atmosphere by adjusting the color hue and the intensity of the glow, and can add personalized captions in elegant, fairytale-style typography. This tool is ideal for creating whimsical social media avatars, themed greeting cards, or enchanting digital keepsakes.

Leave a Reply

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