{"id":20987,"date":"2026-04-10T13:48:53","date_gmt":"2026-04-10T13:48:53","guid":{"rendered":"https:\/\/kentekenvideo.nl\/index.php\/jj351d\/"},"modified":"2026-04-15T23:37:41","modified_gmt":"2026-04-15T23:37:41","slug":"jj351d","status":"publish","type":"page","link":"https:\/\/kentekenvideo.nl\/index.php\/jj351d\/","title":{"rendered":"JJ351D"},"content":{"rendered":"    <div class=\"ksb-wrapper\">\r\n                \r\n        <form class=\"ksb-form\" method=\"POST\" action=\"https:\/\/kentekenvideo.nl\/wp-admin\/admin-post.php\">\r\n            <input type=\"hidden\" name=\"action\" value=\"ksb_process_search\">\r\n            <input type=\"hidden\" id=\"ksb_nonce\" name=\"ksb_nonce\" value=\"bb396dd705\" \/><input type=\"hidden\" name=\"_wp_http_referer\" value=\"\/index.php\/wp-json\/wp\/v2\/pages\/20987\" \/>            <input type=\"text\" \r\n                   name=\"ksb_kenteken\" \r\n                   placeholder=\"Voer kenteken in (bijv. 53-JGG-2)\"\r\n                   required>\r\n            <button type=\"submit\">Zoeken<\/button>\r\n        <\/form>\r\n    <\/div>\r\n    \r\n<!-- Car Promo Info: Geen kenteken gevonden in slug of attribuut. -->\r\n        <div class=\"kpv-gallery\">\r\n                                                <div class=\"kpv-item\">\r\n                        <img decoding=\"async\" src=\"https:\/\/kentekenvideo.nl\/wp-content\/Photo-Approved\/JJ351D\/JJ351D_image_1.jpg\" \r\n                            alt=\"Voertuigfoto: JJ351D_image_1.jpg\"\r\n                            class=\"kpv-thumbnail\"\r\n                            data-full=\"https:\/\/kentekenvideo.nl\/wp-content\/Photo-Approved\/JJ351D\/JJ351D_image_1.jpg\">\r\n                    <\/div>\r\n                                    <\/div>\r\n\r\n                    <!-- Fullscreen Overlay HTML for Image Gallery -->\r\n            <div class=\"kpv-overlay\">\r\n                <div class=\"kpv-close-btn\" aria-label=\"Close photo viewer\"><\/div>\r\n                <button class=\"kpv-nav-btn kpv-prev-btn\" aria-label=\"Previous image\">\r\n                    <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"\/><\/svg>\r\n                <\/button>\r\n                <button class=\"kpv-nav-btn kpv-next-btn\" aria-label=\"Next image\">\r\n                    <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"\/><\/svg>\r\n                <\/button>\r\n                <div class=\"kpv-overlay-content\">\r\n                    <img decoding=\"async\" class=\"kpv-overlay-image\" src=\"\" alt=\"Volledige afbeelding\">\r\n                <\/div>\r\n            <\/div>\r\n                \r\n        \r\n        \r\n\r\n        <style>\r\n            .kpm-poster-btn {\r\n                background-color: #0073aa; border: 1px solid #006799; color: white; padding: 10px 20px;\r\n                text-align: center; text-decoration: none; display: inline-block; font-size: 16px; cursor: pointer;\r\n                border-radius: 4px; transition: background-color 0.2s ease-in-out; margin: 0;\r\n                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n            }\r\n            .kpm-poster-btn:hover { background-color: #006799; }\r\n            .kpm-modal { display: none; position: fixed; z-index: 999999; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.85); backdrop-filter: blur(4px); }\r\n            .kpm-modal-content { background-color: #fff; margin: 2% auto; width: 95%; max-width: 1100px; height: 90vh; border-radius: 8px; display: flex; flex-direction: column; overflow: hidden; font-family: sans-serif; }\r\n            .kpm-header { padding: 15px 20px; background: #f0f0f1; border-bottom: 1px solid #ddd; display: flex; justify-content: space-between; align-items: center; }\r\n            .kpm-close { font-size: 28px; cursor: pointer; line-height: 1; }\r\n            .kpm-body { display: flex; flex: 1; overflow: hidden; }\r\n            .kpm-controls { width: 350px; padding: 20px; overflow-y: auto; background: #f9f9f9; border-right: 1px solid #ddd; display: flex; flex-direction: column; gap: 20px; }\r\n            .kpm-section h4 { margin: 0 0 10px 0; font-size: 16px; color: #333; }\r\n            .kpm-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; }\r\n            .kpm-thumb { width: 100%; aspect-ratio: 1\/1; object-fit: cover; cursor: pointer; border: 2px solid transparent; border-radius: 4px; }\r\n            .kpm-thumb.selected { border-color: #0073aa; opacity: 0.7; }\r\n            .kpm-input-row { margin-bottom: 10px; }\r\n            .kpm-input-row label { display: block; font-size: 12px; font-weight: bold; margin-bottom: 4px; }\r\n            .kpm-input-row input[type=\"text\"], .kpm-input-row select { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; }\r\n            .kpm-checkbox-label { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13px; font-weight: bold; }\r\n            .kpm-checkbox-label input { margin: 0; width: auto; cursor: pointer; }\r\n            .kpm-specs-list label { display: block; font-size: 13px; margin-bottom: 4px; cursor: pointer; }\r\n            .kpm-preview { flex: 1; background: #444; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 20px; }\r\n            #kpm-canvas { max-width: 100%; max-height: 85%; box-shadow: 0 0 20px rgba(0,0,0,0.5); background: white; }\r\n            .kpm-download-btn { margin-top: 15px; background: #46b450; color: white; padding: 10px 25px; text-decoration: none; border-radius: 5px; font-weight: bold; display: inline-block; }\r\n            .kpm-download-btn:hover { background: #36933f; color: white; }\r\n            @media (max-width: 768px) { .kpm-body { flex-direction: column-reverse; } .kpm-controls { width: 100%; height: 50%; } .kpm-preview { height: 50%; } }\r\n            #kpm-wrapper { display: inline-block; }\r\n        <\/style>\r\n\r\n        <span id=\"kpm-wrapper\"><button id=\"kpm-trigger\" class=\"kpm-poster-btn\" data-kenteken=\"jj351d\">Maak een Poster<\/button><\/span>\r\n\r\n        <div id=\"kpm-modal\" class=\"kpm-modal\">\r\n            <div class=\"kpm-modal-content\">\r\n                <div class=\"kpm-header\"><h3 style=\"margin:0\">Poster Maken: jj351d<\/h3><span class=\"kpm-close\">&times;<\/span><\/div>\r\n                <div class=\"kpm-body\">\r\n                    <div class=\"kpm-controls\">\r\n                        <div class=\"kpm-section\"><h4>1. Kies Foto<\/h4><div id=\"kpm-photo-grid\" class=\"kpm-grid\"><em>Laden...<\/em><\/div><\/div>\r\n                        <div class=\"kpm-section\">\r\n                            <h4>2. Instellingen<\/h4>\r\n                            <div class=\"kpm-input-row\"><label>Ori\u00ebntatie<\/label><select id=\"kpm-orient\"><option value=\"v\">Verticaal (Standaard)<\/option><option value=\"h\">Horizontaal<\/option><\/select><\/div>\r\n                            <div class=\"kpm-input-row\"><label>Prijs (\u20ac)<\/label><input type=\"text\" id=\"kpm-price\" placeholder=\"Bijv. 14.500,-\"><\/div>\r\n                            <div class=\"kpm-input-row\"><label>Contact Info<\/label><input type=\"text\" id=\"kpm-contact\" placeholder=\"\"><\/div>\r\n                            <div class=\"kpm-input-row\">\r\n                                <label class=\"kpm-checkbox-label\">\r\n                                    <input type=\"checkbox\" id=\"kpm-show-plate\"> Toon Kentekenplaat\r\n                                <\/label>\r\n                            <\/div>\r\n                        <\/div>\r\n                        <div class=\"kpm-section\"><h4>3. Specificaties<\/h4><div id=\"kpm-specs\" class=\"kpm-specs-list\"><em>Laden...<\/em><\/div><\/div>\r\n                    <\/div>\r\n                    <div class=\"kpm-preview\"><canvas id=\"kpm-canvas\" width=\"800\" height=\"1200\"><\/canvas><a href=\"#\" id=\"kpm-download\" class=\"kpm-download-btn\">Download Poster<\/a><\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <script>\r\n        document.addEventListener('DOMContentLoaded', function() {\r\n            const kpmBtn = document.getElementById('kpm-trigger');\r\n            const kpmWrapper = document.getElementById('kpm-wrapper');\r\n            const targetContainer = document.querySelector('.kvg-button-container');\r\n            if (kpmBtn && targetContainer) { targetContainer.prepend(kpmBtn); if(kpmWrapper) kpmWrapper.style.display = 'none'; }\r\n\r\n            const modal = document.getElementById('kpm-modal');\r\n            const close = document.querySelector('.kpm-close');\r\n            const canvas = document.getElementById('kpm-canvas');\r\n            const ctx = canvas.getContext('2d');\r\n            const photoGrid = document.getElementById('kpm-photo-grid');\r\n            const specsList = document.getElementById('kpm-specs');\r\n            const dlBtn = document.getElementById('kpm-download');\r\n            \r\n            let vehicleData = { images: [], specs: {}, formatted_kenteken: '', stars_svg: '' };\r\n            let selectedImage = null;\r\n            let loadedImg = new Image();\r\n            let watermarkImg = new Image();\r\n            watermarkImg.crossOrigin = \"Anonymous\";\r\n            watermarkImg.src = \"https:\/\/kentekenvideo.nl\/wp-content\/uploads\/2025\/05\/cropped-logoV3-removebg-preview.png\";\r\n            let starsImg = new Image();\r\n\r\n            if(kpmBtn) kpmBtn.addEventListener('click', function(e) { e.preventDefault(); modal.style.display = 'block'; if(!vehicleData.images.length) fetchData(this.dataset.kenteken); });\r\n            if(close) { close.addEventListener('click', () => modal.style.display = 'none'); window.addEventListener('click', (e) => { if(e.target == modal) modal.style.display = 'none'; }); }\r\n\r\n            function fetchData(kenteken) {\r\n                const fd = new FormData(); fd.append('action', 'kpm_get_data'); fd.append('kenteken', kenteken);\r\n                fetch('https:\/\/kentekenvideo.nl\/wp-admin\/admin-ajax.php', { method: 'POST', body: fd }).then(r => r.json()).then(res => {\r\n                    if(res.success) { vehicleData = res.data; starsImg.src = vehicleData.stars_svg; renderUI(); } \r\n                    else photoGrid.innerHTML = 'Geen data.';\r\n                });\r\n            }\r\n\r\n            function renderUI() {\r\n                photoGrid.innerHTML = '';\r\n                if(vehicleData.images.length) {\r\n                    vehicleData.images.forEach((url, i) => {\r\n                        const img = document.createElement('img'); img.src = url; img.className = 'kpm-thumb';\r\n                        if(i===0) img.classList.add('selected');\r\n                        img.onclick = () => { document.querySelectorAll('.kpm-thumb').forEach(t => t.classList.remove('selected')); img.classList.add('selected'); selectImage(url); };\r\n                        photoGrid.appendChild(img); if(i===0) selectImage(url);\r\n                    });\r\n                } else photoGrid.innerHTML = 'Geen foto\\'s.';\r\n\r\n                specsList.innerHTML = '';\r\n                const defaults = ['Merk', 'Model', 'Bouwjaar', 'APK tot'];\r\n                for(let key in vehicleData.specs) {\r\n                    if(vehicleData.specs[key]) {\r\n                        const div = document.createElement('div');\r\n                        const isChecked = defaults.includes(key) ? 'checked' : '';\r\n                        div.innerHTML = `<label><input type=\"checkbox\" class=\"kpm-spec-check\" value=\"${key}\" ${isChecked}> ${key}: ${vehicleData.specs[key]}<\/label>`;\r\n                        specsList.appendChild(div);\r\n                    }\r\n                }\r\n                \r\n                document.querySelectorAll('.kpm-spec-check').forEach(c => c.addEventListener('change', draw));\r\n                document.getElementById('kpm-orient').addEventListener('change', draw);\r\n                document.getElementById('kpm-show-plate').addEventListener('change', draw);\r\n                ['kpm-price', 'kpm-contact'].forEach(id => document.getElementById(id).addEventListener('input', draw));\r\n            }\r\n\r\n            function selectImage(url) {\r\n                selectedImage = url; loadedImg = new Image(); loadedImg.crossOrigin = \"Anonymous\"; loadedImg.src = url; loadedImg.onload = draw;\r\n            }\r\n\r\n            function draw() {\r\n                if(!selectedImage) return;\r\n                const orient = document.getElementById('kpm-orient').value;\r\n                const showPlate = document.getElementById('kpm-show-plate').checked;\r\n                const isVert = orient === 'v';\r\n                const w = isVert ? 800 : 1200; const h = isVert ? 1200 : 800;\r\n                canvas.width = w; canvas.height = h;\r\n\r\n                \/\/ --- 50% Scaling Logic for Horizontal Mode ---\r\n                let specScale = 1;\r\n                let plateScale = 1;\r\n                let priceScale = 1; \/\/ New in 1.6\r\n                \r\n                if (!isVert) { \/\/ If Horizontal\r\n                    specScale = 0.5;\r\n                    plateScale = 0.5;\r\n                    priceScale = 0.5; \/\/ New in 1.6\r\n                }\r\n                \/\/ ---------------------------------------------\r\n\r\n                \/\/ 1. Background\r\n                const iRatio = loadedImg.width \/ loadedImg.height; const cRatio = w \/ h;\r\n                let dw, dh, dx, dy;\r\n                if(iRatio > cRatio) { dh = h; dw = h * iRatio; dx = (w - dw)\/2; dy = 0; } else { dw = w; dh = w \/ iRatio; dx = 0; dy = (h - dh)\/2; }\r\n                ctx.drawImage(loadedImg, dx, dy, dw, dh);\r\n\r\n                \/\/ 2. Gradient\r\n                const grad = ctx.createLinearGradient(0, h * 0.4, 0, h);\r\n                grad.addColorStop(0, \"rgba(0,0,0,0)\"); grad.addColorStop(0.7, \"rgba(0,0,0,0.8)\"); grad.addColorStop(1, \"rgba(0,0,0,0.95)\");\r\n                ctx.fillStyle = grad; ctx.fillRect(0, h * 0.4, w, h * 0.6);\r\n\r\n                \/\/ 3. Header \"TE KOOP\" (Standard sizing, not scaled)\r\n                const headerFontSize = w * 0.1;\r\n                const headerY = w * 0.12;\r\n                ctx.save();\r\n                ctx.fillStyle = \"#fff\"; ctx.shadowColor = \"rgba(0,0,0,0.8)\"; ctx.shadowBlur = 15; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 4;\r\n                ctx.textAlign = \"center\"; ctx.font = `bold ${headerFontSize}px Arial`;\r\n                ctx.fillText(\"TE KOOP\", w\/2, headerY);\r\n                ctx.restore();\r\n\r\n                \/\/ 4. Calculate Plate Dimensions (with Scaling)\r\n                let plateH = 0;\r\n                let plateY = h; \r\n                let plateW = 0;\r\n                \r\n                if(showPlate && vehicleData.formatted_kenteken) {\r\n                     \/\/ Standard is 35% width, Apply Scale Factor\r\n                     plateW = (w * 0.35) * plateScale;\r\n                     plateH = plateW \/ 4.7;\r\n                     plateY = h - plateH - 30; \r\n                }\r\n\r\n                \/\/ 5. Specs (with Scaling)\r\n                ctx.fillStyle = \"#fff\"; ctx.shadowColor = \"rgba(0,0,0,0.5)\"; ctx.shadowBlur = 10;\r\n                ctx.textAlign = \"left\"; \r\n                \r\n                \/\/ Standard is 3.5% width, Apply Scale Factor\r\n                const specFontSize = (w * 0.035) * specScale;\r\n                const lineHeight = (w * 0.045) * specScale;\r\n                \r\n                ctx.font = `${specFontSize}px Arial`;\r\n                \r\n                const checkedSpecs = document.querySelectorAll('.kpm-spec-check:checked');\r\n                const totalSpecsHeight = checkedSpecs.length * lineHeight;\r\n                \r\n                let startSpecY;\r\n                if (showPlate) {\r\n                    startSpecY = plateY - totalSpecsHeight - 20; \r\n                } else {\r\n                    startSpecY = h - (h*0.28); \r\n                    if (startSpecY + totalSpecsHeight > h - 50) {\r\n                        startSpecY = h - 50 - totalSpecsHeight; \r\n                    }\r\n                }\r\n\r\n                let ty = startSpecY + lineHeight;\r\n                const lx = w * 0.05;\r\n                checkedSpecs.forEach(chk => {\r\n                    ctx.fillText(`\u2022 ${chk.value}: ${vehicleData.specs[chk.value]}`, lx, ty); \r\n                    ty += lineHeight;\r\n                });\r\n\r\n                \/\/ 6. Price (with Scaling in 1.6)\r\n                const priceVal = document.getElementById('kpm-price').value;\r\n                if(priceVal) {\r\n                    const pTxt = \"\u20ac \" + priceVal;\r\n                    \r\n                    \/\/ Apply Price Scale\r\n                    const pFontSize = (w * 0.06) * priceScale;\r\n                    ctx.font = `bold ${pFontSize}px Arial`;\r\n                    \r\n                    \/\/ Scale padding constants so box shrinks too\r\n                    const padX = 40 * priceScale;\r\n                    const padY = 30 * priceScale;\r\n                    const textLift = 18 * priceScale;\r\n                    \r\n                    const pMet = ctx.measureText(pTxt);\r\n                    const bw = pMet.width + padX; \r\n                    const bh = pFontSize + padY;\r\n                    \r\n                    const priceY = headerY + (headerFontSize * 0.5); \r\n                    ctx.fillStyle = \"#e67e22\"; ctx.shadowBlur = 0;\r\n                    ctx.fillRect(w - bw - 20, priceY, bw, bh);\r\n                    ctx.fillStyle = \"#fff\"; ctx.textAlign = \"center\";\r\n                    ctx.fillText(pTxt, w - 20 - (bw\/2), priceY + bh - textLift);\r\n                }\r\n\r\n                \/\/ 7. Contact (Standard Sizing)\r\n                const contact = document.getElementById('kpm-contact').value;\r\n                if(contact) {\r\n                    ctx.fillStyle = \"#ccc\"; ctx.font = `italic ${w * 0.03}px Arial`;\r\n                    ctx.textAlign = \"center\"; ctx.shadowBlur = 4; ctx.shadowColor = \"#000\";\r\n                    ctx.fillText(contact, w\/2, h - 20);\r\n                }\r\n\r\n                \/\/ 8. Watermark (Standard Sizing)\r\n                if(watermarkImg.complete && watermarkImg.naturalWidth > 0) {\r\n                     const wmScale = w * 0.25 \/ watermarkImg.width;\r\n                     const wmW = watermarkImg.width * wmScale; const wmH = watermarkImg.height * wmScale;\r\n                     ctx.globalAlpha = 0.9;\r\n                     ctx.drawImage(watermarkImg, w - wmW - 20, h - wmH - 20, wmW, wmH);\r\n                     ctx.globalAlpha = 1.0;\r\n                }\r\n\r\n                \/\/ 9. Draw Plate\r\n                if(showPlate && vehicleData.formatted_kenteken) {\r\n                    drawLicensePlate(ctx, 30, plateY, plateW, plateH, vehicleData.formatted_kenteken);\r\n                }\r\n\r\n                dlBtn.href = canvas.toDataURL(\"image\/png\");\r\n                dlBtn.download = `Poster-${kpmBtn.dataset.kenteken}.png`;\r\n            }\r\n\r\n            function drawLicensePlate(ctx, x, y, w, h, text) {\r\n                const r = 5; \r\n                ctx.fillStyle = \"#FECC00\"; ctx.strokeStyle = \"#000\"; ctx.lineWidth = 2;\r\n                ctx.beginPath(); ctx.roundRect(x, y, w, h, r); ctx.fill(); ctx.stroke();\r\n                const blueW = w * 0.15;\r\n                ctx.fillStyle = \"#003399\";\r\n                ctx.beginPath(); ctx.roundRect(x, y, blueW, h, [r, 0, 0, r]); ctx.fill();\r\n                if(starsImg.complete) {\r\n                    const sSize = blueW * 0.7;\r\n                    ctx.drawImage(starsImg, x + (blueW - sSize)\/2, y + (h * 0.1), sSize, sSize);\r\n                }\r\n                ctx.fillStyle = \"#FFF\"; ctx.font = `bold ${h * 0.25}px Arial`;\r\n                ctx.textAlign = \"center\"; ctx.fillText(\"NL\", x + blueW\/2, y + h - (h*0.1));\r\n                ctx.fillStyle = \"#000\"; ctx.font = `bold ${h * 0.65}px \"Courier New\", monospace`;\r\n                const textCenter = x + blueW + ((w - blueW)\/2);\r\n                ctx.fillText(text, textCenter, y + (h * 0.7));\r\n            }\r\n        });\r\n        <\/script>\r\n        \r\n<div class=\"kvg-video-generator-container\">\r\n        <div class=\"kvg-button-container\" style=\"margin: 10px 0;\">\r\n            <button class=\"kvg-generate-video-button\" data-kenteken=\"JJ351D\">Genereer een Video<\/button>\r\n            <div class=\"rdw-report-container\" data-kenteken=\"JJ351D\"><button class=\"rdw-generate-report-btn\">Genereer een RDW-Voertuigrapport<\/button><\/div>        <\/div>\r\n        <div id=\"kvg-orientation-chooser\" style=\"display: none; margin: 15px 0;\">\r\n            <p style=\"font-size: 16px; margin-bottom: 10px;\">Kies de video ori\u00ebntatie:<\/p>\r\n            <button class=\"kvg-orientation-btn\" data-orientation=\"horizontal\">\ud83d\udcbb Horizontaal<\/button>\r\n            <button class=\"kvg-orientation-btn\" data-orientation=\"vertical\">\ud83d\udcf1 Verticaal<\/button>\r\n        <\/div>\r\n        <div id=\"kvg-progress-container\" style=\"display: none;\"><div id=\"kvg-progress-label\"><\/div><div class=\"kvg-progress-bar-outer\"><div id=\"kvg-progress-bar-inner\"><\/div><\/div><\/div>\r\n        <div id=\"kvg-video-output\"><\/div>\r\n    <\/div>\r\n            <style>\r\n            .kvg-video-generator-container { text-align: center; margin: 20px 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; }\r\n            .kvg-button-container { display: flex; justify-content: center; align-items: center; gap: 10px; flex-wrap: wrap; }\r\n            .kvg-generate-video-button, .kvg-orientation-btn { background-color: #0073aa; border: 1px solid #006799; color: white; padding: 10px 20px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; cursor: pointer; border-radius: 4px; transition: background-color 0.2s ease-in-out; margin: 0; }\r\n            .kvg-generate-video-button:hover, .kvg-orientation-btn:hover { background-color: #006799; }\r\n            .kvg-generate-video-button:disabled { background-color: #a0a5aa; cursor: not-allowed; opacity: 0.7; }\r\n            #kvg-progress-container { margin-top: 15px; text-align: left; max-width: 500px; margin-left: auto; margin-right: auto; }\r\n            #kvg-progress-label { margin-bottom: 5px; font-size: 14px; color: #444; }\r\n            .kvg-progress-bar-outer { width: 100%; height: 20px; background-color: #e0e0e0; border: 1px solid #ccc; border-radius: 10px; overflow: hidden; }\r\n            #kvg-progress-bar-inner { width: 0%; height: 100%; background-color: #0073aa; border-radius: 10px 0 0 10px; transition: width 0.3s ease-in-out; text-align: center; color: white; line-height: 20px; font-size: 12px; font-weight: bold; }\r\n            #kvg-video-output video { max-width: 100%; height: auto; margin-top: 15px; border: 1px solid #ddd; background-color: #f0f0f0; }\r\n        <\/style>\r\n        <script>\r\n        document.addEventListener('DOMContentLoaded', function() {\r\n            const generateButton = document.querySelector('.kvg-generate-video-button');\r\n            if (!generateButton) return;\r\n\r\n            const orientationChooser = document.getElementById('kvg-orientation-chooser');\r\n            const videoContainer = document.getElementById('kvg-video-output');\r\n            const progressContainer = document.getElementById('kvg-progress-container');\r\n            const progressLabel = document.getElementById('kvg-progress-label');\r\n            const progressBar = document.getElementById('kvg-progress-bar-inner');\r\n            const kenteken = generateButton.dataset.kenteken;\r\n\r\n            generateButton.addEventListener('click', function() {\r\n                orientationChooser.style.display = 'block';\r\n            });\r\n\r\n            document.querySelectorAll('.kvg-orientation-btn').forEach(btn => {\r\n                btn.addEventListener('click', function() {\r\n                    orientationChooser.style.display = 'none';\r\n                    const orientation = this.dataset.orientation;\r\n                    let videoWidth, videoHeight;\r\n                    if (orientation === 'horizontal') {\r\n                        videoWidth = 1920; videoHeight = 1080;\r\n                    } else {\r\n                        videoWidth = 1080; videoHeight = 1920;\r\n                    }\r\n                    startGeneration(videoWidth, videoHeight);\r\n                });\r\n            });\r\n\r\n            async function startGeneration(videoWidth, videoHeight) {\r\n                generateButton.disabled = true; generateButton.textContent = 'Bezig met genereren...';\r\n                videoContainer.innerHTML = ''; progressContainer.style.display = 'block';\r\n                progressLabel.style.color = '#444'; progressBar.style.backgroundColor = '#0073aa';\r\n                updateProgress(0, 'Starten...');\r\n\r\n                try {\r\n                    updateProgress(5, 'Stap 1\/4: Data ophalen...');\r\n                    const [imageUrls, rdwData] = await Promise.all([ fetchData('kvg_get_images', kenteken), fetchData('kvg_get_rdw_info', kenteken) ]);\r\n                    if (imageUrls.length === 0) { throw new Error('Helaas zijn er geen foto\\'s beschikbaar.'); }\r\n                    \r\n                    updateProgress(15, 'Stap 2\/4: Assets laden...');\r\n                    const [loadedImages, watermarkImage, euStarsImage] = await Promise.all([ preloadImages(imageUrls), preloadImage('https:\/\/kentekenvideo.nl\/wp-content\/uploads\/2025\/05\/cropped-logoV3-removebg-preview.png'), preloadImage(rdwData.eu_stars_svg_data_url) ]);\r\n                    \r\n                    updateProgress(45, 'Stap 3\/4: Video renderen...');\r\n                    const videoBlob = await generateVideoFromImages(loadedImages, rdwData, watermarkImage, euStarsImage, videoWidth, videoHeight);\r\n\r\n                    \/\/ CHANGE V2.5.5: Changed progress message\r\n                    updateProgress(100, 'Stap 4\/4: Video succesvol gegenereerd!');\r\n                    \r\n                    const videoUrl = URL.createObjectURL(videoBlob);\r\n                    const videoElement = document.createElement('video');\r\n                    videoElement.src = videoUrl; videoElement.controls = true; videoElement.autoplay = true;\r\n                    videoElement.style.maxWidth = '100%';\r\n                    videoContainer.innerHTML = ''; videoContainer.appendChild(videoElement);\r\n                    \r\n                    \/\/ CHANGE V2.5.5: Removed automatic download\r\n                    \/\/ const a = document.createElement('a');\r\n                    \/\/ a.style.display = 'none'; a.href = videoUrl; a.download = `video-${kenteken}.webm`;\r\n                    \/\/ document.body.appendChild(a); a.click();\r\n                    \/\/ setTimeout(() => { document.body.removeChild(a); }, 100);\r\n\r\n                } catch (error) {\r\n                    progressLabel.textContent = 'Fout: ' + error.message;\r\n                    progressLabel.style.color = 'red'; progressBar.style.backgroundColor = '#dc3232';\r\n                } finally {\r\n                    generateButton.disabled = false; generateButton.textContent = 'Genereer een Video';\r\n                    setTimeout(() => { progressContainer.style.display = 'none'; }, 8000);\r\n                }\r\n            }\r\n\r\n            function updateProgress(percentage, label) { const p = Math.round(percentage); progressBar.style.width = p + '%'; progressBar.textContent = p + '%'; progressLabel.textContent = label; }\r\n\r\n            async function fetchData(action, kenteken) {\r\n                const formData = new FormData();\r\n                formData.append('action', action); formData.append('kenteken', kenteken);\r\n                const response = await fetch('https:\/\/kentekenvideo.nl\/wp-admin\/admin-ajax.php', { method: 'POST', body: formData });\r\n                if (!response.ok) { throw new Error(`Serverfout (HTTP Status: ${response.status})`); }\r\n                const result = await response.json();\r\n                if (!result.success) { throw new Error(result.data.message || 'Onbekende fout.'); }\r\n                return result.data;\r\n            }\r\n\r\n            async function preloadImage(url) {\r\n                return new Promise((resolve, reject) => {\r\n                    const image = new Image(); image.crossOrigin = 'Anonymous';\r\n                    image.onload = () => resolve(image);\r\n                    image.onerror = () => reject(new Error(`Kon asset niet laden: ${url}`));\r\n                    image.src = url;\r\n                });\r\n            }\r\n\r\n            async function preloadImages(urls) {\r\n                const promises = urls.map(url => preloadImage(url));\r\n                return Promise.all(promises);\r\n            }\r\n\r\n            function drawWatermark(ctx, watermarkImage) {\r\n                const padding = 30;\r\n                const scale = 1.0;\r\n                const w = watermarkImage.width * scale;\r\n                const h = watermarkImage.height * scale;\r\n                const x = ctx.canvas.width - w - padding;\r\n                const y = padding;\r\n                ctx.drawImage(watermarkImage, x, y, w, h);\r\n            }\r\n\r\n            function drawLicensePlate(ctx, formattedKenteken, euStarsImage) {\r\n                const plateHeight = 80; const plateWidth = 375;\r\n                const padding = 30; const x = padding; const y = padding;\r\n                const borderRadius = 10; const euStripWidth = 65;\r\n                ctx.fillStyle = '#003399'; ctx.beginPath(); ctx.roundRect(x, y, plateWidth, plateHeight, borderRadius); ctx.fill();\r\n                ctx.fillStyle = '#FECC00'; ctx.beginPath(); ctx.roundRect(x + euStripWidth, y, plateWidth - euStripWidth, plateHeight, [0, borderRadius, borderRadius, 0]); ctx.fill();\r\n                const starsSize = 40; ctx.drawImage(euStarsImage, x + (euStripWidth - starsSize) \/ 2, y + 8, starsSize, starsSize);\r\n                ctx.fillStyle = '#FFFFFF'; ctx.font = 'bold 20px Arial'; ctx.textAlign = 'center';\r\n                ctx.fillText('NL', x + euStripWidth \/ 2, y + plateHeight - 20);\r\n                ctx.fillStyle = '#000000'; ctx.font = \"bold 52px 'Kenteken', 'DIN 1451 Engschrift', monospace\";\r\n                ctx.textAlign = 'center'; ctx.fillText(formattedKenteken, x + euStripWidth + (plateWidth - euStripWidth) \/ 2, y + plateHeight \/ 2 + 4);\r\n            }\r\n\r\n            function drawRdwOverlay(ctx, textToDisplay, videoWidth) {\r\n                const canvasHeight = ctx.canvas.height;\r\n                const barHeight = (videoWidth === 1920) ? 80 : 100;\r\n                const barY = canvasHeight - barHeight;\r\n                ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';\r\n                ctx.fillRect(0, barY, videoWidth, barHeight);\r\n                ctx.fillStyle = '#FFFFFF';\r\n                ctx.textBaseline = 'middle';\r\n                const fontSize = (videoWidth === 1920) ? 42 : 48;\r\n                ctx.font = `bold ${fontSize}px Arial`;\r\n                if (videoWidth === 1920) {\r\n                    ctx.textAlign = 'left';\r\n                    ctx.fillText(textToDisplay, 30, barY + barHeight \/ 2);\r\n                } else {\r\n                    ctx.textAlign = 'center';\r\n                    ctx.fillText(textToDisplay, videoWidth \/ 2, barY + barHeight \/ 2);\r\n                }\r\n            }\r\n\r\n            async function generateVideoFromImages(loadedImages, rdwData, watermarkImage, euStarsImage, videoWidth, videoHeight) {\r\n                const frameDuration = 2000; \r\n                const transitionDuration = 500;\r\n                \r\n                const canvas = document.createElement('canvas'); canvas.width = videoWidth; canvas.height = videoHeight; const ctx = canvas.getContext('2d');\r\n                const stream = canvas.captureStream();\r\n                const recorder = new MediaRecorder(stream, { mimeType: 'video\/webm;codecs=vp9' });\r\n                const chunks = [];\r\n                recorder.ondataavailable = event => { if (event.data.size > 0) chunks.push(event.data); };\r\n                const recorderPromise = new Promise(resolve => { recorder.onstop = () => resolve(new Blob(chunks, { type: 'video\/webm' })); });\r\n                \r\n                recorder.start();\r\n\r\n                for (let i = 0; i < loadedImages.length; i++) {\r\n                    const progress = 45 + ((i + 1) \/ loadedImages.length) * 55;\r\n                    updateProgress(progress, `Stap 3\/4: Frame ${i + 1} van ${loadedImages.length} renderen...`);\r\n                    \r\n                    const currentImage = loadedImages[i];\r\n                    const nextImage = (i + 1 < loadedImages.length) ? loadedImages[i + 1] : null;\r\n                    const infoText = rdwData.overlay_texts[i % rdwData.overlay_texts.length];\r\n                    \r\n                    drawImageWithBlurredBg(ctx, currentImage, videoWidth, videoHeight);\r\n                    drawRdwOverlay(ctx, infoText, videoWidth);\r\n                    drawWatermark(ctx, watermarkImage);\r\n                    drawLicensePlate(ctx, rdwData.formatted_kenteken, euStarsImage);\r\n                    await new Promise(r => setTimeout(r, frameDuration - (nextImage ? transitionDuration : 0)));\r\n\r\n                    if (nextImage) {\r\n                        const nextInfoText = rdwData.overlay_texts[(i + 1) % rdwData.overlay_texts.length];\r\n                        const startTime = performance.now();\r\n                        while (performance.now() - startTime < transitionDuration) {\r\n                            const p = (performance.now() - startTime) \/ transitionDuration;\r\n                            ctx.globalAlpha = 1 - p;\r\n                            drawImageWithBlurredBg(ctx, currentImage, videoWidth, videoHeight);\r\n                            drawRdwOverlay(ctx, infoText, videoWidth);\r\n                            \r\n                            ctx.globalAlpha = p;\r\n                            drawImageWithBlurredBg(ctx, nextImage, videoWidth, videoHeight);\r\n                            drawRdwOverlay(ctx, nextInfoText, videoWidth);\r\n\r\n                            ctx.globalAlpha = 1;\r\n                            drawWatermark(ctx, watermarkImage);\r\n                            drawLicensePlate(ctx, rdwData.formatted_kenteken, euStarsImage);\r\n                            await new Promise(r => requestAnimationFrame(r));\r\n                        }\r\n                    }\r\n                }\r\n                recorder.stop(); return recorderPromise;\r\n            }\r\n\r\n            function drawImageWithBlurredBg(ctx, img, canvasWidth, canvasHeight) {\r\n                ctx.filter = 'blur(20px)';\r\n                const imgRatio = img.width \/ img.height; const canvasRatio = canvasWidth \/ canvasHeight;\r\n                let sWidth = img.width, sHeight = img.height, sx = 0, sy = 0;\r\n                if (imgRatio > canvasRatio) { sHeight = img.height; sWidth = sHeight * canvasRatio; sx = (img.width - sWidth) \/ 2; } \r\n                else { sWidth = img.width; sHeight = sWidth \/ canvasRatio; sy = (img.height - sHeight) \/ 2; }\r\n                ctx.drawImage(img, sx, sy, sWidth, sHeight, 0, 0, canvasWidth, canvasHeight);\r\n                ctx.filter = 'none';\r\n                let newWidth, newHeight, offsetX, offsetY;\r\n                if (imgRatio > canvasRatio) { newWidth = canvasWidth; newHeight = canvasWidth \/ imgRatio; } \r\n                else { newHeight = canvasHeight; newWidth = canvasHeight * imgRatio; }\r\n                offsetX = (canvasWidth - newWidth) \/ 2;\r\n                offsetY = (canvasHeight - newHeight) \/ 2;\r\n                ctx.drawImage(img, offsetX, offsetY, newWidth, newHeight);\r\n            }\r\n        });\r\n        <\/script>\r\n        \r\n<div id=\"site-ad-wrapper-69e0366d03e5c\" class=\"site-ad-wrapper\" data-ad-id=\"ad_slot_2\" data-instance-id=\"69e0366d03e5c\"><script async src=\"https:\/\/pagead2.googlesyndication.com\/pagead\/js\/adsbygoogle.js?client=ca-pub-7269053088454771\"\r\n     crossorigin=\"anonymous\"><\/script>\r\n<!-- Page -->\r\n<ins class=\"adsbygoogle\"\r\n     style=\"display:block\"\r\n     data-ad-client=\"ca-pub-7269053088454771\"\r\n     data-ad-slot=\"9932429364\"\r\n     data-ad-format=\"auto\"\r\n     data-full-width-responsive=\"true\"><\/ins>\r\n<script>\r\n     (adsbygoogle = window.adsbygoogle || []).push({});\r\n<\/script><\/div><div class=\"rdw-table-wrapper\"><table><tr><th>Kenteken<\/th><td><div class=\"rg-kenteken-plaat\"><div class=\"rg-kenteken-eu-strip\"><div class=\"rg-kenteken-eu-stars\"><svg aria-hidden=\"true\" focusable=\"false\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 50 50\" class=\"rg-kenteken-eu-stars-svg\"><g fill=\"#FFC72C\"><g transform=\"translate(25 25) rotate(0)\"><polygon transform=\"translate(0 -16)\" points=\"0,-3 0.674,-0.927 2.853,-0.927 1.090,0.354 1.763,2.427 0,1.146 -1.763,2.427 -1.090,0.354 -2.853,-0.927 -0.674,-0.927\"\/><\/g><g transform=\"translate(25 25) rotate(30)\"><polygon transform=\"translate(0 -16)\" points=\"0,-3 0.674,-0.927 2.853,-0.927 1.090,0.354 1.763,2.427 0,1.146 -1.763,2.427 -1.090,0.354 -2.853,-0.927 -0.674,-0.927\"\/><\/g><g transform=\"translate(25 25) rotate(60)\"><polygon transform=\"translate(0 -16)\" points=\"0,-3 0.674,-0.927 2.853,-0.927 1.090,0.354 1.763,2.427 0,1.146 -1.763,2.427 -1.090,0.354 -2.853,-0.927 -0.674,-0.927\"\/><\/g><g transform=\"translate(25 25) rotate(90)\"><polygon transform=\"translate(0 -16)\" points=\"0,-3 0.674,-0.927 2.853,-0.927 1.090,0.354 1.763,2.427 0,1.146 -1.763,2.427 -1.090,0.354 -2.853,-0.927 -0.674,-0.927\"\/><\/g><g transform=\"translate(25 25) rotate(120)\"><polygon transform=\"translate(0 -16)\" points=\"0,-3 0.674,-0.927 2.853,-0.927 1.090,0.354 1.763,2.427 0,1.146 -1.763,2.427 -1.090,0.354 -2.853,-0.927 -0.674,-0.927\"\/><\/g><g transform=\"translate(25 25) rotate(150)\"><polygon transform=\"translate(0 -16)\" points=\"0,-3 0.674,-0.927 2.853,-0.927 1.090,0.354 1.763,2.427 0,1.146 -1.763,2.427 -1.090,0.354 -2.853,-0.927 -0.674,-0.927\"\/><\/g><g transform=\"translate(25 25) rotate(180)\"><polygon transform=\"translate(0 -16)\" points=\"0,-3 0.674,-0.927 2.853,-0.927 1.090,0.354 1.763,2.427 0,1.146 -1.763,2.427 -1.090,0.354 -2.853,-0.927 -0.674,-0.927\"\/><\/g><g transform=\"translate(25 25) rotate(210)\"><polygon transform=\"translate(0 -16)\" points=\"0,-3 0.674,-0.927 2.853,-0.927 1.090,0.354 1.763,2.427 0,1.146 -1.763,2.427 -1.090,0.354 -2.853,-0.927 -0.674,-0.927\"\/><\/g><g transform=\"translate(25 25) rotate(240)\"><polygon transform=\"translate(0 -16)\" points=\"0,-3 0.674,-0.927 2.853,-0.927 1.090,0.354 1.763,2.427 0,1.146 -1.763,2.427 -1.090,0.354 -2.853,-0.927 -0.674,-0.927\"\/><\/g><g transform=\"translate(25 25) rotate(270)\"><polygon transform=\"translate(0 -16)\" points=\"0,-3 0.674,-0.927 2.853,-0.927 1.090,0.354 1.763,2.427 0,1.146 -1.763,2.427 -1.090,0.354 -2.853,-0.927 -0.674,-0.927\"\/><\/g><g transform=\"translate(25 25) rotate(300)\"><polygon transform=\"translate(0 -16)\" points=\"0,-3 0.674,-0.927 2.853,-0.927 1.090,0.354 1.763,2.427 0,1.146 -1.763,2.427 -1.090,0.354 -2.853,-0.927 -0.674,-0.927\"\/><\/g><g transform=\"translate(25 25) rotate(330)\"><polygon transform=\"translate(0 -16)\" points=\"0,-3 0.674,-0.927 2.853,-0.927 1.090,0.354 1.763,2.427 0,1.146 -1.763,2.427 -1.090,0.354 -2.853,-0.927 -0.674,-0.927\"\/><\/g><\/g><\/svg><\/div><div class=\"rg-kenteken-eu-country\">NL<\/div><\/div><div class=\"rg-kenteken-main\"><span class=\"rg-kenteken-text\">JJ-351-D<\/span><\/div><\/div><div style=\"color: white; font-size: 1px; user-select: none;\"><span class=\"rg-kenteken-text\">JJ-351-D<\/span><\/div><\/td><\/tr><tr><th>Voertuigsoort<\/th><td>Personenauto<\/td><\/tr><tr><th>Merk<\/th><td>KIA<\/td><\/tr><tr><th>Handelsbenaming<\/th><td>PICANTO<\/td><\/tr><tr><th>Vervaldatum Apk<\/th><td>10-10-2026<\/td><\/tr><tr><th>Datum Tenaamstelling<\/th><td>31-07-2018<\/td><\/tr><tr><th>Bruto Bpm<\/th><td>1753 \u20ac<\/td><\/tr><tr><th>Inrichting<\/th><td>MPV<\/td><\/tr><tr><th>Aantal Zitplaatsen<\/th><td>5<\/td><\/tr><tr><th>Eerste Kleur<\/th><td>ZWART<\/td><\/tr><tr><th>Tweede Kleur<\/th><td>Niet geregistreerd<\/td><\/tr><tr><th>Aantal Cilinders<\/th><td>3<\/td><\/tr><tr><th>Cilinderinhoud<\/th><td>998 cm3<\/td><\/tr><tr><th>Massa Ledig Voertuig<\/th><td>830 kg<\/td><\/tr><tr><th>Toegestane Maximum Massa Voertuig<\/th><td>1400 kg<\/td><\/tr><tr><th>Massa Rijklaar<\/th><td>930 kg<\/td><\/tr><tr><th>Datum Eerste Toelating<\/th><td>31-08-2016<\/td><\/tr><tr><th>Datum Eerste Tenaamstelling In Nederland<\/th><td>31-08-2016<\/td><\/tr><tr><th>Wacht Op Keuren<\/th><td>Geen verstrekking in Open Data<\/td><\/tr><tr><th>Catalogusprijs<\/th><td>13990 \u20ac<\/td><\/tr><tr><th>Wam Verzekerd<\/th><td>Ja<\/td><\/tr><tr><th>Aantal Deuren<\/th><td>5<\/td><\/tr><tr><th>Aantal Wielen<\/th><td>4<\/td><\/tr><tr><th>Lengte<\/th><td>360<\/td><\/tr><tr><th>Breedte<\/th><td>160 cm<\/td><\/tr><tr><th>Europese Voertuigcategorie<\/th><td>M1<\/td><\/tr><tr><th>Plaats Chassisnummer<\/th><td>in kofferruimte op bodemplaat<\/td><\/tr><tr><th>Technische Max Massa Voertuig<\/th><td>1400 kg<\/td><\/tr><tr><th>Type<\/th><td>TA<\/td><\/tr><tr><th>Typegoedkeuringsnummer<\/th><td>e4*2007\/46*0256*13<\/td><\/tr><tr><th>Variant<\/th><td>F5P61<\/td><\/tr><tr><th>Uitvoering<\/th><td>M51AZ1<\/td><\/tr><tr><th>Volgnummer Wijziging Eu Typegoedkeuring<\/th><td>0<\/td><\/tr><tr><th>Vermogen Massarijklaar<\/th><td>0.05<\/td><\/tr><tr><th>Wielbasis<\/th><td>239 cm<\/td><\/tr><tr><th>Export Indicator<\/th><td>Nee<\/td><\/tr><tr><th>Openstaande Terugroepactie Indicator<\/th><td>Nee<\/td><\/tr><tr><th>Taxi Indicator<\/th><td>Nee<\/td><\/tr><tr><th>Jaar Laatste Registratie Tellerstand<\/th><td>2025<\/td><\/tr><tr><th>Tellerstandoordeel<\/th><td>Logisch<\/td><\/tr><tr><th>Code Toelichting Tellerstandoordeel<\/th><td>00<\/td><\/tr><tr><th>Tenaamstellen Mogelijk<\/th><td>Ja<\/td><\/tr><tr><th>Hoogte Voertuig<\/th><td>148<\/td><\/tr><tr><th>Zuinigheidsclassificatie<\/th><td>B<\/td><\/tr><\/table><\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":0,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"tags":[],"class_list":["post-20987","page","type-page","status-publish"],"_links":{"self":[{"href":"https:\/\/kentekenvideo.nl\/index.php\/wp-json\/wp\/v2\/pages\/20987","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kentekenvideo.nl\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/kentekenvideo.nl\/index.php\/wp-json\/wp\/v2\/types\/page"}],"replies":[{"embeddable":true,"href":"https:\/\/kentekenvideo.nl\/index.php\/wp-json\/wp\/v2\/comments?post=20987"}],"version-history":[{"count":1,"href":"https:\/\/kentekenvideo.nl\/index.php\/wp-json\/wp\/v2\/pages\/20987\/revisions"}],"predecessor-version":[{"id":20993,"href":"https:\/\/kentekenvideo.nl\/index.php\/wp-json\/wp\/v2\/pages\/20987\/revisions\/20993"}],"wp:attachment":[{"href":"https:\/\/kentekenvideo.nl\/index.php\/wp-json\/wp\/v2\/media?parent=20987"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kentekenvideo.nl\/index.php\/wp-json\/wp\/v2\/tags?post=20987"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}