{"id":1990,"date":"2026-03-30T22:13:15","date_gmt":"2026-03-30T22:13:15","guid":{"rendered":"https:\/\/marineconservation.id\/?page_id=1990"},"modified":"2026-03-31T22:59:09","modified_gmt":"2026-03-31T22:59:09","slug":"qrcode","status":"publish","type":"page","link":"https:\/\/marineconservation.id\/id\/qrcode\/","title":{"rendered":"QRcode"},"content":{"rendered":"<div data-elementor-type=\"wp-page\" data-elementor-id=\"1990\" class=\"elementor elementor-1990\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-efdd19d e-flex e-con-boxed e-con e-parent\" data-id=\"efdd19d\" 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-abdc3d0 elementor-widget elementor-widget-html\" data-id=\"abdc3d0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!DOCTYPE html>\r\n<html lang=\"id\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>QR Pro Global | QR Terbaca + Sudut Terpisah (Outer & Center)<\/title>\r\n    <style>\r\n        * { box-sizing: border-box; font-family: 'Inter', system-ui, sans-serif; }\r\n        body { background: #f4f7fb; margin: 0; padding: 20px; color: #333; }\r\n        .wrapper { display: flex; flex-wrap: wrap; gap: 20px; max-width: 1200px; margin: auto; }\r\n        .left, .right { background: white; padding: 25px; border-radius: 16px; box-shadow: 0 10px 25px rgba(0,0,0,0.08); }\r\n        .left { flex: 1; min-width: 350px; }\r\n        .right { width: 380px; text-align: center; position: sticky; top: 20px; height: fit-content; }\r\n        \r\n        .type-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; margin-bottom: 20px; }\r\n        .type-btn { padding: 12px 5px; border-radius: 10px; background: #eef3ff; cursor: pointer; font-size: 11px; font-weight: 700; border: none; transition: all 0.2s; text-align: center; }\r\n        .type-btn:hover { background: #d4e2fc; transform: translateY(-1px); }\r\n        .type-btn.active { background: #00399F; color: white; }\r\n        \r\n        .input-group { display: flex; gap: 5px; margin-top: 8px; }\r\n        .country-select { width: 140px !important; flex-shrink: 0; font-size: 13px; }\r\n        input, textarea, select { width: 100%; padding: 12px; border-radius: 8px; border: 1px solid #ddd; margin-top: 8px; font-size: 14px; outline: none; }\r\n        #map { height: 250px; border-radius: 12px; margin-top: 10px; border: 1px solid #ddd; z-index: 1; }\r\n        \r\n        .section-title { font-weight: 800; margin: 20px 0 10px; font-size: 11px; text-transform: uppercase; color: #999; border-bottom: 1px solid #eee; padding-bottom: 5px; }\r\n        \r\n        .option-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }\r\n        .opt-item { border: 2px solid #eee; border-radius: 10px; padding: 8px; cursor: pointer; text-align: center; font-size: 11px; font-weight: 600; transition: 0.2s; }\r\n        .opt-item:hover { background: #eef3ff; }\r\n        .opt-item.active { border-color: #00399F; background: #f0f5ff; color: #00399F; }\r\n\r\n        .branding-row { display: grid; grid-template-columns: 100px 1fr 110px; align-items: center; gap: 10px; margin-top: 8px; }\r\n        .branding-row input[type=\"color\"] { height: 40px; padding: 2px; cursor: pointer; border: 1px solid #ddd; margin-top: 0; }\r\n        .branding-row input[type=\"text\"] { margin-top: 0; font-family: monospace; text-align: center; text-transform: uppercase; }\r\n\r\n        .icon-presets { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; margin-top: 10px; }\r\n        .icon-box { aspect-ratio: 1; border: 2px solid #eee; border-radius: 10px; cursor: pointer; display: flex; align-items: center; justify-content: center; background: white; padding: 8px; transition: 0.2s; }\r\n        .icon-box:hover { background: #eef3ff; }\r\n        .icon-box svg { width: 100%; height: 100%; }\r\n        .icon-box.active { border-color: #00399F; background: #f0f5ff; }\r\n\r\n        \/* Frame visual grid *\/\r\n        .frame-visual-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; margin: 15px 0; }\r\n        .frame-visual-item { border: 2px solid #eee; border-radius: 12px; padding: 8px; text-align: center; cursor: pointer; transition: 0.2s; background: white; }\r\n        .frame-visual-item:hover { background: #eef3ff; }\r\n        .frame-visual-item.active { border-color: #00399F; background: #f0f5ff; }\r\n        .frame-preview-svg { width: 80px; height: 80px; margin: 0 auto; display: block; }\r\n        .frame-visual-item span { font-size: 10px; display: block; margin-top: 5px; }\r\n\r\n        #canvas-wrapper { background: white; padding: 15px; border-radius: 12px; display: inline-block; margin: 15px 0; border: 1px solid #eee; }\r\n        #mainCanvas { max-width: 100%; height: auto; }\r\n        .main-btn { background: #00399F; color: white; border: none; padding: 16px; width: 100%; border-radius: 12px; font-weight: 700; cursor: pointer; font-size: 16px; transition: 0.3s; }\r\n        .main-btn:hover { background: #002a7a; }\r\n        .note-small { font-size: 10px; color: #888; margin-top: 4px; text-align: center; }\r\n    <\/style>\r\n    <link rel=\"stylesheet\" href=\"https:\/\/unpkg.com\/leaflet@1.9.4\/dist\/leaflet.css\" \/>\r\n    <script src=\"https:\/\/unpkg.com\/leaflet@1.9.4\/dist\/leaflet.js\"><\/script>\r\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/qrcode-generator@1.4.4\/qrcode.min.js\"><\/script>\r\n<\/head>\r\n<body>\r\n\r\n<div class=\"wrapper\">\r\n    <div class=\"left\">\r\n        <div class=\"section-title\">1. Konten Global (10 Fungsi)<\/div>\r\n        <div class=\"type-grid\">\r\n            <button class=\"type-btn active\" data-type=\"url\">\ud83c\udf10 URL<\/button>\r\n            <button class=\"type-btn\" data-type=\"wa\">\ud83d\udcac WA<\/button>\r\n            <button class=\"type-btn\" data-type=\"maps\">\ud83d\udccd MAPS<\/button>\r\n            <button class=\"type-btn\" data-type=\"zoom\">\ud83d\udcf9 ZOOM<\/button>\r\n            <button class=\"type-btn\" data-type=\"wifi\">\ud83d\udcf6 WIFI<\/button>\r\n            <button class=\"type-btn\" data-type=\"contact\">\ud83d\udc64 VCARD<\/button>\r\n            <button class=\"type-btn\" data-type=\"email\">\ud83d\udce7 EMAIL<\/button>\r\n            <button class=\"type-btn\" data-type=\"sms\">\ud83d\udce9 SMS<\/button>\r\n            <button class=\"type-btn\" data-type=\"event\">\ud83d\udcc5 EVENT<\/button>\r\n            <button class=\"type-btn\" data-type=\"text\">\ud83d\udcdd TEKS<\/button>\r\n        <\/div>\r\n\r\n        <div id=\"inputsContainer\"><\/div>\r\n\r\n        <div class=\"section-title\">2. Kustom Desain Modul & Marker<\/div>\r\n        <div class=\"option-grid\" id=\"patternGrid\" style=\"margin-bottom:10px\">\r\n            <div class=\"opt-item active\" data-pattern=\"square\">Square<\/div>\r\n            <div class=\"opt-item\" data-pattern=\"dot\">Dots<\/div>\r\n            <div class=\"opt-item\" data-pattern=\"rounded\">Rounded<\/div>\r\n            <div class=\"opt-item\" data-pattern=\"diamond\">Diamond<\/div>\r\n        <\/div>\r\n\r\n        <div class=\"section-title\">3. Sudut (Finder Pattern) - Bentuk & Warna<\/div>\r\n        <div class=\"branding-row\">\r\n            <label>Outer Shape:<\/label>\r\n            <select id=\"outerShapeSelect\" onchange=\"generateQR()\">\r\n                <option value=\"square\">Square<\/option>\r\n                <option value=\"circle\">Circle<\/option>\r\n                <option value=\"smooth\">Smooth<\/option>\r\n            <\/select>\r\n        <\/div>\r\n        <div class=\"branding-row\">\r\n            <label>Center Shape:<\/label>\r\n            <select id=\"centerShapeSelect\" onchange=\"generateQR()\">\r\n                <option value=\"square\">Square<\/option>\r\n                <option value=\"circle\">Circle<\/option>\r\n                <option value=\"dot\">Dot<\/option>\r\n            <\/select>\r\n        <\/div>\r\n        <div class=\"branding-row\">\r\n            <label>Warna Outer:<\/label>\r\n            <input type=\"color\" id=\"cornerOuterColor\" value=\"#00399F\" oninput=\"updateCornerColors()\">\r\n            <input type=\"text\" id=\"cornerOuterColorText\" value=\"#00399F\" maxlength=\"7\" oninput=\"updateCornerColorsText('outer')\">\r\n        <\/div>\r\n        <div class=\"branding-row\">\r\n            <label>Warna Inner:<\/label>\r\n            <input type=\"color\" id=\"cornerInnerColor\" value=\"#FFFFFF\" oninput=\"updateCornerColors()\">\r\n            <input type=\"text\" id=\"cornerInnerColorText\" value=\"#FFFFFF\" maxlength=\"7\" oninput=\"updateCornerColorsText('inner')\">\r\n        <\/div>\r\n        <div class=\"branding-row\">\r\n            <label>Warna Center:<\/label>\r\n            <input type=\"color\" id=\"cornerCenterColor\" value=\"#00399F\" oninput=\"updateCornerColors()\">\r\n            <input type=\"text\" id=\"cornerCenterColorText\" value=\"#00399F\" maxlength=\"7\" oninput=\"updateCornerColorsText('center')\">\r\n        <\/div>\r\n\r\n        <div class=\"section-title\">4. Warna QR (Utama & Latar)<\/div>\r\n        <div class=\"branding-row\">\r\n            <label>Utama QR:<\/label>\r\n            <input type=\"color\" id=\"fgColorPicker\" value=\"#00399F\" oninput=\"syncColor('fg', 'picker')\">\r\n            <input type=\"text\" id=\"fgColorText\" value=\"#00399F\" maxlength=\"7\" oninput=\"syncColor('fg', 'text')\">\r\n        <\/div>\r\n        <div class=\"branding-row\">\r\n            <label>Latar QR:<\/label>\r\n            <input type=\"color\" id=\"bgColorPicker\" value=\"#FFFFFF\" oninput=\"syncColor('bg', 'picker')\">\r\n            <input type=\"text\" id=\"bgColorText\" value=\"#FFFFFF\" maxlength=\"7\" oninput=\"syncColor('bg', 'text')\">\r\n        <\/div>\r\n\r\n        <div class=\"section-title\">5. Ikon Tengah (Pilih Manual)<\/div>\r\n        <div class=\"icon-presets\" id=\"iconPresets\">\r\n            <div class=\"icon-box active\" data-icon=\"none\">OFF<\/div>\r\n            <div class=\"icon-box\" data-icon=\"url\" id=\"icon-url\"><\/div>\r\n            <div class=\"icon-box\" data-icon=\"wa\" id=\"icon-wa\"><\/div>\r\n            <div class=\"icon-box\" data-icon=\"maps\" id=\"icon-maps\"><\/div>\r\n            <div class=\"icon-box\" data-icon=\"zoom\" id=\"icon-zoom\"><\/div>\r\n            <div class=\"icon-box\" data-icon=\"wifi\" id=\"icon-wifi\"><\/div>\r\n            <div class=\"icon-box\" data-icon=\"contact\" id=\"icon-contact\"><\/div>\r\n            <div class=\"icon-box\" data-icon=\"email\" id=\"icon-email\"><\/div>\r\n            <div class=\"icon-box\" data-icon=\"sms\" id=\"icon-sms\"><\/div>\r\n            <div class=\"icon-box\" data-icon=\"event\" id=\"icon-event\"><\/div>\r\n            <div class=\"icon-box\" data-icon=\"text\" id=\"icon-text\"><\/div>\r\n        <\/div>\r\n        <div class=\"branding-row\" style=\"margin-top: 12px;\">\r\n            <label>Ukuran Ikon (%):<\/label>\r\n            <input type=\"range\" id=\"iconSizeSlider\" min=\"10\" max=\"30\" value=\"20\" step=\"1\" oninput=\"document.getElementById('iconSizeVal').innerText=this.value+'%'; generateQR()\">\r\n            <span id=\"iconSizeVal\">20%<\/span>\r\n        <\/div>\r\n        <div class=\"note-small\">\u26a0\ufe0f Untuk hasil scan optimal, gunakan ukuran ikon \u2264 25%<\/div>\r\n        <input type=\"file\" id=\"logoInput\" style=\"margin-top:10px\" accept=\"image\/*\" onchange=\"handleLogoUpload(this)\">\r\n\r\n        <!-- Frame Section -->\r\n        <div class=\"section-title\">6. Frame (Border Dekoratif)<\/div>\r\n        <div class=\"frame-visual-grid\" id=\"frameVisualGrid\"><\/div>\r\n        <div class=\"branding-row\">\r\n            <label>Warna Border:<\/label>\r\n            <input type=\"color\" id=\"frameBorderColor\" value=\"#cccccc\" oninput=\"generateQR()\">\r\n            <input type=\"text\" id=\"frameBorderColorText\" value=\"#cccccc\" maxlength=\"7\" oninput=\"syncFrameColor('border', this)\">\r\n        <\/div>\r\n        <div class=\"branding-row\">\r\n            <label>Warna Latar Frame:<\/label>\r\n            <input type=\"color\" id=\"frameBgColor\" value=\"#ffffff\" oninput=\"generateQR()\">\r\n            <input type=\"text\" id=\"frameBgColorText\" value=\"#ffffff\" maxlength=\"7\" oninput=\"syncFrameColor('bg', this)\">\r\n        <\/div>\r\n\r\n        <!-- Label Section -->\r\n        <div class=\"section-title\">7. Label (Teks Bawah)<\/div>\r\n        <div class=\"input-group\" style=\"margin-top:8px\">\r\n            <input type=\"text\" id=\"labelText\" placeholder=\"Teks Label\" value=\"SCAN DISINI\" oninput=\"generateQR()\">\r\n        <\/div>\r\n        <div class=\"branding-row\">\r\n            <label>Warna Teks:<\/label>\r\n            <input type=\"color\" id=\"labelTextColor\" value=\"#1f2937\" oninput=\"generateQR()\">\r\n            <input type=\"text\" id=\"labelTextColorText\" value=\"#1f2937\" maxlength=\"7\" oninput=\"syncLabelColor(this)\">\r\n        <\/div>\r\n        <div class=\"branding-row\">\r\n            <label>Warna Latar Label:<\/label>\r\n            <input type=\"color\" id=\"labelBgColor\" value=\"#ffffff\" oninput=\"generateQR()\">\r\n            <input type=\"text\" id=\"labelBgColorText\" value=\"#ffffff\" maxlength=\"7\" oninput=\"syncLabelBgColor(this)\">\r\n        <\/div>\r\n        <div class=\"branding-row\">\r\n            <label>Font Label:<\/label>\r\n            <select id=\"labelFontSelect\" onchange=\"generateQR()\">\r\n                <option value=\"Arial\">Arial<\/option><option value=\"Verdana\">Verdana<\/option><option value=\"Georgia\">Georgia<\/option>\r\n                <option value=\"'Times New Roman'\">Times New Roman<\/option><option value=\"'Courier New'\">Courier New<\/option>\r\n                <option value=\"'Comic Sans MS'\">Comic Sans MS<\/option><option value=\"'Trebuchet MS'\">Trebuchet MS<\/option>\r\n                <option value=\"'Palatino Linotype'\">Palatino Linotype<\/option><option value=\"'Lucida Sans Unicode'\">Lucida Sans Unicode<\/option>\r\n                <option value=\"Tahoma\">Tahoma<\/option><option value=\"'Segoe UI'\">Segoe UI<\/option><option value=\"Roboto\">Roboto<\/option>\r\n                <option value=\"Open Sans\">Open Sans<\/option><option value=\"Lato\">Lato<\/option><option value=\"Montserrat\">Montserrat<\/option>\r\n                <option value=\"Poppins\">Poppins<\/option><option value=\"'Nunito Sans'\">Nunito Sans<\/option><option value=\"'Fira Sans'\">Fira Sans<\/option>\r\n                <option value=\"'Source Sans Pro'\">Source Sans Pro<\/option><option value=\"'Oswald'\">Oswald<\/option><option value=\"'Raleway'\">Raleway<\/option>\r\n                <option value=\"'Merriweather'\">Merriweather<\/option><option value=\"'Playfair Display'\">Playfair Display<\/option>\r\n                <option value=\"'Inconsolata'\">Inconsolata<\/option><option value=\"CustomFont\">Custom (Upload)<\/option>\r\n            <\/select>\r\n            <input type=\"file\" id=\"customFontUpload\" accept=\".ttf,.otf\" style=\"display:none;\" onchange=\"uploadCustomFont(this)\">\r\n            <button type=\"button\" onclick=\"document.getElementById('customFontUpload').click()\" style=\"padding:8px; background:#eef3ff; border:1px solid #ddd; border-radius:8px;\">Upload Font<\/button>\r\n        <\/div>\r\n\r\n        <div class=\"section-title\">8. Opsi Ukuran<\/div>\r\n        <select id=\"qrSize\" onchange=\"generateQR()\">\r\n            <option value=\"450\">Layar (450px)<\/option>\r\n            <option value=\"2500\">Cetak High-Res (2500px)<\/option>\r\n        <\/select>\r\n        <button class=\"main-btn\" onclick=\"downloadQR()\">\u2b07\ufe0f Download PNG<\/button>\r\n    <\/div>\r\n\r\n    <div class=\"right\">\r\n        <h3>Preview QR Code<\/h3>\r\n        <div id=\"canvas-wrapper\">\r\n            <canvas id=\"mainCanvas\"><\/canvas>\r\n        <\/div>\r\n        <p style=\"font-size:12px; color:#666;\">Outer & Center shape terpisah, QR tetap terbaca<\/p>\r\n    <\/div>\r\n<\/div>\r\n\r\n<script>\r\n    \/\/ ======================== DATA GLOBAL ========================\r\n    let currentType = \"url\", map, marker, customLogo = null, selectedIcon = 'none';\r\n    let designConfig = { pattern: 'square' };\r\n    let cornerShapes = { outer: 'square', center: 'square' };\r\n    let cornerColors = {\r\n        outer: \"#00399F\",\r\n        inner: \"#FFFFFF\",\r\n        center: \"#00399F\"\r\n    };\r\n    let currentFrameStyle = \"none\";\r\n    let frameBorderColor = \"#cccccc\", frameBgColor = \"#ffffff\";\r\n    let labelTextColor = \"#1f2937\", labelBgColor = \"#ffffff\";\r\n    let customFontFamily = null;\r\n\r\n    \/\/ ======================== COUNTRY LIST (LENGKAP) ========================\r\n    const countryList = [\r\n        {n:\"Indonesia\",c:\"62\"},{n:\"Afghanistan\",c:\"93\"},{n:\"Albania\",c:\"355\"},{n:\"Algeria\",c:\"213\"},{n:\"Andorra\",c:\"376\"},{n:\"Angola\",c:\"244\"},{n:\"Argentina\",c:\"54\"},{n:\"Armenia\",c:\"374\"},{n:\"Australia\",c:\"61\"},{n:\"Austria\",c:\"43\"},{n:\"Azerbaijan\",c:\"994\"},{n:\"Bahamas\",c:\"1242\"},{n:\"Bahrain\",c:\"973\"},{n:\"Bangladesh\",c:\"880\"},{n:\"Belarus\",c:\"375\"},{n:\"Belgium\",c:\"32\"},{n:\"Belize\",c:\"501\"},{n:\"Benin\",c:\"229\"},{n:\"Bhutan\",c:\"975\"},{n:\"Bolivia\",c:\"591\"},{n:\"Bosnia\",c:\"387\"},{n:\"Botswana\",c:\"267\"},{n:\"Brazil\",c:\"55\"},{n:\"Brunei\",c:\"673\"},{n:\"Bulgaria\",c:\"359\"},{n:\"Burkina Faso\",c:\"226\"},{n:\"Cambodia\",c:\"855\"},{n:\"Cameroon\",c:\"237\"},{n:\"Canada\",c:\"1\"},{n:\"Chile\",c:\"56\"},{n:\"China\",c:\"86\"},{n:\"Colombia\",c:\"57\"},{n:\"Costa Rica\",c:\"506\"},{n:\"Croatia\",c:\"385\"},{n:\"Cuba\",c:\"53\"},{n:\"Cyprus\",c:\"357\"},{n:\"Czech Rep\",c:\"420\"},{n:\"Denmark\",c:\"45\"},{n:\"Ecuador\",c:\"593\"},{n:\"Egypt\",c:\"20\"},{n:\"Estonia\",c:\"372\"},{n:\"Ethiopia\",c:\"251\"},{n:\"Fiji\",c:\"679\"},{n:\"Finland\",c:\"358\"},{n:\"France\",c:\"33\"},{n:\"Georgia\",c:\"995\"},{n:\"Germany\",c:\"49\"},{n:\"Ghana\",c:\"233\"},{n:\"Greece\",c:\"30\"},{n:\"Hong Kong\",c:\"852\"},{n:\"Hungary\",c:\"36\"},{n:\"Iceland\",c:\"354\"},{n:\"India\",c:\"91\"},{n:\"Iran\",c:\"98\"},{n:\"Iraq\",c:\"964\"},{n:\"Ireland\",c:\"353\"},{n:\"Israel\",c:\"972\"},{n:\"Italy\",c:\"39\"},{n:\"Jamaica\",c:\"1876\"},{n:\"Japan\",c:\"81\"},{n:\"Jordan\",c:\"962\"},{n:\"Kazakhstan\",c:\"7\"},{n:\"Kenya\",c:\"254\"},{n:\"Korea South\",c:\"82\"},{n:\"Kuwait\",c:\"965\"},{n:\"Laos\",c:\"856\"},{n:\"Latvia\",c:\"371\"},{n:\"Lebanon\",c:\"961\"},{n:\"Libya\",c:\"218\"},{n:\"Lithuania\",c:\"370\"},{n:\"Luxembourg\",c:\"352\"},{n:\"Macau\",c:\"853\"},{n:\"Madagascar\",c:\"261\"},{n:\"Malawi\",c:\"265\"},{n:\"Malaysia\",c:\"60\"},{n:\"Maldives\",c:\"960\"},{n:\"Malta\",c:\"356\"},{n:\"Mauritius\",c:\"230\"},{n:\"Mexico\",c:\"52\"},{n:\"Moldova\",c:\"373\"},{n:\"Monaco\",c:\"377\"},{n:\"Mongolia\",c:\"976\"},{n:\"Montenegro\",c:\"382\"},{n:\"Morocco\",c:\"212\"},{n:\"Myanmar\",c:\"95\"},{n:\"Namibia\",c:\"264\"},{n:\"Nepal\",c:\"977\"},{n:\"Netherlands\",c:\"31\"},{n:\"New Zealand\",c:\"64\"},{n:\"Nigeria\",c:\"234\"},{n:\"Norway\",c:\"47\"},{n:\"Oman\",c:\"968\"},{n:\"Pakistan\",c:\"92\"},{n:\"Panama\",c:\"507\"},{n:\"Paraguay\",c:\"595\"},{n:\"Peru\",c:\"51\"},{n:\"Philippines\",c:\"63\"},{n:\"Poland\",c:\"48\"},{n:\"Portugal\",c:\"351\"},{n:\"Qatar\",c:\"974\"},{n:\"Romania\",c:\"40\"},{n:\"Russia\",c:\"7\"},{n:\"Saudi Arabia\",c:\"966\"},{n:\"Senegal\",c:\"221\"},{n:\"Serbia\",c:\"381\"},{n:\"Singapore\",c:\"65\"},{n:\"Slovakia\",c:\"421\"},{n:\"Slovenia\",c:\"386\"},{n:\"South Africa\",c:\"27\"},{n:\"Spain\",c:\"34\"},{n:\"Sri Lanka\",c:\"94\"},{n:\"Sudan\",c:\"249\"},{n:\"Sweden\",c:\"46\"},{n:\"Switzerland\",c:\"41\"},{n:\"Syria\",c:\"963\"},{n:\"Taiwan\",c:\"886\"},{n:\"Tanzania\",c:\"255\"},{n:\"Thailand\",c:\"66\"},{n:\"Tunisia\",c:\"216\"},{n:\"Turkey\",c:\"90\"},{n:\"Uganda\",c:\"256\"},{n:\"Ukraine\",c:\"380\"},{n:\"UAE\",c:\"971\"},{n:\"UK\",c:\"44\"},{n:\"USA\",c:\"1\"},{n:\"Uruguay\",c:\"598\"},{n:\"Uzbekistan\",c:\"998\"},{n:\"Vatican\",c:\"379\"},{n:\"Venezuela\",c:\"58\"},{n:\"Vietnam\",c:\"84\"},{n:\"Yemen\",c:\"967\"},{n:\"Zambia\",c:\"260\"},{n:\"Zimbabwe\",c:\"263\"}\r\n    ];\r\n\r\n    \/\/ ======================== ICON PATHS ========================\r\n    const icons = {\r\n        url: \"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z\",\r\n        wa: \"M12.04 2c-5.46 0-9.91 4.45-9.91 9.91 0 1.75.46 3.45 1.32 4.95L2.05 22l5.25-1.38c1.45.79 3.08 1.21 4.74 1.21 5.46 0 9.91-4.45 9.91-9.91 0-2.65-1.03-5.14-2.9-7.01A9.816 9.816 0 0 0 12.04 2\",\r\n        maps: \"M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z\",\r\n        zoom: \"M21 6.5l-4 4V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11z\",\r\n        wifi: \"M12 3C7.41 3 3.44 4.72.5 7.5l11.5 14.5L23.5 7.5C20.56 4.72 16.59 3 12 3z\",\r\n        contact: \"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z\",\r\n        email: \"M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z\",\r\n        sms: \"M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2\",\r\n        event: \"M19 4h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V10h14v10z\",\r\n        text: \"M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6\"\r\n    };\r\n\r\n    \/\/ ======================== FRAME STYLES ========================\r\n    const frameStyles = [\r\n        { id: \"none\", name: \"None\", preview: \"M10,10h80v80h-80z\" },\r\n        { id: \"simple\", name: \"Simple\", preview: \"M5,5h90v90h-90zM10,10h80v80h-80z\" },\r\n        { id: \"shadow\", name: \"Shadow\", preview: \"M5,5h90v90h-90zM8,8h84v84h-84z\" },\r\n        { id: \"double\", name: \"Double\", preview: \"M5,5h90v90h-90zM15,15h70v70h-70z\" },\r\n        { id: \"dashed\", name: \"Dashed\", preview: \"M5,5h90v90h-90zM10,10h80v80h-80z\" },\r\n        { id: \"rounded\", name: \"Rounded\", preview: \"M15,5h70v90h-70zM20,10h60v80h-60z\" },\r\n        { id: \"neon\", name: \"Neon\", preview: \"M5,5h90v90h-90zM10,10h80v80h-80z\" },\r\n        { id: \"vintage\", name: \"Vintage\", preview: \"M5,5h90v90h-90zM12,12h76v76h-76z\" },\r\n        { id: \"minimal\", name: \"Minimal\", preview: \"M10,10h80v80h-80z\" },\r\n        { id: \"label\", name: \"Label (Khusus Label)\", preview: \"M10,10h80v70h-80zM10,85h80v10h-80z\" }\r\n    ];\r\n\r\n    \/\/ ======================== INISIALISASI UI ========================\r\n    function initUI() {\r\n        \/\/ Generate ikon\r\n        Object.keys(icons).forEach(key => {\r\n            const el = document.getElementById(`icon-${key}`);\r\n            if(el) el.innerHTML = `<svg viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"${icons[key]}\"><\/path><\/svg>`;\r\n        });\r\n        \/\/ Generate frame visual grid\r\n        const grid = document.getElementById('frameVisualGrid');\r\n        frameStyles.forEach(style => {\r\n            const div = document.createElement('div');\r\n            div.className = 'frame-visual-item';\r\n            if (style.id === 'none') div.classList.add('active');\r\n            div.setAttribute('data-frame-id', style.id);\r\n            div.innerHTML = `\r\n                <svg class=\"frame-preview-svg\" viewBox=\"0 0 100 100\">\r\n                    <rect x=\"0\" y=\"0\" width=\"100\" height=\"100\" fill=\"#f0f0f0\" stroke=\"none\"\/>\r\n                    <path d=\"${style.preview}\" fill=\"none\" stroke=\"#00399F\" stroke-width=\"2\"\/>\r\n                    ${style.id === 'label' ? '<rect x=\"10\" y=\"85\" width=\"80\" height=\"10\" fill=\"#00399F\" \/>' : ''}\r\n                <\/svg>\r\n                <span>${style.name}<\/span>\r\n            `;\r\n            div.onclick = () => {\r\n                document.querySelectorAll('.frame-visual-item').forEach(i => i.classList.remove('active'));\r\n                div.classList.add('active');\r\n                currentFrameStyle = style.id;\r\n                generateQR();\r\n            };\r\n            grid.appendChild(div);\r\n        });\r\n        renderInputs();\r\n        updateIconColors();\r\n        generateQR();\r\n    }\r\n\r\n    \/\/ ======================== EVENT HANDLERS ========================\r\n    function setPattern(p) {\r\n        designConfig.pattern = p;\r\n        document.querySelectorAll('#patternGrid .opt-item').forEach(el => {\r\n            el.classList.toggle('active', el.dataset.pattern === p);\r\n        });\r\n        generateQR();\r\n    }\r\n\r\n    function syncColor(type, source) {\r\n        const picker = document.getElementById(`${type}ColorPicker`);\r\n        const text = document.getElementById(`${type}ColorText`);\r\n        if (source === 'picker') text.value = picker.value.toUpperCase();\r\n        else if (\/^#[0-9A-F]{6}$\/i.test(text.value)) picker.value = text.value;\r\n        updateIconColors(); generateQR();\r\n    }\r\n\r\n    function updateCornerColors() {\r\n        cornerColors.outer = document.getElementById('cornerOuterColor').value;\r\n        cornerColors.inner = document.getElementById('cornerInnerColor').value;\r\n        cornerColors.center = document.getElementById('cornerCenterColor').value;\r\n        document.getElementById('cornerOuterColorText').value = cornerColors.outer.toUpperCase();\r\n        document.getElementById('cornerInnerColorText').value = cornerColors.inner.toUpperCase();\r\n        document.getElementById('cornerCenterColorText').value = cornerColors.center.toUpperCase();\r\n        generateQR();\r\n    }\r\n    function updateCornerColorsText(type) {\r\n        const val = document.getElementById(`corner${type === 'outer' ? 'Outer' : (type === 'inner' ? 'Inner' : 'Center')}ColorText`).value;\r\n        if (\/^#[0-9A-F]{6}$\/i.test(val)) {\r\n            if (type === 'outer') document.getElementById('cornerOuterColor').value = val;\r\n            if (type === 'inner') document.getElementById('cornerInnerColor').value = val;\r\n            if (type === 'center') document.getElementById('cornerCenterColor').value = val;\r\n            updateCornerColors();\r\n        }\r\n    }\r\n\r\n    function updateIconColors() {\r\n        const color = document.getElementById('fgColorPicker').value;\r\n        document.querySelectorAll('.icon-box svg').forEach(svg => svg.style.color = color);\r\n    }\r\n\r\n    function syncFrameColor(type, input) {\r\n        const val = input.value;\r\n        if (type === 'border' && \/^#[0-9A-F]{6}$\/i.test(val)) {\r\n            document.getElementById('frameBorderColor').value = val;\r\n            generateQR();\r\n        } else if (type === 'bg' && \/^#[0-9A-F]{6}$\/i.test(val)) {\r\n            document.getElementById('frameBgColor').value = val;\r\n            generateQR();\r\n        }\r\n    }\r\n    function syncLabelColor(input) {\r\n        const val = input.value;\r\n        if (\/^#[0-9A-F]{6}$\/i.test(val)) {\r\n            labelTextColor = val;\r\n            document.getElementById('labelTextColor').value = val;\r\n            generateQR();\r\n        }\r\n    }\r\n    function syncLabelBgColor(input) {\r\n        const val = input.value;\r\n        if (\/^#[0-9A-F]{6}$\/i.test(val)) {\r\n            labelBgColor = val;\r\n            document.getElementById('labelBgColor').value = val;\r\n            generateQR();\r\n        }\r\n    }\r\n\r\n    document.querySelectorAll('.type-btn').forEach(btn => {\r\n        btn.addEventListener('click', () => {\r\n            document.querySelectorAll('.type-btn').forEach(b => b.classList.remove('active'));\r\n            btn.classList.add('active');\r\n            currentType = btn.dataset.type;\r\n            renderInputs();\r\n            generateQR();\r\n        });\r\n    });\r\n\r\n    document.querySelectorAll('#patternGrid .opt-item').forEach(el => {\r\n        el.addEventListener('click', () => setPattern(el.dataset.pattern));\r\n    });\r\n\r\n    document.getElementById('outerShapeSelect').addEventListener('change', (e) => {\r\n        cornerShapes.outer = e.target.value;\r\n        generateQR();\r\n    });\r\n    document.getElementById('centerShapeSelect').addEventListener('change', (e) => {\r\n        cornerShapes.center = e.target.value;\r\n        generateQR();\r\n    });\r\n\r\n    function renderInputs() {\r\n        const container = document.getElementById('inputsContainer');\r\n        const cSel = `<select class=\"country-select\" id=\"cCode\" onchange=\"generateQR()\">${countryList.map(c => `<option value=\"${c.c}\">${c.n} (+${c.c})<\/option>`).join('')}<\/select>`;\r\n        let html = \"\";\r\n        switch(currentType) {\r\n            case \"url\": html = `<input id=\"urlD\" placeholder=\"https:\/\/...\" oninput=\"generateQR()\">`; break;\r\n            case \"wa\": html = `<div class=\"input-group\">${cSel}<input id=\"waP\" placeholder=\"812...\" oninput=\"generateQR()\"><\/div><textarea id=\"waM\" placeholder=\"Pesan...\" oninput=\"generateQR()\"><\/textarea>`; break;\r\n            case \"zoom\": html = `<input id=\"zId\" placeholder=\"Meeting ID\" oninput=\"generateQR()\"><input id=\"zPw\" placeholder=\"Passcode\" oninput=\"generateQR()\">`; break;\r\n            case \"wifi\": html = `<input id=\"wSsid\" placeholder=\"Nama WiFi\" oninput=\"generateQR()\"><input id=\"wPass\" placeholder=\"Password\" oninput=\"generateQR()\">`; break;\r\n            case \"contact\": html = `<input id=\"vN\" placeholder=\"Nama\" oninput=\"generateQR()\"><div class=\"input-group\">${cSel}<input id=\"vT\" placeholder=\"Telepon\" oninput=\"generateQR()\"><\/div><input id=\"vE\" placeholder=\"Email\" oninput=\"generateQR()\">`; break;\r\n            case \"email\": html = `<input id=\"eT\" placeholder=\"Email Tujuan\" oninput=\"generateQR()\"><input id=\"eS\" placeholder=\"Subjek\" oninput=\"generateQR()\"><textarea id=\"eB\" placeholder=\"Isi Email (opsional)\" oninput=\"generateQR()\"><\/textarea>`; break;\r\n            case \"sms\": html = `<div class=\"input-group\">${cSel}<input id=\"sP\" placeholder=\"Nomor\" oninput=\"generateQR()\"><\/div><textarea id=\"sB\" placeholder=\"Pesan SMS\" oninput=\"generateQR()\"><\/textarea>`; break;\r\n            case \"event\": html = `<input id=\"evT\" placeholder=\"Judul Event\" oninput=\"generateQR()\"><input id=\"evL\" placeholder=\"Lokasi\" oninput=\"generateQR()\"><input id=\"evS\" type=\"datetime-local\" oninput=\"generateQR()\"><input id=\"evE\" type=\"datetime-local\" placeholder=\"Akhir (opsional)\" oninput=\"generateQR()\"><textarea id=\"evD\" placeholder=\"Deskripsi (opsional)\" oninput=\"generateQR()\"><\/textarea>`; break;\r\n            case \"text\": html = `<textarea id=\"txtD\" placeholder=\"Teks bebas...\" oninput=\"generateQR()\"><\/textarea>`; break;\r\n            case \"maps\": html = `<div id=\"map\"><\/div><div class=\"input-group\"><input id=\"mLat\" placeholder=\"Lat\" oninput=\"generateQR()\"><input id=\"mLng\" placeholder=\"Lng\" oninput=\"generateQR()\"><\/div>`; setTimeout(initMap, 100); break;\r\n        }\r\n        container.innerHTML = html;\r\n    }\r\n\r\n    function initMap() {\r\n        if (map) map.remove();\r\n        map = L.map('map').setView([-8.4, 115.1], 9);\r\n        const street = L.tileLayer('https:\/\/{s}.tile.openstreetmap.org\/{z}\/{x}\/{y}.png').addTo(map);\r\n        const sat = L.tileLayer('https:\/\/{s}.google.com\/vt\/lyrs=s&x={x}&y={y}&z={z}', {subdomains:['mt0','mt1','mt2','mt3']});\r\n        L.control.layers({\"Jalan\": street, \"Satelit\": sat}).addTo(map);\r\n        map.on('click', e => {\r\n            document.getElementById('mLat').value = e.latlng.lat;\r\n            document.getElementById('mLng').value = e.latlng.lng;\r\n            if (marker) marker.setLatLng(e.latlng); else marker = L.marker(e.latlng).addTo(map);\r\n            generateQR();\r\n        });\r\n    }\r\n\r\n    function setPresetIcon(key, el) {\r\n        document.querySelectorAll('.icon-box').forEach(b => b.classList.remove('active'));\r\n        el.classList.add('active');\r\n        selectedIcon = key;\r\n        customLogo = null;\r\n        generateQR();\r\n    }\r\n    document.querySelectorAll('.icon-box').forEach(el => {\r\n        el.addEventListener('click', () => setPresetIcon(el.dataset.icon, el));\r\n    });\r\n\r\n    function handleLogoUpload(input) {\r\n        if (input.files && input.files[0]) {\r\n            const reader = new FileReader();\r\n            reader.onload = e => {\r\n                customLogo = new Image(); customLogo.src = e.target.result;\r\n                customLogo.onload = () => { selectedIcon = 'upload'; generateQR(); };\r\n            };\r\n            reader.readAsDataURL(input.files[0]);\r\n        }\r\n    }\r\n    function uploadCustomFont(input) {\r\n        if (input.files && input.files[0]) {\r\n            const reader = new FileReader();\r\n            reader.onload = e => {\r\n                const fontData = e.target.result;\r\n                const fontName = 'CustomFont_' + Date.now();\r\n                const style = document.createElement('style');\r\n                style.textContent = `@font-face { font-family: '${fontName}'; src: url(${fontData}) format('truetype'); }`;\r\n                document.head.appendChild(style);\r\n                customFontFamily = fontName;\r\n                const fontSelect = document.getElementById('labelFontSelect');\r\n                fontSelect.innerHTML += `<option value=\"${fontName}\" selected>${fontName}<\/option>`;\r\n                fontSelect.value = fontName;\r\n                generateQR();\r\n            };\r\n            reader.readAsDataURL(input.files[0]);\r\n        }\r\n    }\r\n\r\n    function drawFrameBorder(ctx, x, y, width, height, style) {\r\n        ctx.save();\r\n        ctx.strokeStyle = frameBorderColor;\r\n        ctx.fillStyle = frameBgColor;\r\n        ctx.lineWidth = style === 'double' ? 3 : 2;\r\n        if (style === 'simple') {\r\n            ctx.fillRect(x, y, width, height);\r\n            ctx.strokeRect(x, y, width, height);\r\n        } else if (style === 'shadow') {\r\n            ctx.shadowColor = 'rgba(0,0,0,0.3)'; ctx.shadowBlur = 10;\r\n            ctx.fillRect(x, y, width, height);\r\n            ctx.shadowColor = 'transparent';\r\n            ctx.strokeRect(x, y, width, height);\r\n        } else if (style === 'double') {\r\n            ctx.fillRect(x, y, width, height);\r\n            ctx.strokeRect(x, y, width, height);\r\n            ctx.strokeRect(x+4, y+4, width-8, height-8);\r\n        } else if (style === 'dashed') {\r\n            ctx.fillRect(x, y, width, height);\r\n            ctx.setLineDash([8,6]); ctx.strokeRect(x, y, width, height); ctx.setLineDash([]);\r\n        } else if (style === 'rounded') {\r\n            ctx.fillStyle = frameBgColor;\r\n            ctx.roundRect(x, y, width, height, 20); ctx.fill();\r\n            ctx.strokeStyle = frameBorderColor; ctx.stroke();\r\n        } else if (style === 'neon') {\r\n            ctx.fillRect(x, y, width, height);\r\n            ctx.shadowBlur = 8; ctx.shadowColor = frameBorderColor;\r\n            ctx.strokeRect(x, y, width, height); ctx.shadowColor = 'transparent';\r\n        } else if (style === 'vintage') {\r\n            ctx.fillStyle = '#f5e6d3'; ctx.fillRect(x, y, width, height);\r\n            ctx.strokeStyle = '#c49a6c'; ctx.lineWidth = 3;\r\n            ctx.strokeRect(x-2, y-2, width+4, height+4);\r\n            ctx.fillStyle = frameBgColor; ctx.fillRect(x, y, width, height);\r\n        } else if (style === 'minimal') {\r\n            ctx.fillRect(x, y, width, height);\r\n            ctx.strokeStyle = '#ccc'; ctx.strokeRect(x, y, width, height);\r\n        }\r\n        ctx.restore();\r\n    }\r\n\r\n    function generateQR() {\r\n        const size = parseInt(document.getElementById('qrSize').value);\r\n        const qrColor = document.getElementById('fgColorPicker').value;\r\n        const qrBg = document.getElementById('bgColorPicker').value;\r\n        const labelText = document.getElementById('labelText').value;\r\n        const labelFont = document.getElementById('labelFontSelect').value === 'CustomFont' && customFontFamily ? customFontFamily : document.getElementById('labelFontSelect').value;\r\n        labelTextColor = document.getElementById('labelTextColor').value;\r\n        labelBgColor = document.getElementById('labelBgColor').value;\r\n        frameBorderColor = document.getElementById('frameBorderColor').value;\r\n        frameBgColor = document.getElementById('frameBgColor').value;\r\n        cornerColors.outer = document.getElementById('cornerOuterColor').value;\r\n        cornerColors.inner = document.getElementById('cornerInnerColor').value;\r\n        cornerColors.center = document.getElementById('cornerCenterColor').value;\r\n        cornerShapes.outer = document.getElementById('outerShapeSelect').value;\r\n        cornerShapes.center = document.getElementById('centerShapeSelect').value;\r\n\r\n        const hasLabel = labelText && labelText.trim() !== '';\r\n        const extraHeight = hasLabel ? size * 0.12 : 0;\r\n        const canvasWidth = size;\r\n        const canvasHeight = size + extraHeight;\r\n        const canvas = document.getElementById('mainCanvas');\r\n        canvas.width = canvasWidth;\r\n        canvas.height = canvasHeight;\r\n        const ctx = canvas.getContext('2d');\r\n\r\n        \/\/ 1. Latar belakang canvas (warna latar frame)\r\n        ctx.fillStyle = frameBgColor;\r\n        ctx.fillRect(0, 0, canvasWidth, canvasHeight);\r\n\r\n        \/\/ 2. Gambar area QR background\r\n        ctx.fillStyle = qrBg;\r\n        ctx.fillRect(0, 0, size, size);\r\n\r\n        \/\/ 3. Gambar frame border (di belakang QR)\r\n        if (currentFrameStyle !== 'none' && currentFrameStyle !== 'label') {\r\n            const margin = 15;\r\n            drawFrameBorder(ctx, margin, margin, size - margin*2, size - margin*2, currentFrameStyle);\r\n        }\r\n\r\n        \/\/ 4. Generate matrix QR\r\n        const code = document.getElementById('cCode')?.value || \"\";\r\n        let data = \"https:\/\/example.com\";\r\n        if(currentType===\"url\") data = document.getElementById('urlD')?.value || data;\r\n        else if(currentType===\"wa\") data = `https:\/\/wa.me\/${code}${document.getElementById('waP')?.value}?text=${encodeURIComponent(document.getElementById('waM')?.value || \"\")}`;\r\n        else if(currentType===\"zoom\") data = `https:\/\/zoom.us\/j\/${document.getElementById('zId')?.value}?pwd=${document.getElementById('zPw')?.value}`;\r\n        else if(currentType===\"wifi\") data = `WIFI:S:${document.getElementById('wSsid')?.value};P:${document.getElementById('wPass')?.value};;`;\r\n        else if(currentType===\"contact\") {\r\n            let name = document.getElementById('vN')?.value || \"\";\r\n            let phone = document.getElementById('vT')?.value || \"\";\r\n            let email = document.getElementById('vE')?.value || \"\";\r\n            data = `BEGIN:VCARD\\nVERSION:3.0\\nFN:${name}\\nTEL:+${code}${phone}\\nEMAIL:${email}\\nEND:VCARD`;\r\n        }\r\n        else if(currentType===\"email\") {\r\n            let to = document.getElementById('eT')?.value || \"\";\r\n            let subject = document.getElementById('eS')?.value || \"\";\r\n            let body = document.getElementById('eB')?.value || \"\";\r\n            data = `mailto:${to}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;\r\n        }\r\n        else if(currentType===\"sms\") {\r\n            let phone = document.getElementById('sP')?.value || \"\";\r\n            let message = document.getElementById('sB')?.value || \"\";\r\n            data = `sms:${code}${phone}?body=${encodeURIComponent(message)}`;\r\n        }\r\n        else if(currentType===\"event\") {\r\n            let title = document.getElementById('evT')?.value || \"\";\r\n            let location = document.getElementById('evL')?.value || \"\";\r\n            let start = document.getElementById('evS')?.value || \"\";\r\n            let end = document.getElementById('evE')?.value || \"\";\r\n            let desc = document.getElementById('evD')?.value || \"\";\r\n            let ics = \"BEGIN:VEVENT\\n\";\r\n            if(title) ics += `SUMMARY:${title}\\n`;\r\n            if(location) ics += `LOCATION:${location}\\n`;\r\n            if(start) ics += `DTSTART:${start.replace(\/[-:]\/g, \"\")}\\n`;\r\n            if(end) ics += `DTEND:${end.replace(\/[-:]\/g, \"\")}\\n`;\r\n            if(desc) ics += `DESCRIPTION:${desc}\\n`;\r\n            ics += \"END:VEVENT\";\r\n            data = ics;\r\n        }\r\n        else if(currentType===\"maps\") data = `geo:${document.getElementById('mLat')?.value},${document.getElementById('mLng')?.value}`;\r\n        else if(currentType===\"text\") data = document.getElementById('txtD')?.value || \" \";\r\n\r\n        const qr = qrcode(0, 'H');\r\n        qr.addData(data); qr.make();\r\n        const count = qr.getModuleCount();\r\n        const pad = size * 0.1, mod = (size - pad * 2) \/ count;\r\n\r\n        ctx.fillStyle = qrColor;\r\n        for (let r = 0; r < count; r++) {\r\n            for (let c = 0; c < count; c++) {\r\n                if ((r < 7 && c < 7) || (r < 7 && c >= count - 7) || (r >= count - 7 && c < 7)) continue;\r\n                if (qr.isDark(r, c)) {\r\n                    const x = pad + c * mod, y = pad + r * mod;\r\n                    ctx.beginPath();\r\n                    if(designConfig.pattern === 'dot') ctx.arc(x+mod\/2, y+mod\/2, mod\/2.4, 0, Math.PI*2);\r\n                    else if(designConfig.pattern === 'rounded') ctx.roundRect(x+0.5, y+0.5, mod-1, mod-1, mod*0.4);\r\n                    else if(designConfig.pattern === 'diamond') { ctx.moveTo(x+mod\/2, y); ctx.lineTo(x+mod, y+mod\/2); ctx.lineTo(x+mod\/2, y+mod); ctx.lineTo(x, y+mod\/2); }\r\n                    else ctx.rect(x, y, mod, mod);\r\n                    ctx.fill();\r\n                }\r\n            }\r\n        }\r\n\r\n        \/\/ 5. Gambar finder patterns dengan outer shape dan center shape terpisah\r\n        function drawFinder(sx, sy, sw, sh) {\r\n            \/\/ Outer shape (7x7)\r\n            ctx.fillStyle = cornerColors.outer;\r\n            if (cornerShapes.outer === 'square') {\r\n                ctx.fillRect(sx, sy, sw, sh);\r\n            } else if (cornerShapes.outer === 'circle') {\r\n                ctx.beginPath();\r\n                ctx.arc(sx + sw\/2, sy + sh\/2, sw\/2, 0, 2*Math.PI);\r\n                ctx.fill();\r\n            } else if (cornerShapes.outer === 'smooth') {\r\n                const radius = sw * 0.2;\r\n                ctx.beginPath();\r\n                ctx.roundRect(sx, sy, sw, sh, radius);\r\n                ctx.fill();\r\n            }\r\n            \/\/ Inner square (5x5) - selalu persegi agar terbaca\r\n            const innerSize = sw * (5\/7);\r\n            const ix = sx + (sw - innerSize)\/2;\r\n            const iy = sy + (sh - innerSize)\/2;\r\n            ctx.fillStyle = cornerColors.inner;\r\n            ctx.fillRect(ix, iy, innerSize, innerSize);\r\n            \/\/ Center shape (3x3)\r\n            const centerSize = sw * (3\/7);\r\n            const cx = sx + (sw - centerSize)\/2;\r\n            const cy = sy + (sh - centerSize)\/2;\r\n            ctx.fillStyle = cornerColors.center;\r\n            if (cornerShapes.center === 'square') {\r\n                ctx.fillRect(cx, cy, centerSize, centerSize);\r\n            } else if (cornerShapes.center === 'circle') {\r\n                ctx.beginPath();\r\n                ctx.arc(cx + centerSize\/2, cy + centerSize\/2, centerSize\/2, 0, 2*Math.PI);\r\n                ctx.fill();\r\n            } else if (cornerShapes.center === 'dot') {\r\n                const dotSize = centerSize * 0.4;\r\n                ctx.fillRect(cx + (centerSize - dotSize)\/2, cy + (centerSize - dotSize)\/2, dotSize, dotSize);\r\n            }\r\n        }\r\n        const markerSize = mod * 7;\r\n        drawFinder(pad, pad, markerSize, markerSize);\r\n        drawFinder(pad + (count-7)*mod, pad, markerSize, markerSize);\r\n        drawFinder(pad, pad + (count-7)*mod, markerSize, markerSize);\r\n\r\n        \/\/ 6. Gambar ikon\/logo di tengah (dengan background putih yang cukup lebar)\r\n        const iconSizePercent = parseInt(document.getElementById('iconSizeSlider').value) \/ 100;\r\n        if(selectedIcon !== 'none') {\r\n            const ls = size * iconSizePercent;\r\n            const lx = (size - ls) \/ 2;\r\n            const ly = (size - ls) \/ 2;\r\n            \/\/ Background putih dengan margin ekstra agar modul di sekitar tidak terganggu\r\n            ctx.fillStyle = qrBg;\r\n            ctx.beginPath();\r\n            ctx.roundRect(lx - 6, ly - 6, ls + 12, ls + 12, 12);\r\n            ctx.fill();\r\n            if(selectedIcon === 'upload' && customLogo) {\r\n                ctx.drawImage(customLogo, lx, ly, ls, ls);\r\n            } else if (icons[selectedIcon]) {\r\n                const p = new Path2D(icons[selectedIcon]);\r\n                ctx.save();\r\n                ctx.translate(lx, ly);\r\n                ctx.scale(ls\/24, ls\/24);\r\n                ctx.fillStyle = qrColor;\r\n                ctx.fill(p);\r\n                ctx.restore();\r\n            }\r\n        }\r\n\r\n        \/\/ 7. Gambar label di bawah QR\r\n        if (hasLabel) {\r\n            const labelY = size;\r\n            const labelH = extraHeight;\r\n            ctx.fillStyle = labelBgColor;\r\n            ctx.fillRect(0, labelY, size, labelH);\r\n            ctx.fillStyle = labelTextColor;\r\n            ctx.font = `bold ${labelH * 0.65}px ${labelFont}`;\r\n            ctx.textAlign = \"center\";\r\n            ctx.fillText(labelText, size\/2, labelY + labelH * 0.7);\r\n        }\r\n    }\r\n\r\n    function downloadQR() {\r\n        const link = document.createElement('a');\r\n        link.download = 'QR-Pro-Global.png';\r\n        link.href = document.getElementById('mainCanvas').toDataURL();\r\n        link.click();\r\n    }\r\n\r\n    if (!CanvasRenderingContext2D.prototype.roundRect) {\r\n        CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) {\r\n            if (w < 2 * r) r = w \/ 2;\r\n            if (h < 2 * r) r = h \/ 2;\r\n            this.moveTo(x+r, y);\r\n            this.lineTo(x+w-r, y);\r\n            this.quadraticCurveTo(x+w, y, x+w, y+r);\r\n            this.lineTo(x+w, y+h-r);\r\n            this.quadraticCurveTo(x+w, y+h, x+w-r, y+h);\r\n            this.lineTo(x+r, y+h);\r\n            this.quadraticCurveTo(x, y+h, x, y+h-r);\r\n            this.lineTo(x, y+r);\r\n            this.quadraticCurveTo(x, y, x+r, y);\r\n            return this;\r\n        };\r\n    }\r\n\r\n    initUI();\r\n    window.generateQR = generateQR;\r\n    window.downloadQR = downloadQR;\r\n    window.syncColor = syncColor;\r\n    window.updateCornerColors = updateCornerColors;\r\n    window.updateCornerColorsText = updateCornerColorsText;\r\n    window.syncFrameColor = syncFrameColor;\r\n    window.syncLabelColor = syncLabelColor;\r\n    window.syncLabelBgColor = syncLabelBgColor;\r\n    window.uploadCustomFont = uploadCustomFont;\r\n    window.handleLogoUpload = handleLogoUpload;\r\n<\/script>\r\n<\/body>\r\n<\/html>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>","protected":false},"excerpt":{"rendered":"<p>QR Pro Global | QR Terbaca + Sudut Terpisah (Outer &#038; Center) 1. Konten Global (10 Fungsi) \ud83c\udf10 URL \ud83d\udcac [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"no-sidebar","site-content-layout":"","ast-site-content-layout":"full-width-container","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"disabled","ast-breadcrumbs-content":"","ast-featured-img":"disabled","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-1990","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v22.3 (Yoast SEO v24.7) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>QRcode - marineconservation.id<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/marineconservation.id\/id\/qrcode\/\" \/>\n<meta property=\"og:locale\" content=\"id_ID\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"QRcode\" \/>\n<meta property=\"og:description\" content=\"QR Pro Global | QR Terbaca + Sudut Terpisah (Outer &#038; Center) 1. Konten Global (10 Fungsi) \ud83c\udf10 URL \ud83d\udcac [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/marineconservation.id\/id\/qrcode\/\" \/>\n<meta property=\"og:site_name\" content=\"marineconservation.id\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/profile.php?id=61572311944591\" \/>\n<meta property=\"article:modified_time\" content=\"2026-03-31T22:59:09+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Estimasi waktu membaca\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 menit\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/marineconservation.id\/qrcode\/\",\"url\":\"https:\/\/marineconservation.id\/qrcode\/\",\"name\":\"QRcode - marineconservation.id\",\"isPartOf\":{\"@id\":\"https:\/\/marineconservation.id\/#website\"},\"datePublished\":\"2026-03-30T22:13:15+00:00\",\"dateModified\":\"2026-03-31T22:59:09+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/marineconservation.id\/qrcode\/#breadcrumb\"},\"inLanguage\":\"id\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/marineconservation.id\/qrcode\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/marineconservation.id\/qrcode\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/marineconservation.id\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"QRcode\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/marineconservation.id\/#website\",\"url\":\"https:\/\/marineconservation.id\/\",\"name\":\"marineconservation.id\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/marineconservation.id\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/marineconservation.id\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"id\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/marineconservation.id\/#organization\",\"name\":\"marineconservation.id\",\"url\":\"https:\/\/marineconservation.id\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"id\",\"@id\":\"https:\/\/marineconservation.id\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/marineconservation.id\/wp-content\/uploads\/2025\/02\/Marine-Conservation-Indonesia.png\",\"contentUrl\":\"https:\/\/marineconservation.id\/wp-content\/uploads\/2025\/02\/Marine-Conservation-Indonesia.png\",\"width\":500,\"height\":500,\"caption\":\"marineconservation.id\"},\"image\":{\"@id\":\"https:\/\/marineconservation.id\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/profile.php?id=61572311944591\",\"https:\/\/www.instagram.com\/marineconservation.id\/\",\"https:\/\/www.youtube.com\/watch?v=nOmjtk-dTg8&list=LL\"]}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"QRcode - marineconservation.id","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/marineconservation.id\/id\/qrcode\/","og_locale":"id_ID","og_type":"article","og_title":"QRcode","og_description":"QR Pro Global | QR Terbaca + Sudut Terpisah (Outer &#038; Center) 1. Konten Global (10 Fungsi) \ud83c\udf10 URL \ud83d\udcac [&hellip;]","og_url":"https:\/\/marineconservation.id\/id\/qrcode\/","og_site_name":"marineconservation.id","article_publisher":"https:\/\/www.facebook.com\/profile.php?id=61572311944591","article_modified_time":"2026-03-31T22:59:09+00:00","twitter_card":"summary_large_image","twitter_misc":{"Estimasi waktu membaca":"1 menit"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/marineconservation.id\/qrcode\/","url":"https:\/\/marineconservation.id\/qrcode\/","name":"QRcode - marineconservation.id","isPartOf":{"@id":"https:\/\/marineconservation.id\/#website"},"datePublished":"2026-03-30T22:13:15+00:00","dateModified":"2026-03-31T22:59:09+00:00","breadcrumb":{"@id":"https:\/\/marineconservation.id\/qrcode\/#breadcrumb"},"inLanguage":"id","potentialAction":[{"@type":"ReadAction","target":["https:\/\/marineconservation.id\/qrcode\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/marineconservation.id\/qrcode\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/marineconservation.id\/"},{"@type":"ListItem","position":2,"name":"QRcode"}]},{"@type":"WebSite","@id":"https:\/\/marineconservation.id\/#website","url":"https:\/\/marineconservation.id\/","name":"marineconservation.id","description":"","publisher":{"@id":"https:\/\/marineconservation.id\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/marineconservation.id\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"id"},{"@type":"Organization","@id":"https:\/\/marineconservation.id\/#organization","name":"marineconservation.id","url":"https:\/\/marineconservation.id\/","logo":{"@type":"ImageObject","inLanguage":"id","@id":"https:\/\/marineconservation.id\/#\/schema\/logo\/image\/","url":"https:\/\/marineconservation.id\/wp-content\/uploads\/2025\/02\/Marine-Conservation-Indonesia.png","contentUrl":"https:\/\/marineconservation.id\/wp-content\/uploads\/2025\/02\/Marine-Conservation-Indonesia.png","width":500,"height":500,"caption":"marineconservation.id"},"image":{"@id":"https:\/\/marineconservation.id\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/profile.php?id=61572311944591","https:\/\/www.instagram.com\/marineconservation.id\/","https:\/\/www.youtube.com\/watch?v=nOmjtk-dTg8&list=LL"]}]}},"_links":{"self":[{"href":"https:\/\/marineconservation.id\/id\/wp-json\/wp\/v2\/pages\/1990","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/marineconservation.id\/id\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/marineconservation.id\/id\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/marineconservation.id\/id\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/marineconservation.id\/id\/wp-json\/wp\/v2\/comments?post=1990"}],"version-history":[{"count":178,"href":"https:\/\/marineconservation.id\/id\/wp-json\/wp\/v2\/pages\/1990\/revisions"}],"predecessor-version":[{"id":2230,"href":"https:\/\/marineconservation.id\/id\/wp-json\/wp\/v2\/pages\/1990\/revisions\/2230"}],"wp:attachment":[{"href":"https:\/\/marineconservation.id\/id\/wp-json\/wp\/v2\/media?parent=1990"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}