{"id":49,"date":"2026-07-01T12:12:17","date_gmt":"2026-07-01T12:12:17","guid":{"rendered":"https:\/\/freewebtools.co.in\/?page_id=49"},"modified":"2026-07-16T16:50:36","modified_gmt":"2026-07-16T16:50:36","slug":"image-compressor","status":"publish","type":"page","link":"https:\/\/freewebtools.co.in\/index.php\/image-compressor\/","title":{"rendered":"Image Compressor"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>SaaS Premium Image Compressor<\/title>\n    <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jszip\/3.10.1\/jszip.min.js\"><\/script>\n    <style>\n        \/* CSS VARIABLES - Highly namespaced to prevent any WordPress host theme pollution *\/\n        :root {\n            --imgc-bg: #fdfdfd;\n            --imgc-surface: #ffffff;\n            --imgc-surface-hover: #fafafa;\n            --imgc-border: #e4e4e7;\n            --imgc-text-main: #09090b;\n            --imgc-text-muted: #71717a;\n            --imgc-primary: #2563eb;\n            --imgc-primary-hover: #1d4ed8;\n            --imgc-accent: #8b5cf6;\n            --imgc-success: #10b981;\n            --imgc-error: #ef4444;\n            --imgc-shadow-sm: 0 1px 3px rgba(0,0,0,0.05);\n            --imgc-shadow-md: 0 4px 12px rgba(0,0,0,0.05);\n            --imgc-shadow-lg: 0 12px 24px rgba(0,0,0,0.08);\n            --imgc-radius-sm: 8px;\n            --imgc-radius-md: 12px;\n            --imgc-radius-lg: 18px;\n            --imgc-transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n        }\n\n        \/* Scope wrapper for everything *\/\n        .imgc-scope {\n            font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n            background-color: var(--imgc-bg);\n            color: var(--imgc-text-main);\n            min-height: 100vh;\n            padding: 2.5rem 1.5rem;\n            box-sizing: border-box;\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n        }\n\n        .imgc-scope * {\n            box-sizing: border-box;\n            margin: 0;\n            padding: 0;\n        }\n\n        \/* Base Typography & Container *\/\n        .imgc-container {\n            width: 100%;\n            max-width: 1200px;\n            display: flex;\n            flex-direction: column;\n            gap: 2rem;\n        }\n\n        .imgc-header {\n            text-align: center;\n            margin-bottom: 0.5rem;\n        }\n\n        .imgc-header h1 {\n            font-size: 2.25rem;\n            font-weight: 800;\n            letter-spacing: -0.03em;\n            color: var(--imgc-text-main);\n            margin-bottom: 0.5rem;\n        }\n\n        .imgc-header p {\n            font-size: 1rem;\n            color: var(--imgc-text-muted);\n            max-width: 600px;\n            margin: 0 auto;\n        }\n\n        \/* Grid Layout split *\/\n        .imgc-workspace {\n            display: grid;\n            grid-template-columns: 1fr;\n            gap: 2rem;\n        }\n\n        @media (min-width: 992px) {\n            .imgc-workspace {\n                grid-template-columns: 1.1fr 0.9fr;\n                align-items: start;\n            }\n        }\n\n        \/* Cards and Elements *\/\n        .imgc-card {\n            background: var(--imgc-surface);\n            border: 1px solid var(--imgc-border);\n            border-radius: var(--imgc-radius-lg);\n            padding: 1.75rem;\n            box-shadow: var(--imgc-shadow-md);\n            transition: var(--imgc-transition);\n        }\n\n        .imgc-card:hover {\n            box-shadow: var(--imgc-shadow-lg);\n        }\n\n        .imgc-section-title {\n            font-size: 1.125rem;\n            font-weight: 700;\n            margin-bottom: 1.25rem;\n            display: flex;\n            align-items: center;\n            gap: 0.5rem;\n            border-bottom: 1px solid var(--imgc-border);\n            padding-bottom: 0.75rem;\n        }\n\n        \/* Upload Dropzone Container *\/\n        .imgc-dropzone {\n            border: 2px dashed var(--imgc-border);\n            border-radius: var(--imgc-radius-md);\n            background: var(--imgc-surface);\n            padding: 3rem 1.5rem;\n            text-align: center;\n            cursor: pointer;\n            position: relative;\n            transition: var(--imgc-transition);\n        }\n\n        .imgc-dropzone:hover, .imgc-dropzone.imgc-dragover {\n            border-color: var(--imgc-primary);\n            background: rgba(37, 99, 235, 0.02);\n        }\n\n        .imgc-dropzone-icon {\n            width: 56px;\n            height: 56px;\n            margin: 0 auto 1rem;\n            color: var(--imgc-primary);\n            transition: var(--imgc-transition);\n        }\n\n        .imgc-dropzone:hover .imgc-dropzone-icon {\n            transform: translateY(-4px);\n        }\n\n        .imgc-dropzone h3 {\n            font-size: 1.125rem;\n            font-weight: 700;\n            margin-bottom: 0.25rem;\n        }\n\n        .imgc-dropzone p {\n            font-size: 0.875rem;\n            color: var(--imgc-text-muted);\n            margin-bottom: 1rem;\n        }\n\n        .imgc-file-input {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            opacity: 0;\n            cursor: pointer;\n        }\n\n        \/* Control Fields styling *\/\n        .imgc-group {\n            margin-bottom: 1.25rem;\n        }\n\n        .imgc-group label {\n            display: block;\n            font-size: 0.8125rem;\n            font-weight: 600;\n            color: var(--imgc-text-main);\n            margin-bottom: 0.5rem;\n            text-transform: uppercase;\n            letter-spacing: 0.05em;\n        }\n\n        .imgc-preset-grid {\n            display: grid;\n            grid-template-columns: repeat(4, 1fr);\n            gap: 0.5rem;\n            margin-bottom: 1rem;\n        }\n\n        .imgc-preset-btn {\n            background: var(--imgc-bg);\n            border: 1px solid var(--imgc-border);\n            border-radius: var(--imgc-radius-sm);\n            padding: 0.5rem;\n            font-size: 0.75rem;\n            font-weight: 600;\n            cursor: pointer;\n            transition: var(--imgc-transition);\n            text-align: center;\n        }\n\n        .imgc-preset-btn:hover, .imgc-preset-btn.imgc-active {\n            background: var(--imgc-primary);\n            border-color: var(--imgc-primary);\n            color: #ffffff;\n        }\n\n        .imgc-range-box {\n            display: flex;\n            align-items: center;\n            gap: 1rem;\n        }\n\n        .imgc-slider {\n            flex-grow: 1;\n            height: 6px;\n            background: var(--imgc-border);\n            border-radius: 3px;\n            outline: none;\n            -webkit-appearance: none;\n        }\n\n        .imgc-slider::-webkit-slider-thumb {\n            -webkit-appearance: none;\n            width: 18px;\n            height: 18px;\n            border-radius: 50%;\n            background: var(--imgc-primary);\n            cursor: pointer;\n            transition: var(--imgc-transition);\n        }\n\n        .imgc-slider-val {\n            font-size: 0.875rem;\n            font-weight: 700;\n            min-width: 3rem;\n            text-align: right;\n        }\n\n        .imgc-input-grid {\n            display: grid;\n            grid-template-columns: 1fr 1fr;\n            gap: 0.75rem;\n        }\n\n        .imgc-input {\n            width: 100%;\n            padding: 0.625rem 0.75rem;\n            border: 1px solid var(--imgc-border);\n            border-radius: var(--imgc-radius-sm);\n            font-size: 0.875rem;\n            outline: none;\n            transition: var(--imgc-transition);\n        }\n\n        .imgc-input:focus {\n            border-color: var(--imgc-primary);\n            box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);\n        }\n\n        .imgc-select {\n            width: 100%;\n            padding: 0.625rem 0.75rem;\n            border: 1px solid var(--imgc-border);\n            border-radius: var(--imgc-radius-sm);\n            font-size: 0.875rem;\n            outline: none;\n            background: var(--imgc-surface);\n            transition: var(--imgc-transition);\n            cursor: pointer;\n        }\n\n        \/* Checkbox switch wrapper *\/\n        .imgc-switch {\n            display: flex;\n            align-items: center;\n            justify-content: space-between;\n            padding: 0.5rem 0;\n        }\n\n        .imgc-switch-lbl {\n            font-size: 0.875rem;\n            font-weight: 500;\n        }\n\n        \/* Simple Action Buttons *\/\n        .imgc-btn {\n            display: inline-flex;\n            align-items: center;\n            justify-content: center;\n            gap: 0.5rem;\n            padding: 0.75rem 1.25rem;\n            font-size: 0.875rem;\n            font-weight: 600;\n            border-radius: var(--imgc-radius-sm);\n            border: 1px solid transparent;\n            cursor: pointer;\n            transition: var(--imgc-transition);\n            text-decoration: none;\n        }\n\n        .imgc-btn-primary {\n            background: var(--imgc-primary);\n            color: #ffffff;\n        }\n\n        .imgc-btn-primary:hover {\n            background: var(--imgc-primary-hover);\n        }\n\n        .imgc-btn-secondary {\n            background: var(--imgc-surface);\n            border-color: var(--imgc-border);\n            color: var(--imgc-text-main);\n        }\n\n        .imgc-btn-secondary:hover {\n            background: var(--imgc-surface-hover);\n        }\n\n        .imgc-btn-danger {\n            background: rgba(239, 68, 68, 0.08);\n            border-color: transparent;\n            color: var(--imgc-error);\n        }\n\n        .imgc-btn-danger:hover {\n            background: var(--imgc-error);\n            color: #ffffff;\n        }\n\n        \/* Batch \/ Single Image Queue item styling *\/\n        .imgc-queue-list {\n            display: flex;\n            flex-direction: column;\n            gap: 0.75rem;\n            margin-top: 1.25rem;\n            max-height: 400px;\n            overflow-y: auto;\n            padding-right: 0.25rem;\n        }\n\n        .imgc-queue-item {\n            display: flex;\n            align-items: center;\n            justify-content: space-between;\n            background: var(--imgc-surface);\n            border: 1px solid var(--imgc-border);\n            border-radius: var(--imgc-radius-md);\n            padding: 0.75rem 1rem;\n            gap: 1rem;\n            transition: var(--imgc-transition);\n            cursor: pointer;\n            position: relative;\n        }\n\n        .imgc-queue-item.imgc-selected {\n            border-color: var(--imgc-primary);\n            background: rgba(37, 99, 235, 0.01);\n        }\n\n        .imgc-queue-item-meta {\n            display: flex;\n            align-items: center;\n            gap: 0.75rem;\n            flex-grow: 1;\n            overflow: hidden;\n        }\n\n        .imgc-queue-thumb {\n            width: 48px;\n            height: 48px;\n            border-radius: var(--imgc-radius-sm);\n            object-fit: cover;\n            border: 1px solid var(--imgc-border);\n            background: #eee;\n        }\n\n        .imgc-queue-info {\n            overflow: hidden;\n            display: flex;\n            flex-direction: column;\n            gap: 0.125rem;\n        }\n\n        .imgc-queue-name {\n            font-size: 0.8125rem;\n            font-weight: 700;\n            white-space: nowrap;\n            overflow: hidden;\n            text-overflow: ellipsis;\n        }\n\n        .imgc-queue-sizes {\n            font-size: 0.75rem;\n            color: var(--imgc-text-muted);\n            display: flex;\n            align-items: center;\n            gap: 0.5rem;\n        }\n\n        .imgc-saving-badge {\n            font-size: 0.6875rem;\n            font-weight: 700;\n            padding: 0.125rem 0.375rem;\n            border-radius: 4px;\n            background: rgba(16, 185, 129, 0.1);\n            color: var(--imgc-success);\n        }\n\n        .imgc-queue-actions {\n            display: flex;\n            align-items: center;\n            gap: 0.375rem;\n        }\n\n        .imgc-small-btn {\n            background: transparent;\n            border: none;\n            width: 28px;\n            height: 28px;\n            border-radius: 50%;\n            cursor: pointer;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            color: var(--imgc-text-muted);\n            transition: var(--imgc-transition);\n        }\n\n        .imgc-small-btn:hover {\n            background: rgba(0,0,0,0.05);\n            color: var(--imgc-text-main);\n        }\n\n        \/* Comparison Preview Slider *\/\n        .imgc-comparison-box {\n            position: relative;\n            width: 100%;\n            height: 380px;\n            background: #f1f5f9;\n            border-radius: var(--imgc-radius-md);\n            overflow: hidden;\n            user-select: none;\n            box-shadow: inset 0 0 10px rgba(0,0,0,0.05);\n            display: flex;\n            align-items: center;\n            justify-content: center;\n        }\n\n        .imgc-checkerboard {\n            background-color: #ffffff;\n            background-image: linear-gradient(45deg, #efefef 25%, transparent 25%),\n                              linear-gradient(-45deg, #efefef 25%, transparent 25%),\n                              linear-gradient(45deg, transparent 75%, #efefef 75%),\n                              linear-gradient(-45deg, transparent 75%, #efefef 75%);\n            background-size: 20px 20px;\n            background-position: 0 0, 0 10px, 10px -10px, -10px 0px;\n        }\n\n        .imgc-preview-img {\n            position: absolute;\n            height: 100%;\n            width: 100%;\n            object-fit: contain;\n            pointer-events: none;\n        }\n\n        .imgc-preview-before {\n            clip-path: polygon(0 0, 50% 0, 50% 100%, 0 100%);\n            z-index: 2;\n        }\n\n        .imgc-preview-after {\n            z-index: 1;\n        }\n\n        \/* Before\/After Split Line handle *\/\n        .imgc-compare-handle {\n            position: absolute;\n            top: 0;\n            bottom: 0;\n            left: 50%;\n            width: 3px;\n            background: #ffffff;\n            z-index: 3;\n            cursor: ew-resize;\n            box-shadow: 0 0 8px rgba(0,0,0,0.3);\n            pointer-events: auto;\n        }\n\n        .imgc-compare-handle::after {\n            content: '\u2194';\n            position: absolute;\n            top: 50%;\n            left: 50%;\n            transform: translate(-50%, -50%);\n            width: 32px;\n            height: 32px;\n            border-radius: 50%;\n            background: #ffffff;\n            border: 1px solid var(--imgc-border);\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            font-weight: 700;\n            color: var(--imgc-text-main);\n            box-shadow: var(--imgc-shadow-md);\n        }\n\n        .imgc-compare-tag {\n            position: absolute;\n            top: 1rem;\n            padding: 0.25rem 0.625rem;\n            border-radius: 4px;\n            font-size: 0.6875rem;\n            font-weight: 700;\n            background: rgba(0,0,0,0.7);\n            color: #ffffff;\n            z-index: 4;\n            pointer-events: none;\n        }\n\n        .imgc-compare-tag-before {\n            left: 1rem;\n        }\n\n        .imgc-compare-tag-after {\n            right: 1rem;\n        }\n\n        \/* Information Grid *\/\n        .imgc-info-grid {\n            display: grid;\n            grid-template-columns: repeat(2, 1fr);\n            gap: 1rem;\n            margin-top: 1.25rem;\n        }\n\n        .imgc-info-tile {\n            background: var(--imgc-bg);\n            border: 1px solid var(--imgc-border);\n            border-radius: var(--imgc-radius-sm);\n            padding: 0.75rem 1rem;\n        }\n\n        .imgc-tile-lbl {\n            font-size: 0.6875rem;\n            text-transform: uppercase;\n            letter-spacing: 0.05em;\n            color: var(--imgc-text-muted);\n            margin-bottom: 0.125rem;\n            font-weight: 600;\n        }\n\n        .imgc-tile-val {\n            font-size: 0.875rem;\n            font-weight: 700;\n            color: var(--imgc-text-main);\n        }\n\n        \/* System Messages Alerts *\/\n        .imgc-alert {\n            display: flex;\n            align-items: flex-start;\n            gap: 0.75rem;\n            padding: 1rem;\n            border-radius: var(--imgc-radius-md);\n            font-size: 0.875rem;\n            margin-top: 1rem;\n        }\n\n        .imgc-alert-error {\n            background: rgba(239, 68, 68, 0.05);\n            border: 1px solid rgba(239, 68, 68, 0.2);\n            color: var(--imgc-error);\n        }\n\n        \/* Hidden Helper *\/\n        .imgc-hidden {\n            display: none !important;\n        }\n\n        \/* Statistics Board *\/\n        .imgc-stats-container {\n            display: grid;\n            grid-template-columns: repeat(3, 1fr);\n            gap: 1rem;\n            margin-top: 1.5rem;\n            padding-top: 1.5rem;\n            border-top: 1px solid var(--imgc-border);\n        }\n\n        \/* Inline Spinners & Animations *\/\n        .imgc-spinner {\n            width: 18px;\n            height: 18px;\n            border: 2px solid rgba(0,0,0,0.1);\n            border-top-color: var(--imgc-primary);\n            border-radius: 50%;\n            animation: imgcSpin 0.7s linear infinite;\n        }\n\n        @keyframes imgcSpin {\n            to { transform: rotate(360deg); }\n        }\n\n        \/* Keyboard tags *\/\n        .imgc-kbd {\n            background: var(--imgc-bg);\n            border: 1px solid var(--imgc-border);\n            border-radius: 4px;\n            padding: 1px 5px;\n            font-size: 0.6875rem;\n            font-family: monospace;\n            font-weight: 600;\n        }\n\n        \/* Fullscreen View *\/\n        .imgc-fs-modal {\n            position: fixed;\n            top: 0; left: 0; right: 0; bottom: 0;\n            background: rgba(9, 9, 11, 0.95);\n            z-index: 9999;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            padding: 2rem;\n        }\n\n        .imgc-fs-img {\n            max-width: 100%;\n            max-height: 100%;\n            object-fit: contain;\n            border-radius: var(--imgc-radius-sm);\n        }\n\n        .imgc-fs-close {\n            position: absolute;\n            top: 1.5rem;\n            right: 1.5rem;\n            background: #ffffff;\n            border: none;\n            width: 40px;\n            height: 40px;\n            border-radius: 50%;\n            cursor: pointer;\n            font-size: 1.25rem;\n            font-weight: 700;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n        }\n    <\/style>\n<\/head>\n<body>\n\n<div class=\"imgc-scope\">\n    <div class=\"imgc-container\">\n        \n        <header class=\"imgc-header\">\n            <h1>Local Image Compressor Pro<\/h1>\n            <p>A premium compression platform functioning safely and offline entirely inside your browser. No server uploads.<\/p>\n        <\/header>\n\n        <div class=\"imgc-workspace\">\n            \n            <div style=\"display: flex; flex-direction: column; gap: 1.5rem;\">\n                \n                <div class=\"imgc-card\" style=\"padding: 1rem;\">\n                    <div class=\"imgc-dropzone\" id=\"imgc-dropzone-element\">\n                        <svg class=\"imgc-dropzone-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n                            <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\"><\/path>\n                        <\/svg>\n                        <h3>Drag &#038; drop multiple images<\/h3>\n                        <p>or click to select. Supports WebP, JPEG, PNG, BMP, and GIF.<\/p>\n                        <span class=\"imgc-kbd\">Ctrl + V<\/span> to paste clipboard image streams.\n                        <input type=\"file\" id=\"imgc-picker-element\" class=\"imgc-file-input\" multiple accept=\"image\/*\">\n                    <\/div>\n                <\/div>\n\n                <div class=\"imgc-card\">\n                    <h2 class=\"imgc-section-title\">\u2699\ufe0f Engine Configuration<\/h2>\n                    \n                    <div class=\"imgc-group\">\n                        <label>Target Quality Mode<\/label>\n                        <div class=\"imgc-preset-grid\">\n                            <button type=\"button\" class=\"imgc-preset-btn\" id=\"imgc-preset-max\">Max Size Redux<\/button>\n                            <button type=\"button\" class=\"imgc-preset-btn imgc-active\" id=\"imgc-preset-bal\">Balanced<\/button>\n                            <button type=\"button\" class=\"imgc-preset-btn\" id=\"imgc-preset-hq\">High Quality<\/button>\n                            <button type=\"button\" class=\"imgc-preset-btn\" id=\"imgc-preset-custom\">Custom<\/button>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"imgc-group\" id=\"imgc-quality-group\">\n                        <label>Output Compression Quality<\/label>\n                        <div class=\"imgc-range-box\">\n                            <input type=\"range\" id=\"imgc-quality-range\" class=\"imgc-slider\" min=\"1\" max=\"100\" value=\"75\">\n                            <span class=\"imgc-slider-val\" id=\"imgc-quality-val\">75%<\/span>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"imgc-group\">\n                        <label>Convert To Output Format<\/label>\n                        <select id=\"imgc-format-select\" class=\"imgc-select\">\n                            <option value=\"original\">Original Format (Match Input)<\/option>\n                            <option value=\"image\/jpeg\">JPEG (.jpg)<\/option>\n                            <option value=\"image\/png\">PNG (.png)<\/option>\n                            <option value=\"image\/webp\">WebP (.webp)<\/option>\n                        <\/select>\n                    <\/div>\n\n                    <div class=\"imgc-group\">\n                        <label>Output Dimensional Scaling<\/label>\n                        <div class=\"imgc-input-grid\">\n                            <input type=\"number\" id=\"imgc-scale-width\" class=\"imgc-input\" placeholder=\"Width Limit (px)\">\n                            <input type=\"number\" id=\"imgc-scale-height\" class=\"imgc-input\" placeholder=\"Height Limit (px)\">\n                        <\/div>\n                        <div style=\"display: flex; gap: 1rem; margin-top: 0.75rem;\">\n                            <label class=\"imgc-switch\" style=\"width: 100%; margin: 0;\">\n                                <span class=\"imgc-switch-lbl\">Maintain Aspect Ratio<\/span>\n                                <input type=\"checkbox\" id=\"imgc-keep-aspect\" checked>\n                            <\/label>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"imgc-group\" style=\"margin-bottom: 0;\">\n                        <label class=\"imgc-switch\">\n                            <span class=\"imgc-switch-lbl\">Target Specific Max File Size (KB)<\/span>\n                            <input type=\"checkbox\" id=\"imgc-target-toggle\">\n                        <\/label>\n                        <input type=\"number\" id=\"imgc-target-size\" class=\"imgc-input imgc-hidden\" placeholder=\"Target maximum weight (e.g. 150)\" style=\"margin-top: 0.5rem;\">\n                    <\/div>\n\n                    <div style=\"display: flex; gap: 1rem; margin-top: 0.75rem;\">\n                        <label class=\"imgc-switch\" style=\"width: 100%; margin: 0;\">\n                            <span class=\"imgc-switch-lbl\">Strip Metadata Structure<\/span>\n                            <input type=\"checkbox\" id=\"imgc-strip-metadata\" checked>\n                        <\/label>\n                    <\/div>\n\n                    <div style=\"display: flex; gap: 0.75rem; margin-top: 1.5rem;\">\n                        <button type=\"button\" class=\"imgc-btn imgc-btn-primary\" id=\"imgc-process-all-btn\" style=\"flex-grow: 1;\">\n                            \ud83d\ude80 Apply Settings &#038; Compress All\n                        <\/button>\n                        <button type=\"button\" class=\"imgc-btn imgc-btn-danger\" id=\"imgc-clear-queue-btn\" title=\"Empty Queue\">\n                            \ud83d\uddd1\ufe0f Reset\n                        <\/button>\n                    <\/div>\n                <\/div>\n\n                <div class=\"imgc-card\">\n                    <h2 class=\"imgc-section-title\">\ud83d\udcc2 Task Management Queue<\/h2>\n                    <div class=\"imgc-queue-list\" id=\"imgc-queue-target\">\n                        <div style=\"text-align: center; color: var(--imgc-text-muted); font-size: 0.8125rem; padding: 2rem 0;\">\n                            No files inside processing queue currently. Drop or choose assets above to commence.\n                        <\/div>\n                    <\/div>\n                    \n                    <div id=\"imgc-batch-download-wrap\" class=\"imgc-hidden\" style=\"margin-top: 1.25rem;\">\n                        <button class=\"imgc-btn imgc-btn-primary\" id=\"imgc-zip-btn\" style=\"width: 100%;\">\n                            \ud83d\udce6 Export All Decimated Assets (.zip)\n                        <\/button>\n                    <\/div>\n                <\/div>\n\n            <\/div>\n\n            <div style=\"display: flex; flex-direction: column; gap: 1.5rem;\">\n                \n                <div class=\"imgc-card\">\n                    <h2 class=\"imgc-section-title\" style=\"justify-content: space-between;\">\n                        <span>\u2696\ufe0f Direct Comparison Preview<\/span>\n                        <div style=\"display: flex; gap: 0.5rem;\">\n                            <button type=\"button\" class=\"imgc-kbd\" id=\"imgc-theme-toggle\" title=\"Light \/ Dark layout preview theme\">Toggle BG Theme<\/button>\n                            <button type=\"button\" class=\"imgc-kbd\" id=\"imgc-zoom-btn\" title=\"Toggle zoom lens modes\">Fullscreen<\/button>\n                        <\/div>\n                    <\/h2>\n\n                    <div class=\"imgc-comparison-box imgc-checkerboard\" id=\"imgc-preview-stage\">\n                        <span id=\"imgc-compare-instructions\" style=\"color: var(--imgc-text-muted); font-size: 0.8125rem;\">Select any queued target file underneath to display live before\/after differences.<\/span>\n                        \n                        <img id=\"imgc-img-before\" class=\"imgc-preview-img imgc-preview-before imgc-hidden\" alt=\"Before processing image asset\">\n                        <span class=\"imgc-compare-tag imgc-compare-tag-before imgc-hidden\" id=\"imgc-lbl-before\">BEFORE<\/span>\n\n                        <img id=\"imgc-img-after\" class=\"imgc-preview-img imgc-preview-after imgc-hidden\" alt=\"After processing image asset\">\n                        <span class=\"imgc-compare-tag imgc-compare-tag-after imgc-hidden\" id=\"imgc-lbl-after\">AFTER<\/span>\n\n                        <div class=\"imgc-compare-handle imgc-hidden\" id=\"imgc-handle-split\"><\/div>\n                    <\/div>\n\n                    <div class=\"imgc-info-grid\">\n                        <div class=\"imgc-info-tile\">\n                            <div class=\"imgc-tile-lbl\">Target Filename<\/div>\n                            <div class=\"imgc-tile-val\" id=\"imgc-info-filename\">&#8211;<\/div>\n                        <\/div>\n                        <div class=\"imgc-info-tile\">\n                            <div class=\"imgc-tile-lbl\">Dimensional Frame<\/div>\n                            <div class=\"imgc-tile-val\" id=\"imgc-info-dims\">&#8211;<\/div>\n                        <\/div>\n                        <div class=\"imgc-info-tile\">\n                            <div class=\"imgc-tile-lbl\">Input Footprint<\/div>\n                            <div class=\"imgc-tile-val\" id=\"imgc-info-input-size\">&#8211;<\/div>\n                        <\/div>\n                        <div class=\"imgc-info-tile\">\n                            <div class=\"imgc-tile-lbl\">Result footprint<\/div>\n                            <div class=\"imgc-tile-val\" id=\"imgc-info-output-size\">&#8211;<\/div>\n                        <\/div>\n                    <\/div>\n\n                    <div style=\"display: flex; gap: 0.75rem; margin-top: 1.25rem;\">\n                        <button type=\"button\" class=\"imgc-btn imgc-btn-primary\" id=\"imgc-single-dl-btn\" style=\"flex-grow: 1;\" disabled>\n                            \ud83d\udce5 Export Active Render Only\n                        <\/button>\n                        <button type=\"button\" class=\"imgc-btn imgc-btn-secondary\" id=\"imgc-info-copy-btn\" disabled>\n                            \ud83d\udccb Copy Info\n                        <\/button>\n                    <\/div>\n                <\/div>\n\n                <div class=\"imgc-card\">\n                    <h2 class=\"imgc-section-title\">\ud83d\udcca Batch Compression Statistics<\/h2>\n                    <div class=\"imgc-stats-container\">\n                        <div style=\"text-align: center;\">\n                            <div style=\"font-size: 0.75rem; color: var(--imgc-text-muted); font-weight: 600;\">FILES IN QUEUE<\/div>\n                            <div style=\"font-size: 1.5rem; font-weight: 800; margin-top: 0.25rem;\" id=\"imgc-stat-count\">0<\/div>\n                        <\/div>\n                        <div style=\"text-align: center;\">\n                            <div style=\"font-size: 0.75rem; color: var(--imgc-text-muted); font-weight: 600;\">ACCUMULATED SAVING<\/div>\n                            <div style=\"font-size: 1.5rem; font-weight: 800; margin-top: 0.25rem; color: var(--imgc-success);\" id=\"imgc-stat-savings\">0%<\/div>\n                        <\/div>\n                        <div style=\"text-align: center;\">\n                            <div style=\"font-size: 0.75rem; color: var(--imgc-text-muted); font-weight: 600;\">MEMORY RECLAIMED<\/div>\n                            <div style=\"font-size: 1.5rem; font-weight: 800; margin-top: 0.25rem;\" id=\"imgc-stat-reclaimed\">0 KB<\/div>\n                        <\/div>\n                    <\/div>\n                <\/div>\n\n                <div id=\"imgc-alert-wrap\" class=\"imgc-alert imgc-alert-error imgc-hidden\">\n                    <span id=\"imgc-alert-text\">Placeholder error string.<\/span>\n                <\/div>\n\n            <\/div>\n\n        <\/div>\n\n    <\/div>\n<\/div>\n\n<div id=\"imgc-portal-root\" class=\"imgc-fs-modal imgc-hidden\">\n    <button class=\"imgc-fs-close\" id=\"imgc-portal-close\">\u2715<\/button>\n    <img decoding=\"async\" id=\"imgc-portal-img\" class=\"imgc-fs-img\" src=\"\" alt=\"Zoomed view image\">\n<\/div>\n\n<script>\n(function() {\n    'use strict';\n\n    \/\/ Application Global Workspace Model State\n    const imgcState = {\n        filesList: [], \/\/ Array representing processing targets\n        selectedIndex: -1, \/\/ Currently rendered visual preview slot\n        presets: {\n            max: 30,\n            balanced: 70,\n            high: 90\n        },\n        compressingBatch: false,\n        themeCheckerboard: true\n    };\n\n    \/\/ Strict UI node declarations\n    const imgcNodes = {\n        picker: document.getElementById('imgc-picker-element'),\n        dropzone: document.getElementById('imgc-dropzone-element'),\n        queueTarget: document.getElementById('imgc-queue-target'),\n        presetMax: document.getElementById('imgc-preset-max'),\n        presetBal: document.getElementById('imgc-preset-bal'),\n        presetHq: document.getElementById('imgc-preset-hq'),\n        presetCustom: document.getElementById('imgc-preset-custom'),\n        qualityGroup: document.getElementById('imgc-quality-group'),\n        qualityRange: document.getElementById('imgc-quality-range'),\n        qualityVal: document.getElementById('imgc-quality-val'),\n        formatSelect: document.getElementById('imgc-format-select'),\n        scaleWidth: document.getElementById('imgc-scale-width'),\n        scaleHeight: document.getElementById('imgc-scale-height'),\n        keepAspect: document.getElementById('imgc-keep-aspect'),\n        targetToggle: document.getElementById('imgc-target-toggle'),\n        targetSize: document.getElementById('imgc-target-size'),\n        stripMetadata: document.getElementById('imgc-strip-metadata'),\n        processAllBtn: document.getElementById('imgc-process-all-btn'),\n        clearQueueBtn: document.getElementById('imgc-clear-queue-btn'),\n        batchDlWrap: document.getElementById('imgc-batch-download-wrap'),\n        zipBtn: document.getElementById('imgc-zip-btn'),\n        themeToggle: document.getElementById('imgc-theme-toggle'),\n        zoomBtn: document.getElementById('imgc-zoom-btn'),\n        previewStage: document.getElementById('imgc-preview-stage'),\n        instructions: document.getElementById('imgc-compare-instructions'),\n        imgBefore: document.getElementById('imgc-img-before'),\n        lblBefore: document.getElementById('imgc-lbl-before'),\n        imgAfter: document.getElementById('imgc-img-after'),\n        lblAfter: document.getElementById('imgc-lbl-after'),\n        handleSplit: document.getElementById('imgc-handle-split'),\n        infoFilename: document.getElementById('imgc-info-filename'),\n        infoDims: document.getElementById('imgc-info-dims'),\n        infoInputSize: document.getElementById('imgc-info-input-size'),\n        infoOutputSize: document.getElementById('imgc-info-output-size'),\n        singleDlBtn: document.getElementById('imgc-single-dl-btn'),\n        infoCopyBtn: document.getElementById('imgc-info-copy-btn'),\n        statCount: document.getElementById('imgc-stat-count'),\n        statSavings: document.getElementById('imgc-stat-savings'),\n        statReclaimed: document.getElementById('imgc-stat-reclaimed'),\n        alertWrap: document.getElementById('imgc-alert-wrap'),\n        alertText: document.getElementById('imgc-alert-text'),\n        portalRoot: document.getElementById('imgc-portal-root'),\n        portalClose: document.getElementById('imgc-portal-close'),\n        portalImg: document.getElementById('imgc-portal-img')\n    };\n\n    \/\/ Boot initialize process routine\n    function imgcBoot() {\n        imgcSetupEvents();\n        imgcSelectPreset('balanced');\n    }\n\n    \/\/ Attach local document handlers\n    function imgcSetupEvents() {\n        imgcNodes.picker.addEventListener('change', imgcHandleFileSelection);\n        imgcNodes.dropzone.addEventListener('dragover', (e) => { e.preventDefault(); imgcNodes.dropzone.classList.add('imgc-dragover'); });\n        imgcNodes.dropzone.addEventListener('dragleave', () => imgcNodes.dropzone.classList.remove('imgc-dragover'));\n        imgcNodes.dropzone.addEventListener('drop', imgcHandleDrop);\n        \n        \/\/ Preset clicks\n        imgcNodes.presetMax.addEventListener('click', () => imgcSelectPreset('max'));\n        imgcNodes.presetBal.addEventListener('click', () => imgcSelectPreset('balanced'));\n        imgcNodes.presetHq.addEventListener('click', () => imgcSelectPreset('high'));\n        imgcNodes.presetCustom.addEventListener('click', () => imgcSelectPreset('custom'));\n\n        \/\/ Quality slider update\n        imgcNodes.qualityRange.addEventListener('input', (e) => {\n            imgcNodes.qualityVal.innerText = e.target.value + '%';\n            imgcSelectPreset('custom');\n        });\n\n        \/\/ Target toggles\n        imgcNodes.targetToggle.addEventListener('change', (e) => {\n            if(e.target.checked) {\n                imgcNodes.targetSize.classList.remove('imgc-hidden');\n            } else {\n                imgcNodes.targetSize.classList.add('imgc-hidden');\n            }\n        });\n\n        \/\/ Global trigger pipelines\n        imgcNodes.processAllBtn.addEventListener('click', imgcProcessEntireQueue);\n        imgcNodes.clearQueueBtn.addEventListener('click', imgcResetPlatformState);\n        imgcNodes.zipBtn.addEventListener('click', imgcBatchZipExport);\n\n        \/\/ Preview options controls\n        imgcNodes.themeToggle.addEventListener('click', imgcToggleStageBackground);\n        imgcNodes.zoomBtn.addEventListener('click', imgcTriggerZoomLens);\n        imgcNodes.singleDlBtn.addEventListener('click', imgcDownloadActiveTarget);\n        imgcNodes.infoCopyBtn.addEventListener('click', imgcCopyActiveInfo);\n\n        \/\/ Fullscreen Modal closures\n        imgcNodes.portalClose.addEventListener('click', () => imgcNodes.portalRoot.classList.add('imgc-hidden'));\n        imgcNodes.portalRoot.addEventListener('click', (e) => {\n            if(e.target === imgcNodes.portalRoot) imgcNodes.portalRoot.classList.add('imgc-hidden');\n        });\n\n        \/\/ Slider splitter dynamics\n        imgcSetupSliderSplitter();\n\n        \/\/ System global clipboard catch\n        window.addEventListener('paste', imgcCapturePaste);\n    }\n\n    \/\/ Handles split sliders drags\n    function imgcSetupSliderSplitter() {\n        let isDragging = false;\n\n        const onStart = (e) => {\n            isDragging = true;\n            e.preventDefault();\n        };\n\n        const onMove = (e) => {\n            if(!isDragging) return;\n            const rect = imgcNodes.previewStage.getBoundingClientRect();\n            let clientX = e.clientX;\n            if(e.touches && e.touches[0]) clientX = e.touches[0].clientX;\n            \n            let percentage = ((clientX - rect.left) \/ rect.width) * 100;\n            if(percentage < 0) percentage = 0;\n            if(percentage > 100) percentage = 100;\n\n            imgcNodes.handleSplit.style.left = `${percentage}%`;\n            imgcNodes.imgBefore.style.clipPath = `polygon(0 0, ${percentage}% 0, ${percentage}% 100%, 0 100%)`;\n        };\n\n        const onEnd = () => {\n            isDragging = false;\n        };\n\n        imgcNodes.handleSplit.addEventListener('mousedown', onStart);\n        imgcNodes.handleSplit.addEventListener('touchstart', onStart);\n\n        window.addEventListener('mousemove', onMove);\n        window.addEventListener('touchmove', onMove);\n\n        window.addEventListener('mouseup', onEnd);\n        window.addEventListener('touchend', onEnd);\n    }\n\n    \/\/ Preset configurations management UI updates\n    function imgcSelectPreset(mode) {\n        imgcNodes.presetMax.classList.remove('imgc-active');\n        imgcNodes.presetBal.classList.remove('imgc-active');\n        imgcNodes.presetHq.classList.remove('imgc-active');\n        imgcNodes.presetCustom.classList.remove('imgc-active');\n\n        if(mode === 'max') {\n            imgcNodes.presetMax.classList.add('imgc-active');\n            imgcNodes.qualityRange.value = imgcState.presets.max;\n            imgcNodes.qualityVal.innerText = imgcState.presets.max + '%';\n        } else if(mode === 'balanced') {\n            imgcNodes.presetBal.classList.add('imgc-active');\n            imgcNodes.qualityRange.value = imgcState.presets.balanced;\n            imgcNodes.qualityVal.innerText = imgcState.presets.balanced + '%';\n        } else if(mode === 'high') {\n            imgcNodes.presetHq.classList.add('imgc-active');\n            imgcNodes.qualityRange.value = imgcState.presets.high;\n            imgcNodes.qualityVal.innerText = imgcState.presets.high + '%';\n        } else {\n            imgcNodes.presetCustom.classList.add('imgc-active');\n        }\n    }\n\n    \/\/ Capture Dragged drops\n    function imgcHandleDrop(e) {\n        e.preventDefault();\n        imgcNodes.dropzone.classList.remove('imgc-dragover');\n        if(e.dataTransfer.files) {\n            imgcProcessRawFiles(e.dataTransfer.files);\n        }\n    }\n\n    \/\/ File input selections\n    function imgcHandleFileSelection(e) {\n        if(e.target.files) {\n            imgcProcessRawFiles(e.target.files);\n        }\n    }\n\n    \/\/ Copy clipboard paste images\n    function imgcCapturePaste(e) {\n        if (e.clipboardData && e.clipboardData.files.length > 0) {\n            imgcProcessRawFiles(e.clipboardData.files);\n        }\n    }\n\n    \/\/ General file collection loader interface\n    function imgcProcessRawFiles(rawFiles) {\n        imgcHideAlert();\n        let addedAny = false;\n\n        for(let i=0; i<rawFiles.length; i++) {\n            const file = rawFiles[i];\n            if(!file.type.startsWith('image\/')) {\n                imgcDisplayError(\"One or more files skipped: Unsupported file format detected.\");\n                continue;\n            }\n\n            const reader = new FileReader();\n            reader.onload = function(evt) {\n                const img = new Image();\n                img.onload = function() {\n                    const struct = {\n                        id: Date.now() + Math.random().toString(36).substr(2, 5),\n                        file: file,\n                        name: file.name,\n                        originalSize: file.size,\n                        originalSrc: evt.target.result,\n                        originalWidth: img.width,\n                        originalHeight: img.height,\n                        compressedSrc: null,\n                        compressedSize: null,\n                        compressedWidth: null,\n                        compressedHeight: null,\n                        savingPercentage: 0,\n                        processing: false\n                    };\n\n                    imgcState.filesList.push(struct);\n                    imgcRenderQueue();\n                    imgcCalculateSystemStats();\n                    \n                    \/\/ Auto select the first newly added item\n                    if(imgcState.selectedIndex === -1) {\n                        imgcSelectActiveQueueIndex(imgcState.filesList.length - 1);\n                    }\n                };\n                img.src = evt.target.result;\n            };\n            reader.readAsDataURL(file);\n            addedAny = true;\n        }\n    }\n\n    \/\/ UI render of queues list\n    function imgcRenderQueue() {\n        if(imgcState.filesList.length === 0) {\n            imgcNodes.queueTarget.innerHTML = `\n                <div style=\"text-align: center; color: var(--imgc-text-muted); font-size: 0.8125rem; padding: 2rem 0;\">\n                    No files inside processing queue currently. Drop or choose assets above to commence.\n                <\/div>\n            `;\n            imgcNodes.batchDlWrap.classList.add('imgc-hidden');\n            return;\n        }\n\n        imgcNodes.queueTarget.innerHTML = '';\n        imgcNodes.batchDlWrap.classList.remove('imgc-hidden');\n\n        imgcState.filesList.forEach((item, index) => {\n            const div = document.createElement('div');\n            div.className = `imgc-queue-item ${index === imgcState.selectedIndex ? 'imgc-selected' : ''}`;\n            \n            \/\/ Generate metadata description markup text\n            const origSizeStr = imgcFormatByteString(item.originalSize);\n            let compDetails = '';\n            \n            if(item.processing) {\n                compDetails = `<span class=\"imgc-spinner\"><\/span>`;\n            } else if(item.compressedSize) {\n                const savingStr = item.savingPercentage > 0 ? `<span class=\"imgc-saving-badge\">-${item.savingPercentage}%<\/span>` : '';\n                compDetails = `<span>\u2192 <strong>${imgcFormatByteString(item.compressedSize)}<\/strong><\/span> ${savingStr}`;\n            }\n\n            div.innerHTML = `\n                <div class=\"imgc-queue-item-meta\" data-index=\"${index}\">\n                    <img decoding=\"async\" class=\"imgc-queue-thumb\" src=\"${item.originalSrc}\" alt=\"Thumbnail\">\n                    <div class=\"imgc-queue-info\">\n                        <span class=\"imgc-queue-name\">${item.name}<\/span>\n                        <div class=\"imgc-queue-sizes\">\n                            <span>${origSizeStr}<\/span>\n                            ${compDetails}\n                        <\/div>\n                    <\/div>\n                <\/div>\n                <div class=\"imgc-queue-actions\">\n                    <button class=\"imgc-small-btn imgc-delete-trigger\" data-index=\"${index}\" title=\"Remove file\">\u2715<\/button>\n                <\/div>\n            `;\n\n            \/\/ Setup click listeners dynamically to obey strict WordPress prefix rules\n            div.querySelector('.imgc-queue-item-meta').addEventListener('click', () => {\n                imgcSelectActiveQueueIndex(index);\n            });\n\n            div.querySelector('.imgc-delete-trigger').addEventListener('click', (e) => {\n                e.stopPropagation();\n                imgcRemoveIndexFromQueue(index);\n            });\n\n            imgcNodes.queueTarget.appendChild(div);\n        });\n    }\n\n    \/\/ Select queue object and load stage visualizations\n    function imgcSelectActiveQueueIndex(index) {\n        if(index < 0 || index >= imgcState.filesList.length) {\n            imgcState.selectedIndex = -1;\n            imgcClearComparisonStage();\n            return;\n        }\n\n        imgcState.selectedIndex = index;\n        imgcRenderQueue(); \/\/ Refresh active highlights\n\n        const item = imgcState.filesList[index];\n\n        \/\/ Enable actions\n        imgcNodes.infoCopyBtn.removeAttribute('disabled');\n\n        \/\/ Text configurations\n        imgcNodes.infoFilename.innerText = item.name;\n        imgcNodes.infoInputSize.innerText = imgcFormatByteString(item.originalSize);\n\n        \/\/ Original specs visual display\n        imgcNodes.imgBefore.src = item.originalSrc;\n        imgcNodes.imgBefore.classList.remove('imgc-hidden');\n        imgcNodes.lblBefore.classList.remove('imgc-hidden');\n        imgcNodes.instructions.classList.add('imgc-hidden');\n\n        if(item.compressedSrc) {\n            imgcNodes.imgAfter.src = item.compressedSrc;\n            imgcNodes.imgAfter.classList.remove('imgc-hidden');\n            imgcNodes.lblAfter.classList.remove('imgc-hidden');\n            imgcNodes.handleSplit.classList.remove('imgc-hidden');\n            imgcNodes.singleDlBtn.removeAttribute('disabled');\n            \n            imgcNodes.infoDims.innerText = `${item.compressedWidth} \u00d7 ${item.compressedHeight} px`;\n            imgcNodes.infoOutputSize.innerText = `${imgcFormatByteString(item.compressedSize)} (-${item.savingPercentage}%)`;\n        } else {\n            \/\/ Compressed properties absent\n            imgcNodes.imgAfter.classList.add('imgc-hidden');\n            imgcNodes.lblAfter.classList.add('imgc-hidden');\n            imgcNodes.handleSplit.classList.add('imgc-hidden');\n            imgcNodes.singleDlBtn.setAttribute('disabled', 'true');\n\n            imgcNodes.infoDims.innerText = `${item.originalWidth} \u00d7 ${item.originalHeight} px`;\n            imgcNodes.infoOutputSize.innerText = \"Pending compression...\";\n        }\n\n        \/\/ Reset split handler line to 50%\n        imgcNodes.handleSplit.style.left = '50%';\n        imgcNodes.imgBefore.style.clipPath = 'polygon(0 0, 50% 0, 50% 100%, 0 100%)';\n    }\n\n    \/\/ Wipe preview outputs\n    function imgcClearComparisonStage() {\n        imgcNodes.imgBefore.classList.add('imgc-hidden');\n        imgcNodes.imgBefore.src = '';\n        imgcNodes.lblBefore.classList.add('imgc-hidden');\n\n        imgcNodes.imgAfter.classList.add('imgc-hidden');\n        imgcNodes.imgAfter.src = '';\n        imgcNodes.lblAfter.classList.add('imgc-hidden');\n\n        imgcNodes.handleSplit.classList.add('imgc-hidden');\n        imgcNodes.instructions.classList.remove('imgc-hidden');\n\n        imgcNodes.infoFilename.innerText = '-';\n        imgcNodes.infoDims.innerText = '-';\n        imgcNodes.infoInputSize.innerText = '-';\n        imgcNodes.infoOutputSize.innerText = '-';\n\n        imgcNodes.singleDlBtn.setAttribute('disabled', 'true');\n        imgcNodes.infoCopyBtn.setAttribute('disabled', 'true');\n    }\n\n    \/\/ Delete single instance\n    function imgcRemoveIndexFromQueue(index) {\n        imgcState.filesList.splice(index, 1);\n        if(imgcState.selectedIndex === index) {\n            imgcState.selectedIndex = -1;\n        } else if (imgcState.selectedIndex > index) {\n            imgcState.selectedIndex--;\n        }\n        imgcRenderQueue();\n        imgcSelectActiveQueueIndex(imgcState.selectedIndex);\n        imgcCalculateSystemStats();\n    }\n\n    \/\/ Reset entire sandbox state\n    function imgcResetPlatformState() {\n        imgcState.filesList = [];\n        imgcState.selectedIndex = -1;\n        imgcRenderQueue();\n        imgcClearComparisonStage();\n        imgcCalculateSystemStats();\n        imgcHideAlert();\n        imgcNodes.picker.value = '';\n    }\n\n    \/\/ Engine Core: Run compression pipelines on the queue\n    async function imgcProcessEntireQueue() {\n        if(imgcState.filesList.length === 0) {\n            imgcDisplayError(\"Your processing task queue is empty. Upload files first.\");\n            return;\n        }\n\n        imgcState.compressingBatch = true;\n        imgcNodes.processAllBtn.setAttribute('disabled', 'true');\n        imgcNodes.processAllBtn.innerText = \"\u23f3 Processing Images...\";\n\n        \/\/ Extract parameters from inputs\n        const targetQuality = parseInt(imgcNodes.qualityRange.value) \/ 100;\n        const targetFormat = imgcNodes.formatSelect.value;\n        const scaleW = parseInt(imgcNodes.scaleWidth.value) || null;\n        const scaleH = parseInt(imgcNodes.scaleHeight.value) || null;\n        const keepRatio = imgcNodes.keepAspect.checked;\n        const targetSizeActive = imgcNodes.targetToggle.checked;\n        const targetSizeVal = parseFloat(imgcNodes.targetSize.value) * 1024 || null; \/\/ in bytes\n\n        for(let i=0; i<imgcState.filesList.length; i++) {\n            const item = imgcState.filesList[i];\n            item.processing = true;\n            imgcRenderQueue();\n\n            try {\n                const outputData = await imgcPerformCanvasCompression(item, {\n                    quality: targetQuality,\n                    format: targetFormat,\n                    width: scaleW,\n                    height: scaleH,\n                    aspect: keepRatio,\n                    targetSizeActive: targetSizeActive,\n                    targetSizeVal: targetSizeVal\n                });\n\n                item.compressedSrc = outputData.src;\n                item.compressedSize = outputData.size;\n                item.compressedWidth = outputData.width;\n                item.compressedHeight = outputData.height;\n                \n                \/\/ Calculate optimization efficiency\n                const saved = item.originalSize - item.compressedSize;\n                item.savingPercentage = Math.max(0, Math.round((saved \/ item.originalSize) * 100));\n            } catch (err) {\n                console.error(err);\n                imgcDisplayError(`Failed compressing ${item.name}: ${err.message}`);\n            }\n\n            item.processing = false;\n            imgcRenderQueue();\n            \n            \/\/ Keep active visuals synchronized\n            if(imgcState.selectedIndex === i) {\n                imgcSelectActiveQueueIndex(i);\n            }\n        }\n\n        imgcState.compressingBatch = false;\n        imgcNodes.processAllBtn.removeAttribute('disabled');\n        imgcNodes.processAllBtn.innerText = \"\ud83d\ude80 Apply Settings &#038; Compress All\";\n        imgcCalculateSystemStats();\n    }\n\n    \/\/ Core drawing compression technique running on HTML Canvas engine elements\n    function imgcPerformCanvasCompression(item, options) {\n        return new Promise((resolve, reject) => {\n            const img = new Image();\n            img.onload = function() {\n                \/\/ Calculate proper dimensions\n                let targetWidth = img.width;\n                let targetHeight = img.height;\n\n                if (options.width || options.height) {\n                    if (options.aspect) {\n                        if (options.width && options.height) {\n                            const ratio = Math.min(options.width \/ img.width, options.height \/ img.height);\n                            targetWidth = Math.round(img.width * ratio);\n                            targetHeight = Math.round(img.height * ratio);\n                        } else if (options.width) {\n                            targetWidth = options.width;\n                            targetHeight = Math.round(img.height * (options.width \/ img.width));\n                        } else {\n                            targetHeight = options.height;\n                            targetWidth = Math.round(img.width * (options.height \/ img.height));\n                        }\n                    } else {\n                        targetWidth = options.width || img.width;\n                        targetHeight = options.height || img.height;\n                    }\n                }\n\n                \/\/ Render image on dynamic workspace canvas\n                const canvas = document.createElement('canvas');\n                canvas.width = targetWidth;\n                canvas.height = targetHeight;\n                const ctx = canvas.getContext('2d');\n                ctx.drawImage(img, 0, 0, targetWidth, targetHeight);\n\n                \/\/ Determine final format mime\n                let exportFormat = options.format;\n                if (exportFormat === 'original') {\n                    exportFormat = item.file.type;\n                }\n\n                \/\/ Fallback output to standard image formats if conversion unsupported by host browser engines\n                const formatsList = ['image\/jpeg', 'image\/png', 'image\/webp'];\n                if (!formatsList.includes(exportFormat)) {\n                    exportFormat = 'image\/jpeg';\n                }\n\n                \/\/ Compress algorithm\n                let currentQuality = options.quality;\n                \n                const processOutput = (q) => {\n                    canvas.toBlob((blob) => {\n                        if(!blob) {\n                            reject(new Error(\"Unable to capture canvas binary structures.\"));\n                            return;\n                        }\n\n                        \/\/ Target Max File Size logic check\n                        if (options.targetSizeActive && options.targetSizeVal && q > 0.05 && blob.size > options.targetSizeVal) {\n                            \/\/ Recursively scale down quality to fit size requirements\n                            q -= 0.1;\n                            processOutput(q);\n                            return;\n                        }\n\n                        const reader = new FileReader();\n                        reader.onloadend = function() {\n                            resolve({\n                                src: reader.result,\n                                size: blob.size,\n                                width: targetWidth,\n                                height: targetHeight\n                            });\n                        };\n                        reader.readAsDataURL(blob);\n                    }, exportFormat, q);\n                };\n\n                processOutput(currentQuality);\n            };\n            img.onerror = () => reject(new Error(\"Could not initialize image source decoder locally.\"));\n            img.src = item.originalSrc;\n        });\n    }\n\n    \/\/ Export single focused preview\n    function imgcDownloadActiveTarget() {\n        if(imgcState.selectedIndex === -1) return;\n        const item = imgcState.filesList[imgcState.selectedIndex];\n        if(!item.compressedSrc) return;\n\n        \/\/ Auto naming calculations\n        const dotIndex = item.name.lastIndexOf('.');\n        const namePart = dotIndex !== -1 ? item.name.substring(0, dotIndex) : item.name;\n        \n        let selectedFormat = imgcNodes.formatSelect.value;\n        if(selectedFormat === 'original') selectedFormat = item.file.type;\n        let ext = 'jpg';\n        if(selectedFormat === 'image\/png') ext = 'png';\n        if(selectedFormat === 'image\/webp') ext = 'webp';\n\n        const dlLink = document.createElement('a');\n        dlLink.href = item.compressedSrc;\n        dlLink.download = `${namePart}_compressed.${ext}`;\n        document.body.appendChild(dlLink);\n        dlLink.click();\n        document.body.removeChild(dlLink);\n    }\n\n    \/\/ Zip batch downloader utilizing imported JSZip\n    async function imgcBatchZipExport() {\n        const zippedTargets = imgcState.filesList.filter(f => f.compressedSrc);\n        if(zippedTargets.length === 0) {\n            imgcDisplayError(\"Nothing available to package. Please run compression first.\");\n            return;\n        }\n\n        imgcNodes.zipBtn.setAttribute('disabled', 'true');\n        imgcNodes.zipBtn.innerText = \"Packing assets inside ZIP container...\";\n\n        try {\n            const zip = new JSZip();\n            for(let i=0; i<zippedTargets.length; i++) {\n                const item = zippedTargets[i];\n                const parts = item.compressedSrc.split(',');\n                const binData = atob(parts[1]);\n                const len = binData.length;\n                const bytes = new Uint8Array(len);\n                for (let j = 0; j < len; j++) {\n                    bytes[j] = binData.charCodeAt(j);\n                }\n\n                \/\/ Construct unique safe naming output formats\n                const dotIndex = item.name.lastIndexOf('.');\n                const namePart = dotIndex !== -1 ? item.name.substring(0, dotIndex) : item.name;\n                \n                let selectedFormat = imgcNodes.formatSelect.value;\n                if(selectedFormat === 'original') selectedFormat = item.file.type;\n                let ext = 'jpg';\n                if(selectedFormat === 'image\/png') ext = 'png';\n                if(selectedFormat === 'image\/webp') ext = 'webp';\n\n                zip.file(`${namePart}_compressed_${i+1}.${ext}`, bytes);\n            }\n\n            const content = await zip.generateAsync({ type: 'blob' });\n            const zipUrl = URL.createObjectURL(content);\n\n            const a = document.createElement('a');\n            a.href = zipUrl;\n            a.download = `compressed_assets_${Date.now()}.zip`;\n            document.body.appendChild(a);\n            a.click();\n            document.body.removeChild(a);\n            URL.revokeObjectURL(zipUrl);\n        } catch (err) {\n            imgcDisplayError(\"Failed creating ZIP output file locally: \" + err.message);\n        } finally {\n            imgcNodes.zipBtn.removeAttribute('disabled');\n            imgcNodes.zipBtn.innerText = \"\ud83d\udce6 Export All Decimated Assets (.zip)\";\n        }\n    }\n\n    \/\/ Copier Clipboard specifications metadata\n    function imgcCopyActiveInfo() {\n        if(imgcState.selectedIndex === -1) return;\n        const item = imgcState.filesList[imgcState.selectedIndex];\n        \n        let clipText = `File Name: ${item.name}\\n`;\n        clipText += `Original Size: ${imgcFormatByteString(item.originalSize)}\\n`;\n        if(item.compressedSize) {\n            clipText += `Compressed Size: ${imgcFormatByteString(item.compressedSize)}\\n`;\n            clipText += `Footprint Reduction: ${item.savingPercentage}%\\n`;\n            clipText += `Output Dimensions: ${item.compressedWidth}x${item.compressedHeight} px\\n`;\n        } else {\n            clipText += `Status: Uncompressed \/ Processing Queued\\n`;\n        }\n        clipText += `Processed locally via Local Image Compressor Pro.\\n`;\n\n        navigator.clipboard.writeText(clipText).then(() => {\n            alert(\"Image structural configuration metadata copied to pasteboard!\");\n        }).catch(() => {\n            imgcDisplayError(\"Clipboard security settings prevented automated copy.\");\n        });\n    }\n\n    \/\/ Background preview styles toggles\n    function imgcToggleStageBackground() {\n        imgcState.themeCheckerboard = !imgcState.themeCheckerboard;\n        if(imgcState.themeCheckerboard) {\n            imgcNodes.previewStage.classList.add('imgc-checkerboard');\n            imgcNodes.previewStage.style.backgroundColor = '';\n        } else {\n            imgcNodes.previewStage.classList.remove('imgc-checkerboard');\n            imgcNodes.previewStage.style.backgroundColor = '#18181b';\n        }\n    }\n\n    \/\/ Zoom lens portals modal trigger\n    function imgcTriggerZoomLens() {\n        if(imgcState.selectedIndex === -1) return;\n        const item = imgcState.filesList[imgcState.selectedIndex];\n        \n        \/\/ Show output image if available, fallback to original\n        const src = item.compressedSrc || item.originalSrc;\n        imgcNodes.portalImg.src = src;\n        imgcNodes.portalRoot.classList.remove('imgc-hidden');\n    }\n\n    \/\/ Calculate aggregated statistics\n    function imgcCalculateSystemStats() {\n        imgcNodes.statCount.innerText = imgcState.filesList.length;\n\n        let totalOriginal = 0;\n        let totalCompressed = 0;\n        let compressedCount = 0;\n\n        imgcState.filesList.forEach(item => {\n            totalOriginal += item.originalSize;\n            if (item.compressedSize) {\n                totalCompressed += item.compressedSize;\n                compressedCount++;\n            } else {\n                totalCompressed += item.originalSize;\n            }\n        });\n\n        if(compressedCount > 0 && totalOriginal > 0) {\n            const savings = totalOriginal - totalCompressed;\n            const savingPercent = Math.max(0, Math.round((savings \/ totalOriginal) * 100));\n            imgcNodes.statSavings.innerText = `${savingPercent}%`;\n            imgcNodes.statReclaimed.innerText = imgcFormatByteString(savings);\n        } else {\n            imgcNodes.statSavings.innerText = \"0%\";\n            imgcNodes.statReclaimed.innerText = \"0 KB\";\n        }\n    }\n\n    \/\/ Format human-readable byte formats\n    function imgcFormatByteString(bytes) {\n        if (bytes === 0) return '0 Bytes';\n        const k = 1024;\n        const sizes = ['Bytes', 'KB', 'MB', 'GB'];\n        const i = Math.floor(Math.log(bytes) \/ Math.log(k));\n        return parseFloat((bytes \/ Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n    }\n\n    \/\/ Error Alert Interfaces\n    function imgcDisplayError(text) {\n        imgcNodes.alertText.innerText = text;\n        imgcNodes.alertWrap.classList.remove('imgc-hidden');\n        setTimeout(() => {\n            imgcHideAlert();\n        }, 6000);\n    }\n\n    function imgcHideAlert() {\n        imgcNodes.alertWrap.classList.add('imgc-hidden');\n    }\n\n    \/\/ Lifecycle trigger\n    imgcBoot();\n\n})();\n<\/script>\n\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>SaaS Premium Image Compressor Local Image Compressor Pro A premium compression platform functioning safely and offline entirely inside your browser. No server uploads. Drag &#038; drop multiple images or click to select. Supports WebP, JPEG, PNG, BMP, and GIF. Ctrl + V to paste clipboard image streams. \u2699\ufe0f Engine Configuration Target Quality Mode Max Size [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-49","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages\/49","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/comments?post=49"}],"version-history":[{"count":7,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages\/49\/revisions"}],"predecessor-version":[{"id":509,"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/pages\/49\/revisions\/509"}],"wp:attachment":[{"href":"https:\/\/freewebtools.co.in\/index.php\/wp-json\/wp\/v2\/media?parent=49"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}