{"id":87,"date":"2026-09-11T13:35:28","date_gmt":"2026-09-11T13:35:28","guid":{"rendered":"https:\/\/ankmavenmarketing.in\/tools\/?page_id=87"},"modified":"2026-09-11T13:36:04","modified_gmt":"2026-09-11T13:36:04","slug":"color-palette-extractor","status":"publish","type":"page","link":"https:\/\/ankmavenmarketing.in\/tools\/color-palette-extractor\/","title":{"rendered":"Color Palette Extractor"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"87\" class=\"elementor elementor-87\">\n\t\t\t\t<div class=\"elementor-element elementor-element-58ab088 e-flex e-con-boxed e-con e-parent\" data-id=\"58ab088\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b6e773f elementor-widget elementor-widget-shortcode\" data-id=\"b6e773f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\">    <!-- SheetJS (xlsx) Library for Master Excel Export -->\r\n    <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/xlsx\/0.18.5\/xlsx.full.min.js\"><\/script>\r\n    \r\n    <!-- Ank Maven Marketing Bulk Color Palette Extractor UI v3.0 -->\r\n    <div id=\"ank-ultimate-bulk-palette\">\r\n        <style>\r\n            #ank-ultimate-bulk-palette {\r\n                --ank-dark: #070d19; --ank-navy: #0f172a; --ank-cyan: #22d3ee; --ank-orange: #f97316; \r\n                --ank-border: #1e293b; --ank-card-bg: #0b1329; --ank-text: #f8fafc; --ank-muted: #94a3b8;\r\n                font-family: 'Inter', sans-serif; background: var(--ank-dark); max-width: 1100px; margin: 5px auto;\r\n                border: 1px solid var(--ank-border); color: var(--ank-text); box-sizing: border-box; position: relative;\r\n            }\r\n            #ank-ultimate-bulk-palette * { box-sizing: border-box; }\r\n\r\n            .ank-head { background: var(--ank-navy); padding: 10px 14px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--ank-border); }\r\n            .ank-head h4 { color: #fff; margin: 0; font-size: 11px; letter-spacing: 2px; font-weight: 900; text-transform: uppercase; }\r\n            .ank-head h4 span { color: var(--ank-orange); }\r\n\r\n            \/* Features Bar *\/\r\n            .ank-guide-box { background: var(--ank-card-bg); border-bottom: 1px solid var(--ank-border); padding: 6px 10px; font-size: 9px; color: var(--ank-muted); display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 4px; }\r\n            .ank-guide-box span { font-weight: 800; color: var(--ank-cyan); }\r\n            .ank-guide-tags { display: flex; gap: 6px; flex-wrap: wrap; }\r\n            .ank-guide-tag { background: var(--ank-navy); border: 1px solid var(--ank-border); padding: 2px 6px; border-radius: 3px; font-size: 8px; font-weight: 700; color: var(--ank-cyan); }\r\n\r\n            \/* Workspace Grid Layout (Before \/ After Style) *\/\r\n            .ank-palette-grid { display: grid; grid-template-columns: 1fr 1fr; min-height: 340px; background: var(--ank-border); gap: 1px; }\r\n            .ank-palette-pane { background: var(--ank-card-bg); position: relative; padding: 12px; display: flex; flex-direction: column; justify-content: flex-start; overflow-y: auto; max-height: 400px; }\r\n            .ank-palette-pane h5 { margin: 0 0 8px 0; font-size: 9px; text-transform: uppercase; letter-spacing: 1px; color: var(--ank-cyan); border-bottom: 1px solid var(--ank-border); padding-bottom: 4px; }\r\n\r\n            \/* Swatches Display *\/\r\n            .swatch-container { display: flex; flex-direction: column; gap: 6px; width: 100%; margin-top: 5px; }\r\n            .swatch-row { display: flex; align-items: center; background: var(--ank-navy); border: 1px solid var(--ank-border); border-radius: 4px; padding: 6px 10px; gap: 10px; }\r\n            .swatch-box { width: 28px; height: 28px; border-radius: 3px; border: 1px solid rgba(255,255,255,0.2); flex-shrink: 0; }\r\n            .swatch-info { flex: 1; display: flex; justify-content: space-between; align-items: center; font-size: 9px; font-weight: 700; }\r\n            .swatch-hex { color: var(--ank-cyan); font-family: monospace; font-size: 10px; }\r\n            .swatch-rgb { color: var(--ank-muted); font-size: 8px; }\r\n            .btn-copy { background: var(--ank-border); color: var(--ank-text); border: none; font-size: 7px; font-weight: 900; padding: 4px 8px; cursor: pointer; border-radius: 3px; text-transform: uppercase; transition: 0.2s; }\r\n            .btn-copy:hover { background: var(--ank-cyan); color: var(--ank-dark); }\r\n\r\n            \/* Thumbnails Strip *\/\r\n            .ank-thumbs { display: none; gap: 8px; padding: 8px 10px; background: var(--ank-card-bg); border-top: 1px solid var(--ank-border); overflow-x: auto; max-height: 100px; }\r\n            .t-card { display: flex; flex-direction: column; gap: 3px; min-width: 55px; align-items: center; }\r\n            .t-box { width: 50px; height: 50px; border: 2px solid var(--ank-border); cursor: pointer; border-radius: 4px; overflow: hidden; background: var(--ank-navy); position: relative; }\r\n            .t-box.active { border-color: var(--ank-cyan); background: #0f2238; }\r\n            .t-box img { width: 100%; height: 100%; object-fit: cover; }\r\n\r\n            \/* Footer *\/\r\n            .ank-foot { padding: 8px 12px; display: flex; justify-content: space-between; align-items: center; background: var(--ank-navy); border-top: 1px solid var(--ank-border); }\r\n            .btn-main { background: var(--ank-orange); color: white; border: none; padding: 0 18px; height: 35px; font-size: 10px; font-weight: 900; cursor: pointer; text-transform: uppercase; border-radius: 4px; transition: 0.2s; }\r\n            .btn-main:hover { opacity: 0.9; }\r\n            .btn-excel { background: var(--ank-cyan) !important; color: var(--ank-dark) !important; display: none; }\r\n            .btn-reset { background: var(--ank-card-bg); color: var(--ank-text); border: 1px solid var(--ank-border); }\r\n\r\n            @media (max-width: 768px) {\r\n                .ank-palette-grid { grid-template-columns: 1fr; }\r\n            }\r\n        <\/style>\r\n\r\n        <div class=\"ank-head\">\r\n            <h4>ANK MAVEN <span>MARKETING<\/span> \u2014 BULK PALETTE & BROCHURE EXTRACTOR v3.0<\/h4>\r\n            <div id=\"sys-tag\" style=\"color:var(--ank-cyan); font-size:9px; font-weight:900;\">\u25cf READY<\/div>\r\n        <\/div>\r\n\r\n        <div class=\"ank-guide-box\">\r\n            <span>\u26a1 Bulk Multi-Use Suite:<\/span>\r\n            <div class=\"ank-guide-tags\">\r\n                <div class=\"ank-guide-tag\">Multiple Images \/ Brochures<\/div>\r\n                <div class=\"ank-guide-tag\">Accurate Swatch Generation<\/div>\r\n                <div class=\"ank-guide-tag\">Master Excel Report (.xlsx)<\/div>\r\n                <div class=\"ank-guide-tag\">Before \/ After Layout<\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <!-- WORKSPACE GRID (BEFORE \/ AFTER) -->\r\n        <div class=\"ank-palette-grid\">\r\n            <div class=\"ank-palette-pane\">\r\n                <h5>1. Original Image \/ Brochure Preview<\/h5>\r\n                <div style=\"display:flex; justify-content:center; align-items:center; height:180px; background:#040810; border:1px dashed var(--ank-border); margin-bottom:8px; border-radius:4px; overflow:hidden;\">\r\n                    <span id=\"palette-placeholder\" style=\"color:var(--ank-muted); font-size:9px; font-weight:800;\">UPLOAD MULTIPLE FILES TO START<\/span>\r\n                    <img id=\"palette-preview-img\" style=\"max-height:100%; max-width:100%; display:none; object-fit:contain;\">\r\n                <\/div>\r\n                <div id=\"image-meta-box\" style=\"font-size:9px; color:var(--ank-muted); font-weight:700; line-height:1.4;\">\r\n                    File Name: N\/A<br>Dimensions: N\/A\r\n                <\/div>\r\n            <\/div>\r\n            \r\n            <div class=\"ank-palette-pane\">\r\n                <h5>2. Extracted Dominant Color Palette (Top 6)<\/h5>\r\n                <div class=\"swatch-container\" id=\"swatches-wrapper\">\r\n                    <div style=\"color:var(--ank-muted); font-size:9px; text-align:center; margin-top:40px;\">Upload brochures, banners, or images to extract colors.<\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <!-- THUMBNAILS STRIP -->\r\n        <div class=\"ank-thumbs\" id=\"palette-thumb-strip\"><\/div>\r\n\r\n        <!-- FOOTER -->\r\n        <div class=\"ank-foot\">\r\n            <input type=\"file\" id=\"palette-file-in\" accept=\"image\/*\" multiple onchange=\"handleBulkPaletteFiles(this)\" style=\"font-size:10px; font-weight:bold; width:180px; color:var(--ank-text);\">\r\n            <div style=\"display:flex; gap:8px;\">\r\n                <button onclick=\"location.reload()\" class=\"btn-main btn-reset\">Reset<\/button>\r\n                <button onclick=\"exportMasterExcelReport()\" id=\"dl-excel-btn\" class=\"btn-main btn-excel\">Export Master Report (.xlsx)<\/button>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <script>\r\n            let uploadedBatchFiles = [];\r\n            let extractedBatchPalettes = {};\r\n\r\n            function handleBulkPaletteFiles(input) {\r\n                if (input.files && input.files.length > 0) {\r\n                    uploadedBatchFiles = Array.from(input.files);\r\n                    extractedBatchPalettes = {};\r\n                    \r\n                    document.getElementById('sys-tag').innerText = `\u25cf READY (${uploadedBatchFiles.length} FILES)`;\r\n                    document.getElementById('dl-excel-btn').style.display = \"block\";\r\n\r\n                    const strip = document.getElementById('palette-thumb-strip');\r\n                    strip.innerHTML = \"\"; strip.style.display = \"flex\";\r\n\r\n                    uploadedBatchFiles.forEach((file, idx) => {\r\n                        const reader = new FileReader();\r\n                        reader.readAsDataURL(file);\r\n                        reader.onload = e => {\r\n                            const card = document.createElement('div'); card.className = \"t-card\";\r\n                            card.innerHTML = `\r\n                                <div class=\"t-box ${idx === 0 ? 'active' : ''}\" onclick=\"switchPaletteItem(${idx})\" id=\"pt-${idx}\"><img decoding=\"async\" src=\"${e.target.result}\"><\/div>\r\n                                <span style=\"font-size:7px; font-weight:700; color:var(--ank-muted);\">#${idx+1}<\/span>\r\n                            `;\r\n                            strip.appendChild(card);\r\n                            \r\n                            \/\/ Process and cache palette immediately\r\n                            const tempImg = new Image();\r\n                            tempImg.src = e.target.result;\r\n                            tempImg.onload = () => {\r\n                                let palette = extractColorsFromImageObject(tempImg);\r\n                                extractedBatchPalettes[idx] = { fileName: file.name, fileSize: file.size, width: tempImg.width, height: tempImg.height, dataUrl: e.target.result, palette: palette };\r\n                                if (idx === 0) {\r\n                                    switchPaletteItem(0);\r\n                                }\r\n                            };\r\n                        };\r\n                    });\r\n                }\r\n            }\r\n\r\n            function switchPaletteItem(idx) {\r\n                const item = extractedBatchPalettes[idx];\r\n                if (!item) return;\r\n\r\n                const img = document.getElementById('palette-preview-img');\r\n                img.src = item.dataUrl;\r\n                img.style.display = \"block\";\r\n                document.getElementById('palette-placeholder').style.display = \"none\";\r\n\r\n                document.getElementById('image-meta-box').innerHTML = `\r\n                    File Name: <strong>${item.fileName}<\/strong><br>\r\n                    Dimensions: <strong>${item.width} x ${item.height} px<\/strong><br>\r\n                    File Size: <strong>${Math.round(item.fileSize \/ 1024)} KB<\/strong>\r\n                `;\r\n\r\n                renderSwatches(item.palette);\r\n                document.querySelectorAll('.t-box').forEach((b, i) => b.classList.toggle('active', i === idx));\r\n            }\r\n\r\n            function extractColorsFromImageObject(img) {\r\n                const canvas = document.createElement('canvas');\r\n                const ctx = canvas.getContext('2d');\r\n                \r\n                const scale = Math.min(1, 120 \/ Math.max(img.width, img.height));\r\n                canvas.width = Math.round(img.width * scale);\r\n                canvas.height = Math.round(img.height * scale);\r\n                \r\n                ctx.drawImage(img, 0, 0, canvas.width, canvas.height);\r\n                const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\r\n                \r\n                let colorBuckets = {};\r\n                for (let i = 0; i < imgData.length; i += 4) {\r\n                    let r = imgData[i];\r\n                    let g = imgData[i+1];\r\n                    let b = imgData[i+2];\r\n                    let a = imgData[i+3];\r\n                    \r\n                    if (a < 128) continue; \/\/ Skip transparency\r\n                    \/\/ Ignore pure whites and pure blacks for more meaningful brand\/design colors\r\n                    if (r > 245 && g > 245 && b > 245) continue;\r\n                    if (r < 15 && g < 15 && b < 15) continue;\r\n\r\n                    \/\/ Quantize into broader color bins\r\n                    let qr = Math.round(r \/ 32) * 32;\r\n                    let qg = Math.round(g \/ 32) * 32;\r\n                    let qb = Math.round(b \/ 32) * 32;\r\n                    \r\n                    let key = `${qr},${qg},${qb}`;\r\n                    colorBuckets[key] = (colorBuckets[key] || 0) + 1;\r\n                }\r\n\r\n                let sortedBuckets = Object.keys(colorBuckets).sort((a, b) => colorBuckets[b] - colorBuckets[a]);\r\n                let palette = [];\r\n                \r\n                for (let i = 0; i < sortedBuckets.length && palette.length < 6; i++) {\r\n                    let rgbArr = sortedBuckets[i].split(',').map(Number);\r\n                    let hex = rgbToHex(rgbArr[0], rgbArr[1], rgbArr[2]);\r\n                    \r\n                    if (palette.some(p => getColorDistance(p.rgbArr, rgbArr) < 45)) continue;\r\n                    palette.push({ hex: hex, rgb: `rgb(${rgbArr[0]}, ${rgbArr[1]}, ${rgbArr[2]})`, rgbArr: rgbArr });\r\n                }\r\n\r\n                \/\/ Fallback if image was pure black\/white\r\n                if (palette.length === 0) {\r\n                    palette.push({ hex: \"#0F172A\", rgb: \"rgb(15, 23, 42)\", rgbArr: [15, 23, 42] });\r\n                }\r\n\r\n                return palette;\r\n            }\r\n\r\n            function renderSwatches(palette) {\r\n                let wrapper = document.getElementById('swatches-wrapper');\r\n                wrapper.innerHTML = \"\";\r\n\r\n                palette.forEach(item => {\r\n                    let row = document.createElement('div');\r\n                    row.className = \"swatch-row\";\r\n                    row.innerHTML = `\r\n                        <div class=\"swatch-box\" style=\"background:${item.hex};\"><\/div>\r\n                        <div class=\"swatch-info\">\r\n                            <div>\r\n                                <div class=\"swatch-hex\">${item.hex}<\/div>\r\n                                <div class=\"swatch-rgb\">${item.rgb}<\/div>\r\n                            <\/div>\r\n                            <button class=\"btn-copy\" onclick=\"copyColorCode('${item.hex}')\">Copy HEX<\/button>\r\n                        <\/div>\r\n                    `;\r\n                    wrapper.appendChild(row);\r\n                });\r\n            }\r\n\r\n            function rgbToHex(r, g, b) {\r\n                return \"#\" + [r, g, b].map(x => {\r\n                    let hex = x.toString(16);\r\n                    return hex.length === 1 ? \"0\" + hex : hex;\r\n                }).join(\"\").toUpperCase();\r\n            }\r\n\r\n            function getColorDistance(rgb1, rgb2) {\r\n                return Math.sqrt(\r\n                    Math.pow(rgb1[0] - rgb2[0], 2) +\r\n                    Math.pow(rgb1[1] - rgb2[1], 2) +\r\n                    Math.pow(rgb1[2] - rgb2[2], 2)\r\n                );\r\n            }\r\n\r\n            function copyColorCode(hex) {\r\n                navigator.clipboard.writeText(hex).then(() => {\r\n                    alert(\"Copied to clipboard: \" + hex);\r\n                });\r\n            }\r\n\r\n            function exportMasterExcelReport() {\r\n                if (Object.keys(extractedBatchPalettes).length === 0) return alert(\"Please upload files first!\");\r\n\r\n                let excelRows = [];\r\n                Object.keys(extractedBatchPalettes).forEach(key => {\r\n                    let entry = extractedBatchPalettes[key];\r\n                    entry.palette.forEach((swatch, sIdx) => {\r\n                        excelRows.push({\r\n                            \"File Name\": entry.fileName,\r\n                            \"Swatch Rank\": `Color #${sIdx + 1}`,\r\n                            \"HEX Code\": swatch.hex,\r\n                            \"RGB Value\": swatch.rgb\r\n                        });\r\n                    });\r\n                });\r\n\r\n                const worksheet = XLSX.utils.json_to_sheet(excelRows);\r\n                const workbook = XLSX.utils.book_new();\r\n                XLSX.utils.book_append_sheet(workbook, worksheet, \"Master Color Palettes\");\r\n                \r\n                XLSX.writeFile(workbook, \"AnkMaven_Master_Color_Palette_Report.xlsx\");\r\n            }\r\n        <\/script>\r\n    <\/div>\r\n    <\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-87","page","type-page","status-publish","hentry"],"_hostinger_reach_plugin_has_subscription_block":false,"_hostinger_reach_plugin_is_elementor":false,"_links":{"self":[{"href":"https:\/\/ankmavenmarketing.in\/tools\/wp-json\/wp\/v2\/pages\/87","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ankmavenmarketing.in\/tools\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ankmavenmarketing.in\/tools\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ankmavenmarketing.in\/tools\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ankmavenmarketing.in\/tools\/wp-json\/wp\/v2\/comments?post=87"}],"version-history":[{"count":4,"href":"https:\/\/ankmavenmarketing.in\/tools\/wp-json\/wp\/v2\/pages\/87\/revisions"}],"predecessor-version":[{"id":91,"href":"https:\/\/ankmavenmarketing.in\/tools\/wp-json\/wp\/v2\/pages\/87\/revisions\/91"}],"wp:attachment":[{"href":"https:\/\/ankmavenmarketing.in\/tools\/wp-json\/wp\/v2\/media?parent=87"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}