Please bookmark this page to avoid losing your image tool!

Image Time Traveler’s Document 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.
function processImage(
    originalImg,
    sepiaLevel = 0.7,
    grainLevel = 20,
    vignetteLevel = 0.6,
    creaseLines = 3,
    stainPatches = 5,
    customText = "",
    textColor = "rgba(50,30,20,0.75)",
    textFont = "italic 18px 'Times New Roman', serif",
    textPlacement = "bottomRight"
) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    const w = originalImg.naturalWidth || originalImg.width;
    const h = originalImg.naturalHeight || originalImg.height;
    canvas.width = w;
    canvas.height = h;

    // Handle cases where image might not be loaded or is empty
    if (w === 0 || h === 0) {
        // console.warn("Image Time Traveler: Original image has zero width or height.");
        return canvas; // Return empty canvas matching original's potential dimensions
    }

    // 1. Draw original image
    ctx.drawImage(originalImg, 0, 0, w, h);

    // 2. Apply Sepia and Grain (Pixel manipulation)
    if (sepiaLevel > 0 || grainLevel > 0) {
        const imageData = ctx.getImageData(0, 0, w, h);
        const data = imageData.data;

        for (let i = 0; i < data.length; i += 4) {
            let r = data[i];
            let g = data[i + 1];
            let b = data[i + 2];

            // Apply Sepia
            if (sepiaLevel > 0) {
                const sr = 0.393 * r + 0.769 * g + 0.189 * b;
                const sg = 0.349 * r + 0.686 * g + 0.168 * b;
                const sb = 0.272 * r + 0.534 * g + 0.131 * b;

                // Blend current color with sepia color
                r = r * (1 - sepiaLevel) + sr * sepiaLevel;
                g = g * (1 - sepiaLevel) + sg * sepiaLevel;
                b = b * (1 - sepiaLevel) + sb * sepiaLevel;
            }

            // Apply Grain
            if (grainLevel > 0) {
                const grainAmount = (Math.random() - 0.5) * grainLevel;
                r += grainAmount;
                g += grainAmount;
                b += grainAmount;
            }

            // Clamp values
            data[i] = Math.max(0, Math.min(255, r));
            data[i + 1] = Math.max(0, Math.min(255, g));
            data[i + 2] = Math.max(0, Math.min(255, b));
        }
        ctx.putImageData(imageData, 0, 0);
    }

    // 3. Draw Stain Patches
    if (stainPatches > 0) {
        for (let i = 0; i < stainPatches; i++) {
            const stainX = Math.random() * w;
            const stainY = Math.random() * h;
            const baseStainRadius = (Math.random() * 0.08 + 0.05) * Math.min(w, h); // 5-13% of min dimension

            const numSplotches = Math.floor(Math.random() * 3) + 2; // 2 to 4 splotches
            for (let k = 0; k < numSplotches; k++) { 
                const offsetX = (Math.random() - 0.5) * baseStainRadius * 1.5;
                const offsetY = (Math.random() - 0.5) * baseStainRadius * 1.5;
                const splotchRadius = baseStainRadius * (Math.random() * 0.6 + 0.4);
                
                const currentX = Math.max(0 - splotchRadius, Math.min(w + splotchRadius, stainX + offsetX)); 
                const currentY = Math.max(0 - splotchRadius, Math.min(h + splotchRadius, stainY + offsetY));
                
                ctx.beginPath();
                ctx.arc(currentX, currentY, splotchRadius, 0, Math.PI * 2);
                
                const R_stain = 120 + Math.random() * 60; 
                const G_stain = R_stain - (30 + Math.random() * 30); 
                const B_stain = G_stain - (40 + Math.random() * 30); 
                const alpha_stain = Math.random() * 0.06 + 0.02; 
                
                ctx.fillStyle = `rgba(${Math.floor(R_stain)}, ${Math.floor(G_stain)}, ${Math.floor(B_stain)}, ${alpha_stain})`;
                ctx.fill();
            }
        }
    }

    // 4. Draw Crease Lines
    if (creaseLines > 0) {
        for (let i = 0; i < creaseLines; i++) {
            let x1, y1, x2, y2;
            const type = Math.random();
            
            if (type < 0.4) { // Primarily horizontal crease
                y1 = Math.random() * h;
                y2 = y1 + (Math.random() - 0.5) * (h * 0.1); 
                x1 = Math.random() * w * 0.2; 
                x2 = w - (Math.random() * w * 0.2); 
                if (Math.random() < 0.5) { [x1,x2] = [x2,x1]; }
            } else if (type < 0.8) { // Primarily vertical crease
                x1 = Math.random() * w;
                x2 = x1 + (Math.random() - 0.5) * (w * 0.1); 
                y1 = Math.random() * h * 0.2; 
                y2 = h - (Math.random() * h * 0.2); 
                if (Math.random() < 0.5) { [y1,y2] = [y2,y1]; }
            } else { // Diagonal crease
                const lengthFactor = Math.min(w,h) * (0.7 + Math.random() * 0.5);
                const angle = Math.random() * Math.PI * 2;
                x1 = Math.random() * w;
                y1 = Math.random() * h;
                x2 = x1 + Math.cos(angle) * lengthFactor;
                y2 = y1 + Math.sin(angle) * lengthFactor;
            }

            ctx.strokeStyle = `rgba(0, 0, 0, ${Math.random() * 0.18 + 0.08})`; 
            ctx.lineWidth = Math.random() * 1.2 + 0.4; 
            ctx.beginPath();
            ctx.moveTo(x1, y1);

            const midX = (x1 + x2) / 2;
            const midY = (y1 + y2) / 2;
            const lineLength = Math.sqrt((x2-x1)**2 + (y2-y1)**2);
            const crinkleMagnitude = lineLength * 0.05 * (Math.random() * 2); 
            
            const perpAngle = Math.atan2(y2-y1, x2-x1) + Math.PI/2;
            const cpX = midX + Math.cos(perpAngle) * crinkleMagnitude * (Math.random() - 0.5) * 2;
            const cpY = midY + Math.sin(perpAngle) * crinkleMagnitude * (Math.random() - 0.5) * 2;
            
            ctx.quadraticCurveTo(cpX, cpY, x2, y2);
            ctx.stroke();
        }
    }
    
    // 5. Draw Vignette
    if (vignetteLevel > 0) {
        const centerX = w / 2;
        const centerY = h / 2;
        
        const R_outer = Math.sqrt(centerX * centerX + centerY * centerY);
        const R_inner = Math.min(w, h) * (0.15 + Math.max(0, 1 - vignetteLevel) * 0.35); // Inner clear area inversely related to vignetteLevel strength

        const gradient = ctx.createRadialGradient(centerX, centerY, R_inner, centerX, centerY, R_outer);
        gradient.addColorStop(0, 'rgba(0,0,0,0)');
        gradient.addColorStop(0.7, `rgba(0,0,0,${vignetteLevel * 0.6})`); 
        gradient.addColorStop(1, `rgba(0,0,0,${vignetteLevel})`);
        
        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, w, h);
    }

    // 6. Draw Custom Text
    if (customText && String(customText).trim() !== "") {
        ctx.font = textFont;
        ctx.fillStyle = textColor;
        const padding = Math.max(10, Math.min(w, h) * 0.04);

        let x, y;
        const normalizedPlacement = String(textPlacement).toLowerCase();
        switch (normalizedPlacement) {
            case "topleft":
                ctx.textAlign = "left";
                ctx.textBaseline = "top";
                x = padding;
                y = padding;
                break;
            case "topright":
                ctx.textAlign = "right";
                ctx.textBaseline = "top";
                x = w - padding;
                y = padding;
                break;
            case "bottomleft":
                ctx.textAlign = "left";
                ctx.textBaseline = "bottom";
                x = padding;
                y = h - padding;
                break;
            case "center":
                ctx.textAlign = "center";
                ctx.textBaseline = "middle";
                x = w / 2;
                y = h / 2;
                break;
            case "bottomright":
            default:
                ctx.textAlign = "right";
                ctx.textBaseline = "bottom";
                x = w - padding;
                y = h - padding;
                break;
        }
        ctx.fillText(String(customText), x, y);
    }

    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 Time Traveler’s Document Creator is a versatile online tool designed to transform your images into nostalgic, vintage-style documents. This tool allows users to apply various effects including sepia toning, grain texture, and vignette borders to evoke a classic look reminiscent of old photographs. Additionally, users can create artificial stains and crease lines for an aged appearance, further enhancing the vintage feel. Custom text can also be added in various fonts and colors, making it suitable for personalizing invitations, creating artistic displays, or adding captions to cherished memories. This tool serves well for anyone looking to give their images a timeless aesthetic, whether for scrapbooking, social media posts, or digital art projects.

