{"id":541,"date":"2026-06-20T05:01:04","date_gmt":"2026-06-20T05:01:04","guid":{"rendered":"https:\/\/toolibee.com\/?page_id=541"},"modified":"2026-06-20T05:24:56","modified_gmt":"2026-06-20T05:24:56","slug":"image-converter","status":"publish","type":"page","link":"https:\/\/toolibee.com\/?page_id=541","title":{"rendered":"Image Converter"},"content":{"rendered":"\n    <div id=\"toolibee-image-12920\" class=\"toolibee-image-tool\">\n        <div class=\"tb-card\">\n            <div class=\"tb-header\">\n                <div class=\"tb-bee\">\ud83d\udc1d<\/div>\n                <div>\n                    <h2>Toolibee Image Converter<\/h2>\n                    <p>Convert images and PDFs right in your browser. No server tools required.<\/p>\n                <\/div>\n            <\/div>\n\n            <div class=\"tb-body\">\n                <div class=\"tb-grid\">\n                    <div class=\"tb-panel\">\n                        <label>Select file or files<\/label>\n                        <input type=\"file\" class=\"tb-files\" multiple accept=\".jpg,.jpeg,.png,.webp,.gif,.heic,.heif,.pdf,image\/*,application\/pdf\" \/>\n\n                        <label>Conversion type<\/label>\n                        <select class=\"tb-mode\">\n                            <option value=\"jpg-pdf\">JPG to PDF<\/option>\n                            <option value=\"pdf-jpg\">PDF to JPG<\/option>\n                            <option value=\"heic-jpg\">HEIC to JPG<\/option>\n                            <option value=\"image-pdf\">Image to PDF<\/option>\n                            <option value=\"image-converter\">Image Converter<\/option>\n                        <\/select>\n\n                        <label>Output format<\/label>\n                        <select class=\"tb-format\">\n                            <option value=\"jpg\">JPG<\/option>\n                            <option value=\"png\">PNG<\/option>\n                            <option value=\"webp\">WEBP<\/option>\n                            <option value=\"pdf\">PDF<\/option>\n                        <\/select>\n\n                        <div class=\"tb-row\">\n                            <div>\n                                <label>Quality<\/label>\n                                <select class=\"tb-quality\">\n                                    <option value=\"0.95\">High<\/option>\n                                    <option value=\"0.82\" selected>Balanced<\/option>\n                                    <option value=\"0.65\">Small file<\/option>\n                                <\/select>\n                            <\/div>\n                            <div>\n                                <label>Max width <small>optional<\/small><\/label>\n                                <input type=\"number\" class=\"tb-width\" placeholder=\"Example: 1200\" \/>\n                            <\/div>\n                        <\/div>\n\n                        <label class=\"tb-check\">\n                            <input type=\"checkbox\" class=\"tb-one-pdf\" checked>\n                            Combine multiple images into one PDF\n                        <\/label>\n\n                        <div class=\"tb-actions\">\n                            <button type=\"button\" class=\"tb-convert\">Convert<\/button>\n                            <button type=\"button\" class=\"tb-clear\">Clear<\/button>\n                        <\/div>\n\n                        <p class=\"tb-note\"><strong>Privacy:<\/strong> Files are converted in the browser. They are not uploaded to your WordPress server.<\/p>\n                    <\/div>\n\n                    <div class=\"tb-panel tb-result-panel\">\n                        <label>Conversion output<\/label>\n                        <div class=\"tb-output\" aria-live=\"polite\">Choose a file and select a conversion type.<\/div>\n\n                        <div class=\"tb-downloads\"><\/div>\n\n                        <p class=\"tb-note\"><strong>Note:<\/strong> PDF to JPG and HEIC to JPG use browser JavaScript libraries loaded on the page. Some locked-down browsers may block these features.<\/p>\n                    <\/div>\n                <\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <style>\n        #toolibee-image-12920{--tb-navy:#18324a;--tb-blue:#2f80ed;--tb-sky:#eaf6ff;--tb-gold:#f6b93b;--tb-ink:#1f2937;--tb-muted:#64748b;--tb-border:#dbe7f3;max-width:1000px;margin:24px auto;padding:0 14px;font-family:Inter,Arial,sans-serif;color:var(--tb-ink)}\n        #toolibee-image-12920 *{box-sizing:border-box}\n        #toolibee-image-12920 .tb-card{background:#fff;border:1px solid var(--tb-border);border-radius:22px;box-shadow:0 14px 35px rgba(24,50,74,.10);overflow:hidden}\n        #toolibee-image-12920 .tb-header{display:flex;gap:14px;align-items:center;background:linear-gradient(135deg,var(--tb-navy),#24577c);color:#fff;padding:22px 24px}\n        #toolibee-image-12920 .tb-bee{width:46px;height:46px;border-radius:50%;display:grid;place-items:center;background:var(--tb-gold);color:#1f2937;font-size:25px;box-shadow:inset 0 -4px 0 rgba(0,0,0,.08);flex:0 0 46px}\n        #toolibee-image-12920 h2{margin:0;font-size:25px;line-height:1.2;color:#fff}\n        #toolibee-image-12920 .tb-header p{margin:5px 0 0;color:#e8f5ff}\n        #toolibee-image-12920 .tb-body{padding:24px;background:linear-gradient(180deg,#fff,#fbfdff)}\n        #toolibee-image-12920 .tb-grid{display:grid;grid-template-columns:1fr 1fr;gap:18px;align-items:start}\n        #toolibee-image-12920 .tb-panel{background:#fff;border:1px solid var(--tb-border);border-radius:18px;padding:18px}\n        #toolibee-image-12920 label{display:block;font-weight:800;margin:0 0 7px;color:var(--tb-navy)}\n        #toolibee-image-12920 label:not(:first-child){margin-top:14px}\n        #toolibee-image-12920 small{font-weight:600;color:var(--tb-muted)}\n        #toolibee-image-12920 input,#toolibee-image-12920 select{width:100%;box-sizing:border-box;border:1px solid var(--tb-border);border-radius:14px;padding:12px 13px;font-size:15px;background:#fff;color:var(--tb-ink)}\n        #toolibee-image-12920 .tb-row{display:grid;grid-template-columns:1fr 1fr;gap:12px}\n        #toolibee-image-12920 .tb-check{display:flex;align-items:center;gap:9px;background:#fffdf6;border:1px solid #f2dfac;border-radius:14px;padding:11px 12px;margin-top:14px}\n        #toolibee-image-12920 .tb-check input{width:auto}\n        #toolibee-image-12920 .tb-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}\n        #toolibee-image-12920 button{border:0;border-radius:999px;padding:11px 18px;font-weight:800;cursor:pointer;background:var(--tb-blue);color:#fff;box-shadow:0 7px 18px rgba(47,128,237,.22)}\n        #toolibee-image-12920 .tb-clear{background:#fff;color:var(--tb-navy);border:1px solid var(--tb-border);box-shadow:none}\n        #toolibee-image-12920 .tb-output{background:var(--tb-sky);border:1px solid var(--tb-border);border-radius:16px;padding:16px;min-height:170px;white-space:pre-wrap;line-height:1.55}\n        #toolibee-image-12920 .tb-note{font-size:13px;color:var(--tb-muted);line-height:1.5;margin-top:12px}\n        #toolibee-image-12920 .tb-note strong{color:var(--tb-navy)}\n        #toolibee-image-12920 .tb-downloads{display:grid;gap:10px;margin-top:14px}\n        #toolibee-image-12920 .tb-download{display:inline-flex;justify-content:center;text-decoration:none;border-radius:999px;padding:11px 18px;font-weight:800;background:var(--tb-gold);color:#1f2937}\n        #toolibee-image-12920 .tb-preview{max-width:100%;border-radius:12px;border:1px solid var(--tb-border);margin-top:10px;background:#fff}\n        @media(max-width:760px){#toolibee-image-12920 .tb-grid,#toolibee-image-12920 .tb-row{grid-template-columns:1fr}#toolibee-image-12920 .tb-header{align-items:flex-start}}\n    <\/style>\n\n    <script>\n    (function(){\n        var root = document.getElementById('toolibee-image-12920');\n        if (!root) return;\n\n        var qs = function(sel){ return root.querySelector(sel); };\n        var output = qs('.tb-output');\n        var downloads = qs('.tb-downloads');\n\n        var libsLoading = null;\n\n        function loadScript(src){\n            return new Promise(function(resolve, reject){\n                var existing = document.querySelector('script[src=\"' + src + '\"]');\n                if (existing) { resolve(); return; }\n                var s = document.createElement('script');\n                s.src = src;\n                s.onload = resolve;\n                s.onerror = reject;\n                document.head.appendChild(s);\n            });\n        }\n\n        function loadLibraries(){\n            if (libsLoading) return libsLoading;\n            libsLoading = Promise.all([\n                loadScript('https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jspdf\/2.5.1\/jspdf.umd.min.js'),\n                loadScript('https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/3.11.174\/pdf.min.js'),\n                loadScript('https:\/\/cdn.jsdelivr.net\/npm\/heic2any@0.0.4\/dist\/heic2any.min.js')\n            ]).then(function(){\n                if (window.pdfjsLib) {\n                    window.pdfjsLib.GlobalWorkerOptions.workerSrc = 'https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/3.11.174\/pdf.worker.min.js';\n                }\n            });\n            return libsLoading;\n        }\n\n        function setStatus(text){ output.textContent = text; }\n        function clearDownloads(){ downloads.innerHTML = ''; }\n\n        function downloadLink(blob, filename){\n            var url = URL.createObjectURL(blob);\n            var a = document.createElement('a');\n            a.className = 'tb-download';\n            a.href = url;\n            a.download = filename;\n            a.textContent = 'Download ' + filename;\n            downloads.appendChild(a);\n        }\n\n        function fileBase(name){\n            return (name || 'converted').replace(\/\\.[^.]+$\/, '').replace(\/[^a-z0-9-_]+\/gi, '-').replace(\/-+\/g, '-').replace(\/^-|-$\/g, '') || 'converted';\n        }\n\n        function readAsDataURL(file){\n            return new Promise(function(resolve, reject){\n                var reader = new FileReader();\n                reader.onload = function(){ resolve(reader.result); };\n                reader.onerror = reject;\n                reader.readAsDataURL(file);\n            });\n        }\n\n        function readAsArrayBuffer(file){\n            return new Promise(function(resolve, reject){\n                var reader = new FileReader();\n                reader.onload = function(){ resolve(reader.result); };\n                reader.onerror = reject;\n                reader.readAsArrayBuffer(file);\n            });\n        }\n\n        function imageFromSource(src){\n            return new Promise(function(resolve, reject){\n                var img = new Image();\n                img.onload = function(){ resolve(img); };\n                img.onerror = reject;\n                img.src = src;\n            });\n        }\n\n        function canvasFromImage(img, maxWidth){\n            var canvas = document.createElement('canvas');\n            var scale = 1;\n            if (maxWidth && img.width > maxWidth) scale = maxWidth \/ img.width;\n            canvas.width = Math.round(img.width * scale);\n            canvas.height = Math.round(img.height * scale);\n            var ctx = canvas.getContext('2d');\n            ctx.drawImage(img, 0, 0, canvas.width, canvas.height);\n            return canvas;\n        }\n\n        function canvasToBlob(canvas, mime, quality){\n            return new Promise(function(resolve){\n                canvas.toBlob(resolve, mime, quality);\n            });\n        }\n\n        async function normalizeHeic(file){\n            var ext = file.name.toLowerCase().split('.').pop();\n            if ((ext === 'heic' || ext === 'heif') && window.heic2any) {\n                return await window.heic2any({blob:file, toType:'image\/jpeg', quality:0.9});\n            }\n            return file;\n        }\n\n        async function imageFileToCanvas(file){\n            file = await normalizeHeic(file);\n            var data = await readAsDataURL(file);\n            var img = await imageFromSource(data);\n            var maxWidth = parseInt(qs('.tb-width').value, 10) || 0;\n            return canvasFromImage(img, maxWidth);\n        }\n\n        async function imagesToPdf(files){\n            await loadLibraries();\n            if (!window.jspdf || !window.jspdf.jsPDF) throw new Error('PDF library did not load.');\n\n            var jsPDF = window.jspdf.jsPDF;\n            var pdf = null;\n\n            for (var i = 0; i < files.length; i++) {\n                setStatus('Adding image ' + (i + 1) + ' of ' + files.length + ' to PDF...');\n                var canvas = await imageFileToCanvas(files[i]);\n                var imgData = canvas.toDataURL('image\/jpeg', 0.92);\n                var orientation = canvas.width > canvas.height ? 'landscape' : 'portrait';\n                var pageW = canvas.width;\n                var pageH = canvas.height;\n\n                if (!pdf) {\n                    pdf = new jsPDF({orientation: orientation, unit: 'px', format: [pageW, pageH]});\n                } else {\n                    pdf.addPage([pageW, pageH], orientation);\n                }\n\n                pdf.addImage(imgData, 'JPEG', 0, 0, pageW, pageH);\n            }\n\n            var blob = pdf.output('blob');\n            downloadLink(blob, 'toolibee-images.pdf');\n        }\n\n        async function imageConvert(files, format){\n            var mime = format === 'png' ? 'image\/png' : (format === 'webp' ? 'image\/webp' : 'image\/jpeg');\n            var ext = format === 'png' ? 'png' : (format === 'webp' ? 'webp' : 'jpg');\n            var quality = parseFloat(qs('.tb-quality').value) || 0.82;\n\n            for (var i = 0; i < files.length; i++) {\n                setStatus('Converting image ' + (i + 1) + ' of ' + files.length + '...');\n                var canvas = await imageFileToCanvas(files[i]);\n                var blob = await canvasToBlob(canvas, mime, quality);\n                downloadLink(blob, fileBase(files[i].name) + '.' + ext);\n\n                if (i === 0) {\n                    var img = document.createElement('img');\n                    img.className = 'tb-preview';\n                    img.src = URL.createObjectURL(blob);\n                    output.innerHTML = 'Preview of first converted image:';\n                    output.appendChild(img);\n                }\n            }\n        }\n\n        async function pdfToJpg(file){\n            await loadLibraries();\n            if (!window.pdfjsLib) throw new Error('PDF.js did not load.');\n\n            var quality = parseFloat(qs('.tb-quality').value) || 0.82;\n            var data = await readAsArrayBuffer(file);\n            var pdf = await window.pdfjsLib.getDocument({data:data}).promise;\n\n            for (var pageNum = 1; pageNum <= pdf.numPages; pageNum++) {\n                setStatus('Converting PDF page ' + pageNum + ' of ' + pdf.numPages + '...');\n                var page = await pdf.getPage(pageNum);\n                var viewport = page.getViewport({scale:2});\n                var canvas = document.createElement('canvas');\n                canvas.width = viewport.width;\n                canvas.height = viewport.height;\n                var ctx = canvas.getContext('2d');\n                await page.render({canvasContext:ctx, viewport:viewport}).promise;\n                var blob = await canvasToBlob(canvas, 'image\/jpeg', quality);\n                downloadLink(blob, fileBase(file.name) + '-page-' + pageNum + '.jpg');\n\n                if (pageNum === 1) {\n                    var img = document.createElement('img');\n                    img.className = 'tb-preview';\n                    img.src = URL.createObjectURL(blob);\n                    output.innerHTML = 'Preview of first converted page:';\n                    output.appendChild(img);\n                }\n            }\n        }\n\n        function syncMode(){\n            var mode = qs('.tb-mode').value;\n            if (mode === 'jpg-pdf' || mode === 'image-pdf') qs('.tb-format').value = 'pdf';\n            if (mode === 'pdf-jpg' || mode === 'heic-jpg') qs('.tb-format').value = 'jpg';\n        }\n\n        qs('.tb-mode').addEventListener('change', syncMode);\n\n        qs('.tb-convert').addEventListener('click', async function(){\n            var files = Array.prototype.slice.call(qs('.tb-files').files || []);\n            var mode = qs('.tb-mode').value;\n            var format = qs('.tb-format').value;\n\n            clearDownloads();\n\n            if (!files.length) {\n                setStatus('Choose at least one file first.');\n                return;\n            }\n\n            try {\n                setStatus('Loading converter...');\n                await loadLibraries();\n\n                if (mode === 'jpg-pdf' || mode === 'image-pdf' || format === 'pdf') {\n                    var imageFiles = files.filter(function(f){ return !\/\\.pdf$\/i.test(f.name); });\n                    if (!imageFiles.length) throw new Error('Choose image files for Image to PDF.');\n                    await imagesToPdf(imageFiles);\n                    setStatus('PDF created. Use the download button below.');\n                    return;\n                }\n\n                if (mode === 'pdf-jpg') {\n                    var pdfFile = files.find(function(f){ return \/\\.pdf$\/i.test(f.name) || f.type === 'application\/pdf'; });\n                    if (!pdfFile) throw new Error('Choose a PDF file for PDF to JPG.');\n                    await pdfToJpg(pdfFile);\n                    setStatus('PDF pages converted to JPG. Use the download buttons below.');\n                    return;\n                }\n\n                if (mode === 'heic-jpg') {\n                    await imageConvert(files, 'jpg');\n                    setStatus('HEIC\/JPG conversion complete. Use the download buttons below.');\n                    return;\n                }\n\n                await imageConvert(files, format);\n                setStatus('Image conversion complete. Use the download buttons below.');\n            } catch (err) {\n                setStatus('Conversion failed: ' + (err && err.message ? err.message : err));\n            }\n        });\n\n        qs('.tb-clear').addEventListener('click', function(){\n            qs('.tb-files').value = '';\n            qs('.tb-mode').value = 'jpg-pdf';\n            qs('.tb-format').value = 'pdf';\n            qs('.tb-quality').value = '0.82';\n            qs('.tb-width').value = '';\n            qs('.tb-one-pdf').checked = true;\n            clearDownloads();\n            setStatus('Choose a file and select a conversion type.');\n        });\n\n        syncMode();\n    })();\n    <\/script>\n    \n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"page-no-title","meta":{"footnotes":""},"class_list":["post-541","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/toolibee.com\/index.php?rest_route=\/wp\/v2\/pages\/541","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/toolibee.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/toolibee.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/toolibee.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/toolibee.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=541"}],"version-history":[{"count":1,"href":"https:\/\/toolibee.com\/index.php?rest_route=\/wp\/v2\/pages\/541\/revisions"}],"predecessor-version":[{"id":542,"href":"https:\/\/toolibee.com\/index.php?rest_route=\/wp\/v2\/pages\/541\/revisions\/542"}],"wp:attachment":[{"href":"https:\/\/toolibee.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=541"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}