Please bookmark this page to avoid losing your image tool!

Icon To TV Image Converter

(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, tvColor = "#ce4a33", tubeColor = "#111811", crtIntensity = 1) {
    const origW = originalImg.width;
    const origH = originalImg.height;

    // Scale up small images (like icons) so the TV detail is always visible
    let scale = 1;
    const maxDim = Math.max(origW, origH);
    if (maxDim < 256) {
        scale = 256 / maxDim;
    }

    const cw = Math.round(origW * scale);
    const ch = Math.round(origH * scale);

    // Calculate a base unit for styling proportions relative to the screen size
    const u = Math.max(cw, ch) * 0.08;

    // Define layout logic
    const tvOuterX = Math.ceil(u);
    const tvOuterY = Math.ceil(u * 2.5);
    const screenW = cw;
    const screenH = ch;
    const tvInnerX = tvOuterX + u;
    const tvInnerY = tvOuterY + u;
    
    // Width = inner padding left (1u) + screen (cw) + control panel margin & space (3.5u)
    const tvOuterWidth = screenW + u * 4.5;
    // Height = inner padding top (1u) + screen (ch) + inner padding bottom (1u)
    const tvOuterHeight = screenH + u * 2.0;

    // Final dimensions to accommodate shadow, legs, and antennas
    const finalW = Math.ceil(tvOuterWidth + u * 2.5);
    const finalH = Math.ceil(tvOuterHeight + u * 4.5);

    const canvas = document.createElement('canvas');
    canvas.width = finalW;
    canvas.height = finalH;
    const ctx = canvas.getContext('2d');

    // Utility path drawing function for rounded rectangles
    function drawRoundRect(c, x, y, w, h, r, fillStyle, strokeStyle, lineWidth) {
        c.beginPath();
        c.moveTo(x + r, y);
        c.lineTo(x + w - r, y);
        c.quadraticCurveTo(x + w, y, x + w, y + r);
        c.lineTo(x + w, y + h - r);
        c.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
        c.lineTo(x + r, y + h);
        c.quadraticCurveTo(x, y + h, x, y + h - r);
        c.lineTo(x, y + r);
        c.quadraticCurveTo(x, y, x + r, y);
        c.closePath();
        if (fillStyle) {
            c.fillStyle = fillStyle;
            c.fill();
        }
        if (strokeStyle) {
            if (lineWidth) c.lineWidth = lineWidth;
            c.strokeStyle = strokeStyle;
            c.stroke();
        }
    }

    // --- Draw TV Components from back to front ---

    // 1. Antennas
    const cx = tvOuterX + tvOuterWidth / 2;
    ctx.strokeStyle = '#a5a5a5';
    ctx.lineWidth = u * 0.15;
    ctx.lineCap = 'round';
    ctx.beginPath();
    // Base V
    ctx.moveTo(cx, tvOuterY);
    ctx.lineTo(cx - u * 2.2, tvOuterY - u * 1.8);
    ctx.moveTo(cx, tvOuterY);
    ctx.lineTo(cx + u * 2.2, tvOuterY - u * 1.8);
    ctx.stroke();
    
    // Antenna tips
    ctx.fillStyle = '#a5a5a5';
    ctx.beginPath();
    ctx.arc(cx - u * 2.2, tvOuterY - u * 1.8, u * 0.25, 0, Math.PI * 2);
    ctx.fill();
    ctx.beginPath();
    ctx.arc(cx + u * 2.2, tvOuterY - u * 1.8, u * 0.25, 0, Math.PI * 2);
    ctx.fill();

    // Antenna Base mounting
    drawRoundRect(ctx, cx - u * 0.6, tvOuterY - u * 0.3, u * 1.2, u * 0.6, u * 0.2, '#2a2a2a');

    // Enable shadows for the main body
    ctx.shadowColor = 'rgba(0, 0, 0, 0.4)';
    ctx.shadowBlur = u * 0.5;
    ctx.shadowOffsetY = u * 0.4;

    // 2. Legs
    ctx.fillStyle = '#222';
    // Left leg
    ctx.beginPath();
    ctx.moveTo(tvOuterX + u * 1.5, tvOuterY + tvOuterHeight - u * 0.5);
    ctx.lineTo(tvOuterX + u * 0.2, tvOuterY + tvOuterHeight + u * 1.2);
    ctx.lineTo(tvOuterX + u * 0.8, tvOuterY + tvOuterHeight + u * 1.2);
    ctx.lineTo(tvOuterX + u * 2.2, tvOuterY + tvOuterHeight - u * 0.5);
    ctx.fill();
    // Right leg
    ctx.beginPath();
    ctx.moveTo(tvOuterX + tvOuterWidth - u * 1.5, tvOuterY + tvOuterHeight - u * 0.5);
    ctx.lineTo(tvOuterX + tvOuterWidth - u * 0.2, tvOuterY + tvOuterHeight + u * 1.2);
    ctx.lineTo(tvOuterX + tvOuterWidth - u * 0.8, tvOuterY + tvOuterHeight + u * 1.2);
    ctx.lineTo(tvOuterX + tvOuterWidth - u * 2.2, tvOuterY + tvOuterHeight - u * 0.5);
    ctx.fill();

    // 3. TV Body Frame
    drawRoundRect(ctx, tvOuterX, tvOuterY, tvOuterWidth, tvOuterHeight, u * 0.5, tvColor);

    // Reset shadow for deeper flat shading
    ctx.shadowColor = 'transparent';

    // Highlight ridge around TV body
    drawRoundRect(ctx, tvOuterX + u * 0.1, tvOuterY + u * 0.1, tvOuterWidth - u * 0.2, tvOuterHeight - u * 0.2, u * 0.4, null, 'rgba(255,255,255,0.15)', u * 0.05);

    // 4. Screen Bezel & Recess
    const bezelX = tvInnerX - u * 0.4;
    const bezelY = tvInnerY - u * 0.4;
    const bezelW = screenW + u * 0.8;
    const bezelH = screenH + u * 0.8;
    drawRoundRect(ctx, bezelX, bezelY, bezelW, bezelH, u * 0.3, '#1a1a1a');
    drawRoundRect(ctx, bezelX + u * 0.1, bezelY + u * 0.1, bezelW - u * 0.2, bezelH - u * 0.2, u * 0.25, '#0d0d0d');

    // 5. Build Final Tube/Screen Content using an off-screen canvas
    const screenCanvas = document.createElement('canvas');
    screenCanvas.width = cw;
    screenCanvas.height = ch;
    const sCtx = screenCanvas.getContext('2d');

    // Base tube color
    sCtx.fillStyle = tubeColor;
    sCtx.fillRect(0, 0, cw, ch);

    // Draw the actual image
    sCtx.imageSmoothingEnabled = false; // preserve retro aesthetic for icons
    sCtx.drawImage(originalImg, 0, 0, cw, ch);

    if (crtIntensity > 0) {
        // CRT RGB Shift & Static Noise
        try {
            const shiftX = Math.max(1, Math.floor(cw * 0.005 * crtIntensity));
            const imgData = sCtx.getImageData(0, 0, cw, ch);
            const data = imgData.data;
            const tvData = new Uint8ClampedArray(data.length);

            for (let y = 0; y < ch; y++) {
                for (let x = 0; x < cw; x++) {
                    const idx = (y * cw + x) * 4;

                    const rX = Math.max(0, x - shiftX);
                    const rIdx = (y * cw + rX) * 4;
                    tvData[idx] = data[rIdx]; // R

                    tvData[idx + 1] = data[idx + 1]; // G

                    const bX = Math.min(cw - 1, x + shiftX);
                    const bIdx = (y * cw + bX) * 4;
                    tvData[idx + 2] = data[bIdx + 2]; // B

                    tvData[idx + 3] = data[idx + 3]; // A

                    // Static Noise
                    if (tvData[idx + 3] > 0) {
                        const noise = (Math.random() - 0.5) * 45 * crtIntensity;
                        tvData[idx] = Math.min(255, Math.max(0, tvData[idx] + noise));
                        tvData[idx + 1] = Math.min(255, Math.max(0, tvData[idx + 1] + noise));
                        tvData[idx + 2] = Math.min(255, Math.max(0, tvData[idx + 2] + noise));
                    }
                }
            }
            sCtx.putImageData(new ImageData(tvData, cw, ch), 0, 0);
        } catch (e) {
            console.warn("CORS issue: Advanced CRT RGB/Noise skipped.", e);
        }

        // Apply Scanlines and Vignette overlay directly
        sCtx.globalCompositeOperation = 'source-atop';
        
        // Scanlines
        sCtx.fillStyle = `rgba(0, 0, 0, ${0.15 + (0.1 * crtIntensity)})`;
        const lineH = Math.max(2, Math.floor(ch * 0.015));
        for (let y = 0; y < ch; y += lineH * 2) {
            sCtx.fillRect(0, y, cw, lineH);
        }

        // Vignette
        const gradient = sCtx.createRadialGradient(
            cw / 2, ch / 2, Math.min(cw, ch) * 0.4,
            cw / 2, ch / 2, Math.max(cw, ch) * 0.8
        );
        gradient.addColorStop(0, 'rgba(0,0,0,0)');
        gradient.addColorStop(1, `rgba(0,0,0,${0.6 * crtIntensity})`);
        sCtx.fillStyle = gradient;
        sCtx.fillRect(0, 0, cw, ch);
        
        sCtx.globalCompositeOperation = 'source-over';
    }

    // Mask bounds of the screen area to round the rigid corners of the canvas
    ctx.save();
    drawRoundRect(ctx, tvInnerX, tvInnerY, screenW, screenH, u * 0.2);
    ctx.clip();
    
    // Draw finalized screen logic
    ctx.drawImage(screenCanvas, tvInnerX, tvInnerY);

    // Dynamic Glass Reflection Over Screen
    ctx.fillStyle = 'rgba(255, 255, 255, 0.12)';
    ctx.beginPath();
    ctx.moveTo(tvInnerX - u, tvInnerY - u);
    ctx.lineTo(tvInnerX + screenW * 0.65, tvInnerY - u);
    ctx.lineTo(tvInnerX + screenW * 0.1, tvInnerY + screenH + u);
    ctx.lineTo(tvInnerX - u, tvInnerY + screenH + u);
    ctx.fill();
    ctx.restore();

    // 6. Right Side Control Panel
    const panelX = tvOuterX + u * 2 + screenW;
    const panelY = tvInnerY - u * 0.2;
    const panelW = u * 2.0;
    const panelH = screenH + u * 0.4;
    drawRoundRect(ctx, panelX, panelY, panelW, panelH, u * 0.2, '#2a2a2a');
    drawRoundRect(ctx, panelX - u * 0.05, panelY - u * 0.05, panelW + u * 0.1, panelH + u * 0.1, u * 0.25, null, '#444', u * 0.1);

    // Knobs Structure
    const knobR = panelW * 0.35;
    const knobX = panelX + panelW / 2;
    const topKnobY = panelY + panelW * 0.7;
    const bottomKnobY = topKnobY + panelW * 1.3;

    // Knob Maker Function
    function drawKnob(x, y, rotation) {
        ctx.fillStyle = '#111';
        ctx.beginPath();
        ctx.arc(x, y, knobR, 0, Math.PI * 2);
        ctx.fill();
        ctx.fillStyle = '#c7c7c7';
        ctx.beginPath();
        ctx.arc(x, y, knobR * 0.8, 0, Math.PI * 2);
        ctx.fill();
        // Dial gauge groove
        ctx.strokeStyle = '#111';
        ctx.lineWidth = Math.max(1, u * 0.1);
        ctx.lineCap = 'round';
        ctx.beginPath();
        ctx.moveTo(x, y);
        ctx.lineTo(x + Math.cos(rotation) * (knobR * 0.6), y + Math.sin(rotation) * (knobR * 0.6));
        ctx.stroke();
    }

    drawKnob(knobX, topKnobY, -Math.PI / 4);
    drawKnob(knobX, bottomKnobY, Math.PI / 6);

    // Speaker Grille lines below buttons
    const grilleStartY = bottomKnobY + panelW;
    const grilleSpacing = panelW * 0.18; // space evenly inside bottom panel layout
    const numGrilles = Math.floor((panelY + panelH - grilleStartY - panelW * 0.2) / grilleSpacing);
    ctx.fillStyle = '#111';
    for (let i = 0; i < numGrilles; i++) {
        drawRoundRect(ctx, panelX + panelW * 0.2, grilleStartY + i * grilleSpacing, panelW * 0.6, panelW * 0.08, panelW * 0.04, '#0d0d0d');
    }

    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 Icon To TV Image Converter transforms your images and icons into stylized, retro-themed illustrations of vintage television sets. The tool automatically frames your image within a classic TV body complete with antennas, knobs, and legs. It applies advanced CRT effects such as RGB color shifting, static noise, scanlines, and vignette overlays to recreate a nostalgic analog aesthetic. This tool is ideal for graphic designers, content creators, or hobbyists looking to create retro-style social media assets, unique profile pictures, or themed digital art.

Leave a Reply

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