Please bookmark this page to avoid losing your image tool!

Image Storybook Creator

(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, vignetteStrength = 0.5, blurAmount = 2, sepiaTone = 0.3, textureOpacity = 0.1, borderStyle = 'ornate') {
    // 1. Create a canvas and get the 2D context
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    // Use naturalWidth/Height to get the original image dimensions.
    // This is important because the img element might be styled with CSS.
    const w = originalImg.naturalWidth;
    const h = originalImg.naturalHeight;

    // Handle cases where the image isn't loaded or has no dimensions.
    if (w === 0 || h === 0) {
        console.error("Image has not loaded or has zero dimensions.");
        canvas.width = 1;
        canvas.height = 1;
        return canvas;
    }

    canvas.width = w;
    canvas.height = h;

    // Ensure parameters are valid numbers, providing defaults if not.
    const numVignetteStrength = Math.max(0, Math.min(1, Number(vignetteStrength))) || 0;
    const numBlurAmount = Math.max(0, Number(blurAmount)) || 0;
    const numSepiaTone = Math.max(0, Math.min(1, Number(sepiaTone))) || 0;
    const numTextureOpacity = Math.max(0, Math.min(1, Number(textureOpacity))) || 0;

    // 2. Apply image filters and draw the original image
    // The filter property allows applying CSS-like filters directly to the canvas context.
    // This creates the soft, vintage, dreamy base for our storybook effect.
    ctx.filter = `blur(${numBlurAmount}px) sepia(${numSepiaTone})`;
    ctx.drawImage(originalImg, 0, 0, w, h);
    // Reset the filter so it doesn't affect subsequent drawings (like the texture and border).
    ctx.filter = 'none';

    // 3. Add a paper/canvas texture overlay
    if (numTextureOpacity > 0) {
        // 'overlay' blend mode works well for adding texture without washing out the image.
        ctx.globalCompositeOperation = 'overlay';
        ctx.fillStyle = '#808080'; // A neutral gray is ideal for overlay blending.
        
        // Draw a large number of tiny, semi-transparent rectangles to simulate noise/texture.
        // The number of particles is proportional to the image area.
        const noiseAmount = (w * h) / 10;
        for (let i = 0; i < noiseAmount; i++) {
            const x = Math.random() * w;
            const y = Math.random() * h;
            // Vary the alpha for a more natural texture.
            const alpha = Math.random() * numTextureOpacity;
            ctx.globalAlpha = alpha;
            // Using 2x2 pixels gives a slightly coarser, more visible texture than 1x1.
            ctx.fillRect(x, y, 2, 2);
        }
        
        // Reset composite operation and alpha for the next steps.
        ctx.globalCompositeOperation = 'source-over';
        ctx.globalAlpha = 1.0;
    }

    // 4. Add a vignette effect (darker corners) to focus attention on the center
    if (numVignetteStrength > 0) {
        // Create a radial gradient from the center outwards.
        const gradient = ctx.createRadialGradient(
            w / 2, h / 2, Math.min(w, h) * 0.2, // Inner circle (transparent)
            w / 2, h / 2, Math.max(w, h) * 0.8  // Outer circle (dark)
        );
        gradient.addColorStop(0, 'rgba(0,0,0,0)');
        gradient.addColorStop(1, `rgba(0,0,0,${numVignetteStrength})`);
        
        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, w, h);
    }

    // 5. Add a decorative border based on the selected style
    const borderColor = 'rgba(50, 40, 30, 0.75)'; // A dark, slightly transparent brown
    
    switch (borderStyle) {
        case 'simple': {
            const borderWidth = Math.min(w, h) * 0.03;
            ctx.strokeStyle = borderColor;
            
            // Outer thin line
            ctx.lineWidth = Math.max(1, borderWidth * 0.1);
            const outerMargin = borderWidth * 0.5;
            ctx.strokeRect(outerMargin, outerMargin, w - outerMargin * 2, h - outerMargin * 2);
            
            // Inner thick line
            ctx.lineWidth = Math.max(1, borderWidth * 0.3);
            const innerMargin = borderWidth;
            ctx.strokeRect(innerMargin, innerMargin, w - innerMargin * 2, h - innerMargin * 2);
            break;
        }
        case 'ornate': {
            const padding = Math.min(w, h) * 0.04;
            const fontSize = Math.max(12, padding * 0.9);
            const ornament = '❦'; // Unicode: FLORAL HEART (a nice storybook-style character)
            
            ctx.fillStyle = borderColor;
            ctx.font = `${fontSize}px Georgia, serif`; // Use a common, web-safe serif font
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            
            // Draw corner ornaments
            ctx.fillText(ornament, padding, padding); // Top-left
            ctx.fillText(ornament, w - padding, padding); // Top-right
            ctx.fillText(ornament, padding, h - padding); // Bottom-left
            ctx.fillText(ornament, w - padding, h - padding); // Bottom-right
            
            // Draw connecting lines for the frame
            ctx.strokeStyle = borderColor;
            ctx.lineWidth = Math.max(1, fontSize * 0.03);
            const lineOffset = fontSize * 0.5; // Offset to not draw over the ornament center

            ctx.beginPath();
            // Top line
            ctx.moveTo(padding + lineOffset, padding);
            ctx.lineTo(w - padding - lineOffset, padding);
            // Right line
            ctx.moveTo(w - padding, padding + lineOffset);
            ctx.lineTo(w - padding, h - padding - lineOffset);
            // Bottom line
            ctx.moveTo(padding + lineOffset, h - padding);
            ctx.lineTo(w - padding - lineOffset, h - padding);
            // Left line
            ctx.moveTo(padding, padding + lineOffset);
            ctx.lineTo(padding, h - padding - lineOffset);
            ctx.stroke();
            break;
        }
        case 'none':
        default:
            // Do nothing for 'none' or unknown styles
            break;
    }

    // 6. Return the final canvas element, which can be appended to the DOM.
    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 Image Storybook Creator is an online tool designed to enhance and transform images into a storybook-like aesthetic. Users can apply various artistic effects such as blur, sepia tone, and texture overlays to create a dreamy, vintage atmosphere. Additionally, the tool offers customization options for vignette strength to focus attention on the center of the image and decorative borders in different styles, enhancing the overall presentation. This tool is ideal for creating visually appealing graphics for children’s books, invitations, or any project where a whimsical touch is desired.

Leave a Reply

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