Please bookmark this page to avoid losing your image tool!

Acer Image Viewer

(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, initialZoom = "fit", bgColor = "#111111") {
    // Main Container
    const container = document.createElement("div");
    container.style.position = "relative";
    container.style.width = "100%";
    container.style.height = "100%";
    container.style.minHeight = "500px";
    container.style.backgroundColor = bgColor;
    container.style.overflow = "hidden";
    container.style.fontFamily = "Arial, sans-serif";
    container.style.display = "flex";
    container.style.flexDirection = "column";
    container.style.borderRadius = "8px";
    container.style.boxShadow = "inset 0 0 30px rgba(0,0,0,0.8)";
    container.style.userSelect = "none";

    // Acer Branding
    const brandContainer = document.createElement("div");
    brandContainer.style.position = "absolute";
    brandContainer.style.top = "15px";
    brandContainer.style.left = "20px";
    brandContainer.style.zIndex = "10";
    brandContainer.style.pointerEvents = "none";
    brandContainer.innerHTML = `
        <span style="color:#82b440; font-weight: 800; font-size: 24px; font-family: 'Arial Black', sans-serif; letter-spacing: -1.5px; text-transform: lowercase; text-shadow: 0 2px 4px rgba(0,0,0,0.5);">acer</span> 
        <span style="color: #ffffff; font-weight: 300; font-size: 14px; opacity: 0.8; margin-left: 8px; text-shadow: 0 1px 3px rgba(0,0,0,0.5);">Image Viewer</span>
    `;
    container.appendChild(brandContainer);

    // Canvas
    const canvas = document.createElement("canvas");
    canvas.style.flex = "1";
    canvas.style.display = "block";
    canvas.style.cursor = "grab";
    canvas.style.width = "100%";
    canvas.style.height = "100%";
    container.appendChild(canvas);

    const ctx = canvas.getContext("2d", { alpha: false });

    // Viewer State variables
    let scale = 1;
    let offsetX = 0;
    let offsetY = 0;
    let rotation = 0;
    let isDragging = false;
    let dragStartX = 0;
    let dragStartY = 0;
    let initDone = false;

    // Helper: Reset view bounds
    const resetView = (mode = initialZoom) => {
        if (canvas.width === 0 || canvas.height === 0 || !originalImg.width) return;
        
        // Handle rotation bounding boxes
        const isRotated = (rotation % 180 !== 0);
        const imgW = isRotated ? originalImg.height : originalImg.width;
        const imgH = isRotated ? originalImg.width : originalImg.height;

        const maxFitScale = Math.min(canvas.width / imgW, canvas.height / imgH) * 0.95;
        
        offsetX = canvas.width / 2;
        offsetY = canvas.height / 2;

        if (mode === "1:1") {
            scale = 1;
        } else if (mode === "fill") {
            scale = Math.max(canvas.width / imgW, canvas.height / imgH);
        } else {
            scale = maxFitScale;
        }
        
        draw();
    };

    // Render original scale layout
    const draw = () => {
        if (!originalImg.width) return; // Prevent draw if image isn't loaded completely
        
        // Clear with background color instead of transparent
        ctx.fillStyle = bgColor;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        
        ctx.save();
        ctx.translate(offsetX, offsetY);
        ctx.rotate(rotation * Math.PI / 180);
        ctx.scale(scale, scale);
        
        // Quality rendering
        ctx.imageSmoothingEnabled = true;
        ctx.imageSmoothingQuality = "high";
        
        ctx.drawImage(originalImg, -originalImg.width / 2, -originalImg.height / 2);
        ctx.restore();
    };

    // Observers & Init
    const resizeObserver = new ResizeObserver(entries => {
        for (let entry of entries) {
            const rect = entry.contentRect;
            canvas.width = rect.width;
            canvas.height = rect.height;
            if (!initDone && originalImg.width) {
                resetView();
                initDone = true;
            } else {
                draw();
            }
        }
    });
    resizeObserver.observe(container);

    if (!originalImg.complete) {
        originalImg.addEventListener('load', () => {
            if (canvas.width > 0) resetView();
        });
    }

    // Interactivity: Drag & Pan
    canvas.addEventListener("pointerdown", (e) => {
        isDragging = true;
        canvas.setPointerCapture(e.pointerId);
        dragStartX = e.clientX - offsetX;
        dragStartY = e.clientY - offsetY;
        canvas.style.cursor = "grabbing";
    });

    canvas.addEventListener("pointermove", (e) => {
        if (!isDragging) return;
        offsetX = e.clientX - dragStartX;
        offsetY = e.clientY - dragStartY;
        draw();
    });

    canvas.addEventListener("pointerup", (e) => {
        if(isDragging) {
            isDragging = false;
            canvas.releasePointerCapture(e.pointerId);
            canvas.style.cursor = "grab";
        }
    });

    // Interactivity: Wheel Zoom (Centered on Pointer)
    canvas.addEventListener("wheel", (e) => {
        e.preventDefault();
        
        // Differentiate line vs pixel scrolling (trackpad vs mouse wheel)
        const zoomIntensity = e.deltaMode === 1 ? 0.05 : 0.002;
        const zoomFactor = Math.exp(-e.deltaY * zoomIntensity);
        
        const rect = canvas.getBoundingClientRect();
        const mouseX = e.clientX - rect.left;
        const mouseY = e.clientY - rect.top;

        let newScale = scale * zoomFactor;
        newScale = Math.max(0.01, Math.min(newScale, 100)); // Limits to prevent glitch

        const ratio = newScale / scale;
        const dx = mouseX - offsetX;
        const dy = mouseY - offsetY;

        offsetX = mouseX - dx * ratio;
        offsetY = mouseY - dy * ratio;
        scale = newScale;

        draw();
    }, { passive: false });

    // Double tap to quick-reset fit
    canvas.addEventListener("dblclick", () => resetView("fit"));

    // UI Overlay (Toolbar Toolbar)
    const toolbar = document.createElement("div");
    toolbar.style.position = "absolute";
    toolbar.style.bottom = "25px";
    toolbar.style.left = "50%";
    toolbar.style.transform = "translateX(-50%)";
    toolbar.style.display = "flex";
    toolbar.style.gap = "4px";
    toolbar.style.padding = "6px 12px";
    toolbar.style.backgroundColor = "rgba(40, 40, 40, 0.75)";
    toolbar.style.backdropFilter = "blur(8px)";
    toolbar.style.webkitBackdropFilter = "blur(8px)";
    toolbar.style.borderRadius = "30px";
    toolbar.style.boxShadow = "0 8px 32px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.1)";
    toolbar.style.zIndex = "10";

    const createBtn = (htmlIcon, title, onClick) => {
        const btn = document.createElement("button");
        btn.innerHTML = htmlIcon;
        btn.title = title;
        btn.style.width = "38px";
        btn.style.height = "38px";
        btn.style.display = "flex";
        btn.style.alignItems = "center";
        btn.style.justifyContent = "center";
        btn.style.backgroundColor = "transparent";
        btn.style.color = "#eaeaea";
        btn.style.border = "none";
        btn.style.borderRadius = "50%";
        btn.style.cursor = "pointer";
        btn.style.fontSize = "16px";
        btn.style.transition = "all 0.15s ease";
        btn.style.outline = "none";
        
        btn.onmouseover = () => {
            btn.style.backgroundColor = "rgba(130, 180, 64, 0.4)"; 
            btn.style.color = "#82b440"; // Acer vibrant green highlight
        };
        btn.onmouseout = () => {
            btn.style.backgroundColor = "transparent";
            btn.style.color = "#eaeaea";
        };
        btn.onmousedown = () => btn.style.transform = "scale(0.9)";
        btn.onmouseup = () => btn.style.transform = "scale(1)";
        
        btn.onclick = onClick;
        return btn;
    };

    // Zoom Out
    toolbar.appendChild(createBtn(
        '<b style="font-size:24px; font-weight: 400; line-height: 0;">-</b>', 
        "Zoom Out", 
        () => { 
            scale = Math.max(0.01, scale * 0.8); 
            draw(); 
        }
    ));

    // Zoom In
    toolbar.appendChild(createBtn(
        '<b style="font-size:22px; font-weight: 400; line-height: 0;">+</b>', 
        "Zoom In", 
        () => { 
            scale = Math.min(100, scale * 1.25); 
            draw(); 
        }
    ));

    // Separator line
    const sep1 = document.createElement("div");
    sep1.style.width = "1px";
    sep1.style.backgroundColor = "rgba(255,255,255,0.1)";
    sep1.style.margin = "4px";
    toolbar.appendChild(sep1);

    // Fit View
    toolbar.appendChild(createBtn(
        '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" y1="3" x2="14" y2="10"></line><line x1="3" y1="21" x2="10" y2="14"></line></svg>', 
        "Fit View", 
        () => resetView("fit")
    ));

    // Custom 1:1 Pixel Mapping
    toolbar.appendChild(createBtn(
        '<b style="font-size:12px; font-family: monospace;">1:1</b>', 
        "Original Size", 
        () => resetView("1:1")
    ));

    // Separator line
    const sep2 = document.createElement("div");
    sep2.style.width = "1px";
    sep2.style.backgroundColor = "rgba(255,255,255,0.1)";
    sep2.style.margin = "4px";
    toolbar.appendChild(sep2);

    // Rotate
    toolbar.appendChild(createBtn(
        '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12a10 10 0 1 1 10 10 10 10 0 0 1-10-10"></path><path d="M12 2v10"></path></svg>', 
        "Rotate 90°", 
        () => { 
            rotation = (rotation + 90) % 360; 
            resetView("fit"); 
        }
    ));

    container.appendChild(toolbar);

    return container;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

Acer Image Viewer is an interactive image viewing tool that allows users to inspect images with high precision. The tool features smooth zooming capabilities via mouse wheel or toolbar buttons, panning through images by clicking and dragging, and a rotation feature to adjust the image orientation. Users can quickly reset their view to fit the screen or view the image at its original 1:1 pixel scale. This tool is ideal for photographers, designers, or anyone needing to perform detailed visual inspections of high-resolution images.

Leave a Reply

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