Leave a Reply

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

Other Image Tools:

Image Cyberpunk Corporate ID Creator

Image Time Period Authentication Creator

Viking Runestone Frame Image Creator

Image Vintage Arcade Cabinet Art Creator

Byzantine Mosaic Frame Creator

Image Fighting Game Character Select Screen Creator

Image UFO Encounter Documentation Creator

Image Fantasy Realm Map Creator

Image Interdimensional Travel Permit Creator

Image Mad Scientist’s Laboratory Notes Creator

Image Underground Resistance Flyer Creator

Image Retro Video Game Box Art Creator

Image Captain’s Naval Journal Creator

Image Renaissance Painting Frame Creator

Image Lost Civilization Artifact Creator

Image Da Vinci Notebook Page Creator

Image Dystopian Citizen ID Creator

Image Monster Hunter Bestiary Creator

Image Vintage Carnival Sideshow Poster Creator

Image Space Explorer’s Log Creator

Image Neolithic Petroglyph Frame Creator

Image Ukiyo-e Japanese Woodblock Print Creator

Image Persian Miniature Painting Creator

Image Sci-Fi Movie Poster Template Creator

Image Horror Movie Poster Template

Image Social Media Milestone Certificate Creator

Halloween Death Certificate Template

Image Anatomical Illustration Frame Creator

Image Romance Novel Cover Template Creator

Image Tabloid Headline Template

Image Space Mission Patch Template Creator

Image Cassette Tape Cover Template Creator

Image Passport Page Template Generator

Image Old Map Frame With Compass Rose Decorator

Image Diploma and Degree Certificate Framer

Image Soviet Propaganda Poster Style Generator

See All →