{"id":5149,"date":"2025-09-09T05:54:48","date_gmt":"2025-09-09T05:54:48","guid":{"rendered":"https:\/\/meiling412.com\/?page_id=5149"},"modified":"2025-09-11T01:58:04","modified_gmt":"2025-09-11T01:58:04","slug":"bible-graphics-generator","status":"publish","type":"page","link":"https:\/\/meiling412.com\/en\/bible-graphics-generator\/","title":{"rendered":"Scripture Image Card Generator"},"content":{"rendered":"\n<!doctype html>\n<html lang=\"zh-Hant\">\n<head>\n<meta charset=\"utf-8\" \/>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" \/>\n<title>\u7dda\u4e0a\u4f5c\u5716\uff5c\u7d93\u6587\u5716\u751f\u6210\u5668\uff08\u7a69\u5b9a\u9032\u968e\u7248\uff09<\/title>\n\n<!-- \u2705 \u7121\u7248\u6b0a\u4e2d\u6587\u5b57\u9ad4\uff08Google Fonts\uff09 -->\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Noto+Sans+TC:wght@400;700;900&#038;family=Noto+Serif+TC:wght@400;700;900&#038;family=Zen+Maru+Gothic:wght@400;700&#038;family=Shippori+Mincho:wght@400;700&#038;display=swap\" rel=\"stylesheet\">\n\n<style>\n  :root{\n    --bg:#fff;--panel:#f9fafb;--soft:#e5e7eb;--text:#111827;--muted:#6b7280;--accent:#7c3aed;\n    --left-col:360px;          \/* \u5de6\u5074\u63a7\u5236\u6b04\u5bec\uff08\u684c\u6a5f\u7528\uff09 *\/\n    --left-gap:110px;          \/* \u5de6\u6b04\u8207\u9810\u89bd\u9593\u8ddd\uff08\u684c\u6a5f\u7528\uff09 *\/\n    --preview-w:480px;         \/* JS \u6703\u8986\u5beb\uff1b\u684c\u6a5f\u9810\u89bd\u5bec\u5ea6\u4e0a\u9650 *\/\n  }\n  *{box-sizing:border-box}\n  body{margin:0;background:var(--bg);color:var(--text);font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,\"Noto Sans TC\",\"PingFang TC\",sans-serif}\n  .wrap{max-width:1280px;margin:24px auto;padding:0 16px}\n  .grid{display:grid;grid-template-columns:var(--left-col) 1fr;gap:16px}\n  .card{background:var(--panel);border:1px solid var(--soft);border-radius:16px;box-shadow:0 4px 12px rgba(0,0,0,.06);padding:16px}\n  h1{font-size:22px;margin:0 0 12px}\n  h2{font-size:15px;margin:16px 0 8px;color:var(--muted)}\n  label{display:block;font-size:13px;margin:8px 0 4px;color:#374151}\n  input,select,textarea{width:100%;background:#fff;color:#111827;border:1px solid #d1d5db;border-radius:10px;padding:8px;font-size:14px}\n  textarea{min-height:96px;resize:vertical}\n  .row{display:grid;grid-template-columns:1fr 1fr;gap:8px}\n  .range{accent-color:var(--accent);width:100%}\n  .btn{display:inline-flex;align-items:center;gap:8px;background:linear-gradient(135deg,#7c3aed,#06b6d4);border:none;color:#fff;padding:10px 14px;border-radius:12px;font-weight:600;cursor:pointer}\n\n  \/* \u53f3\u5074\u9810\u89bd\uff1a\u684c\u6a5f\u56fa\u5b9a\uff1b\u624b\u6a5f\u55ae\u6b04\u81ea\u9069\u61c9 *\/\n  #previewCol{\n    position:fixed !important;\n    top:var(--dock-top,120px);\n    left:calc(var(--left-col) + var(--left-gap));\n    width:var(--preview-w);\n    max-width:480px; \/* \u2705 \u4e0d\u8d85\u904e 480px\uff0c\u907f\u514d\u58d3\u5230\u53f3\u5074 *\/\n    z-index:999;\n    display:flex;justify-content:center;align-items:flex-start;\n  }\n  .previewWrap{width:100%;display:flex;justify-content:center;align-items:center}\n  #c{\n    width:100%;\n    height:auto;\n    background:#000;\n    border-radius:16px;\n    display:block;\n    box-shadow:0 6px 20px rgba(0,0,0,.12);\n  }\n\n  \/* \ud83d\udcf1 \u624b\u6a5f\uff0f\u5e73\u677f\uff1a\u55ae\u6b04\u3001\u9810\u89bd 100% \u5bec\uff0c\u4e0d\u56fa\u5b9a\u5b9a\u4f4d *\/\n  @media (max-width:1024px){\n    .grid{grid-template-columns:1fr}\n    #previewCol{position:static !important;left:auto;top:auto;width:100%;max-width:100%}\n    .row{grid-template-columns:1fr}\n  }\n\n  \/* \u7e2e\u5716 *\/\n  .thumbs{display:grid;grid-template-columns:repeat(5,1fr);gap:6px;margin-top:6px}\n  .thumbBtn{\n    width:100%;aspect-ratio:16\/10;border:1px solid #d1d5db;border-radius:8px;background:#eee center\/cover no-repeat;cursor:pointer;\n    transition:transform .1s ease, border-color .1s ease;\n  }\n  .thumbBtn:hover{transform:translateY(-1px);border-color:var(--accent)}\n  .small{font-size:12px;color:#6b7280}\n<\/style>\n<\/head>\n<body>\n  <div class=\"wrap\">\n    <h1>\u7dda\u4e0a\u4f5c\u5716\uff5c\u7d93\u6587\u5716\u751f\u6210\u5668\uff08\u7a69\u5b9a\u9032\u968e\u7248\uff09<\/h1>\n    <div class=\"grid\">\n      <!-- \u5de6\u5074\u63a7\u5236 -->\n      <aside class=\"card\">\n        <h2>\u756b\u5e03\u5c3a\u5bf8<\/h2>\n        <div class=\"row\">\n          <div>\n            <label>\u5feb\u901f\u9078\u64c7<\/label>\n            <select id=\"presetSize\">\n              <option value=\"1920x1080\">YouTube 16:9\uff081920\u00d71080\uff09<\/option>\n              <option value=\"1280x720\">\u7e2e\u5716 16:9\uff081280\u00d7720\uff09<\/option>\n              <option value=\"1200x630\">Facebook \u8cbc\u6587\uff081200\u00d7630\uff09<\/option>\n              <option value=\"1080x1080\" selected>Instagram \u6b63\u65b9\u5f62\uff081080\u00d71080\uff09<\/option>\n              <option value=\"1080x1920\">\u5782\u76f4 9:16\uff081080\u00d71920\uff09<\/option>\n            <\/select>\n          <\/div>\n          <div>\n            <label>\u81ea\u8a02\u5c3a\u5bf8 (\u5bec\u00d7\u9ad8)<\/label>\n            <input id=\"customSize\" type=\"text\" value=\"1080x1080\"\/>\n          <\/div>\n        <\/div>\n\n        <h2>\u80cc\u666f\u5716<\/h2>\n        <label>\u4e0a\u50b3\u80cc\u666f\u5716<\/label>\n        <input id=\"bgFile\" type=\"file\" accept=\"image\/*\"\/>\n        <label>\u5feb\u901f\u9078\u5716\uff08\u9ad8\u89e3\u6790\uff09<\/label>\n        <div class=\"thumbs\" id=\"bgThumbs\"><\/div>\n\n        <h2>\u6587\u5b57\u5167\u5bb9<\/h2>\n        <textarea id=\"mainText\">\u8a69\u7bc7 119:105 \n\u7962\u7684\u8a71\u662f\u6211\u8173\u524d\u7684\u71c8\n\u662f\u6211\u8def\u4e0a\u7684\u5149<\/textarea>\n\n        <div class=\"row\">\n          <div>\n            <label>\u5b57\u578b\uff08Google Fonts\uff09<\/label>\n            <select id=\"fontFamily\">\n              <option value=\"'Noto Sans TC', 'PingFang TC', sans-serif\" selected>Noto Sans TC\uff08\u7121\u896f\u7dda\uff09<\/option>\n              <option value=\"'Noto Serif TC', 'PMingLiU', serif\">Noto Serif TC\uff08\u660e\u9ad4\uff09<\/option>\n              <option value=\"'Zen Maru Gothic', 'Noto Sans TC', sans-serif\">Zen Maru Gothic\uff08\u5713\u9ad4\uff09<\/option>\n              <option value=\"'Shippori Mincho', 'Noto Serif TC', serif\">Shippori Mincho\uff08\u7d30\u660e\u98a8\uff09<\/option>\n            <\/select>\n          <\/div>\n          <div>\n            <label>\u5b57\u9ad4\u5927\u5c0f<\/label>\n            <input id=\"fontSize\" type=\"number\" value=\"120\"\/>\n          <\/div>\n        <\/div>\n\n        <div class=\"row\">\n          <div>\n            <label>\u6587\u5b57\u984f\u8272<\/label>\n            <input id=\"fillColor\" type=\"color\" value=\"#ffffff\"\/>\n          <\/div>\n          <div>\n            <label>\u5916\u6846\u984f\u8272<\/label>\n            <input id=\"strokeColor\" type=\"color\" value=\"#000000\"\/>\n          <\/div>\n        <\/div>\n\n        <div class=\"row\">\n          <div>\n            <label>\u5916\u6846\u7c97\u7d30<\/label>\n            <input id=\"strokeWidth\" class=\"range\" type=\"range\" min=\"0\" max=\"20\" step=\"1\" value=\"6\"\/>\n          <\/div>\n          <div>\n            <label>\u5c0d\u9f4a<\/label>\n            <select id=\"align\">\n              <option value=\"center\" selected>\u7f6e\u4e2d<\/option>\n              <option value=\"left\">\u9760\u5de6<\/option>\n              <option value=\"right\">\u9760\u53f3<\/option>\n            <\/select>\n          <\/div>\n        <\/div>\n\n        <div class=\"row\">\n          <div>\n            <label>\u6587\u5b57\u5340\u5bec\u5ea6\uff08%\uff09<\/label>\n            <input id=\"textWidth\" class=\"range\" type=\"range\" min=\"40\" max=\"100\" step=\"1\" value=\"90\"\/>\n          <\/div>\n          <div>\n            <label>\u4ee5\u9802\u7aef\u5c0d\u9f4a<\/label>\n            <div style=\"display:flex;align-items:center;gap:8px\">\n              <input id=\"anchorTop\" type=\"checkbox\" style=\"width:auto\"\/>\n              <span class=\"small\">\uff08\u95dc\u9589\uff1d\u4ee5\u5340\u584a\u4e2d\u5fc3\u5c0d\u9f4a\uff09<\/span>\n            <\/div>\n          <\/div>\n        <\/div>\n\n        <div class=\"row\">\n          <div>\n            <label>\u6c34\u5e73\u4f4d\u7f6e\uff08%\uff09<\/label>\n            <input id=\"hPos\" class=\"range\" type=\"range\" min=\"0\" max=\"100\" step=\"1\" value=\"50\"\/>\n          <\/div>\n          <div>\n            <label>\u5782\u76f4\u4f4d\u7f6e\uff08%\uff09<\/label>\n            <input id=\"vPos\" class=\"range\" type=\"range\" min=\"0\" max=\"100\" step=\"1\" value=\"55\"\/>\n          <\/div>\n        <\/div>\n\n        <h2>\u4e0b\u8f09\u8a2d\u5b9a<\/h2>\n        <div class=\"row\">\n          <div>\n            <label>\u683c\u5f0f<\/label>\n            <select id=\"saveFormat\">\n              <option value=\"png\">PNG<\/option>\n              <option value=\"jpeg\">JPG<\/option>\n              <option value=\"webp\">WebP<\/option>\n            <\/select>\n          <\/div>\n          <div>\n            <label>\u54c1\u8cea (JPG\/WebP)<\/label>\n            <input id=\"saveQuality\" type=\"number\" min=\"0.5\" max=\"1\" step=\"0.05\" value=\"0.9\"\/>\n          <\/div>\n        <\/div>\n\n        <div class=\"small\" style=\"margin-top:8px\">\n          \u63d0\u793a\uff1a\u624b\u52d5\u63db\u884c\u5c0e\u81f4\u67d0\u884c\u904e\u9577\u6642\uff0c\u7cfb\u7d71\u6703\u81ea\u52d5\u7b49\u6bd4\u7e2e\u5c0f\u5b57\u7d1a\u4ee5\u907f\u514d\u8d85\u51fa\u8a2d\u5b9a\u7684\u6587\u5b57\u5340\u5bec\u5ea6\u3002\n        <\/div>\n\n        <div style=\"margin-top:12px;text-align:right\">\n          <button class=\"btn\" id=\"download\">\u4e0b\u8f09\u5716\u7247<\/button>\n        <\/div>\n      <\/aside>\n\n      <!-- \u53f3\u5074\u9810\u89bd -->\n      <main class=\"card\" id=\"previewCol\">\n        <div class=\"previewWrap\">\n          <canvas id=\"c\" width=\"1080\" height=\"1080\"><\/canvas>\n        <\/div>\n      <\/main>\n    <\/div>\n  <\/div>\n\n<script>\nconst $=id=>document.getElementById(id)\nconst c=$('c'),ctx=c.getContext('2d')\nctx.imageSmoothingEnabled=true\nctx.imageSmoothingQuality='high'\nlet bgImg=null\n\n\/* \u8b93\u9810\u89bd\u907f\u958b WP Admin Bar\/\u4e3b\u984c Header\uff08\u684c\u6a5f\u7528\uff09 *\/\n;(function calcTop(){\n  function setTop(){\n    const adminBar=document.getElementById('wpadminbar')\n    const adminH=adminBar?adminBar.offsetHeight:0\n    const header=document.querySelector('#site-header, header.site-header, header[role=\"banner\"], header')\n    const headerH=header?header.offsetHeight:0\n    const top=adminH+headerH+20\n    document.documentElement.style.setProperty('--dock-top', top+'px')\n  }\n  window.addEventListener('load',setTop)\n  window.addEventListener('resize',setTop)\n  window.addEventListener('scroll',setTop)\n  setTop()\n})()\n\nconst mqMobile = window.matchMedia('(max-width:1024px)')\nconst isMobile = ()=> mqMobile.matches\n\nfunction cssVar(name){\n  const v=getComputedStyle(document.documentElement).getPropertyValue(name)\n  return parseFloat(v)||0\n}\n\n\/* \u2705 \u684c\u6a5f\u9810\u89bd\u56fa\u5b9a\u4e0d\u8d85\u904e 480px\uff1b\u624b\u6a5f\u81ea\u9069\u61c9\u5bb9\u5668\u5bec *\/\nfunction updatePreviewWidth(){\n  const aspect = c.width \/ c.height\n  let maxW, maxH\n\n  if (isMobile()){\n    const col = document.querySelector('#previewCol')\n    const containerW = (col && col.clientWidth) ? col.clientWidth : (window.innerWidth - 32)\n    maxW = Math.max(240, containerW)\n    maxH = Math.max(240, window.innerHeight * 0.7)\n  } else {\n    const left = cssVar('--left-col') + cssVar('--left-gap')\n    maxW = Math.min(480, Math.max(240, window.innerWidth - left - 40))  \/\/ \u26f3 \u4e0a\u9650 480\n    const top = cssVar('--dock-top')\n    maxH = Math.max(240, window.innerHeight - top - 40)\n  }\n\n  let w, h\n  if (aspect >= 1){\n    const wByHeight = maxH * aspect\n    w = Math.min(maxW, wByHeight)\n    h = w \/ aspect\n  }else{\n    const hByWidth = maxW \/ aspect\n    h = Math.min(maxH, hByWidth)\n    w = h * aspect\n  }\n\n  document.documentElement.style.setProperty('--preview-w', (isMobile()? maxW : w) + 'px')\n  c.style.maxHeight = maxH + 'px'\n}\n\n\/* \u80cc\u666f\u6e05\u55ae\uff08Unsplash\uff1bCORS OK\uff09\u2014\u2014\u53bb\u91cd\u7cbe\u9078 30 \u5f35 *\/\nconst bgUrls = [\n  \"https:\/\/images.unsplash.com\/photo-1501785888041-af3ef285b470?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1441974231531-c6227db76b6e?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1507525428034-b723cf961d3e?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1470770841072-f978cf4d019e?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1465101162946-4377e57745c3?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1443890923422-7819ed4101c0?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1519681393784-d120267933ba?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1472214103451-9374bd1c798e?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1441829266145-b7a8ed1d4e0b?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1500534314209-a25ddb2bd429?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1526481280698-8fcc13fdc3da?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1470777636352-1cf9a81a8b5f?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1493246507139-91e8fad9978e?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1445820135717-d00a8e6c9a3b?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1533518463841-4f8d3f4e3f2a?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1452570053594-1b985d6ea890?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1439853949127-fa647821eba0?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1493244040629-496f6d136cc3?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1482192505345-5655af888cc4?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1427434846691-47fc561d1179?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1445299370299-fba06c02df22?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1476610182048-b716b8518aae?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1451188502541-13943edb6acb?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1469474968028-3f33c5f01b5d?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1497294815431-9365093b7331?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1500530855697-0673cf1d4d49?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1500534314209-8d0dfb1a82b1?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1491553895911-5512f3b0ec30?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1480497490787-505ec076689f?auto=format&fit=crop&w=1600&q=80\",\n  \"https:\/\/images.unsplash.com\/photo-1441974231531-02cb7d78490a?auto=format&fit=crop&w=1600&q=80\"\n]\n\n\/* \u7522\u751f\u7e2e\u5716\uff08\u9810\u8f09\u6210\u529f\u624d\u986f\u793a\uff0c\u907f\u514d\u65b7\u5716\uff09 *\/\n;(function buildThumbs(){\n  const box=$('bgThumbs'); box.innerHTML=''\n  const toThumb=u=>{\n    let v=u.replace(\/w=\\d+\/,'w=480')\n    v = \/h=\\d+\/.test(v) ? v.replace(\/h=\\d+\/,'h=320') : v + '&h=320'\n    if(!\/fit=crop\/.test(v)) v += '&fit=crop'\n    v += '&q=70&dpr=1'\n    return v\n  }\n  const preload=(src)=>new Promise((res,rej)=>{\n    const img=new Image()\n    img.crossOrigin='anonymous'\n    img.referrerPolicy='no-referrer'\n    img.onload=()=>res(img)\n    img.onerror=rej\n    img.src=src\n  })\n  bgUrls.forEach(async (url)=>{\n    try{\n      await preload(toThumb(url))\n      const btn=document.createElement('button')\n      btn.className='thumbBtn'\n      btn.type='button'\n      btn.style.backgroundImage=`url(\"${toThumb(url)}\")`\n      btn.onclick=async ()=>{\n        const full=new Image()\n        full.crossOrigin='anonymous'\n        full.referrerPolicy='no-referrer'\n        full.src=url\n        if(full.decode){try{await full.decode()}catch(e){}}\n        if(full.complete || full.naturalWidth>0){bgImg=full; draw()}\n        else full.onload=()=>{bgImg=full; draw()}\n      }\n      box.appendChild(btn)\n    }catch(e){}\n  })\n})()\n\n\/* \u72c0\u614b *\/\nconst state={\n  fontFamily:\"'Noto Sans TC', 'PingFang TC', sans-serif\",\n  fontSize:120,\n  align:'center',\n  textWidthP:0.90,\n  posX:0.5,\n  posY:0.55,\n  anchorTop:false,\n  safeMargin:0.05,\n  fillColor:'#ffffff',\n  strokeColor:'#000000',\n  strokeWidth:6\n}\n\n\/* \u7e6a\u88fd *\/\nfunction draw(){\n  ctx.clearRect(0,0,c.width,c.height)\n\n  \/\/ \u80cc\u666f cover\n  if(bgImg && bgImg.naturalWidth>0){\n    const sR=bgImg.naturalWidth\/bgImg.naturalHeight, dR=c.width\/c.height\n    let sx=0,sy=0,sw=bgImg.naturalWidth,sh=bgImg.naturalHeight\n    if(sR>dR){ sh=bgImg.naturalHeight; sw=sh*dR; sx=(bgImg.naturalWidth-sw)\/2 }\n    else{ sw=bgImg.naturalWidth; sh=sw\/dR; sy=(bgImg.naturalHeight-sh)\/2 }\n    ctx.drawImage(bgImg,sx,sy,sw,sh,0,0,c.width,c.height)\n  }else{\n    ctx.fillStyle=\"#1f2937\"; ctx.fillRect(0,0,c.width,c.height)\n  }\n\n  \/\/ \u6587\u5b57\n  let fs=state.fontSize\n  ctx.textAlign=state.align\n  ctx.textBaseline=state.anchorTop?'top':'middle'\n  ctx.font=`bold ${fs}px ${state.fontFamily}`\n\n  const padding=Math.round(c.width*0.06)\n  const maxW=Math.max(100, Math.round(c.width*state.textWidthP)) - padding*2\n\n  const SAFE=state.safeMargin\n  let x=c.width*state.posX\n  let y=c.height*state.posY\n  const minY=c.height*SAFE, maxY=c.height*(1-SAFE)\n  if(y<minY) y=minY; if(y>maxY) y=maxY\n\n  const lines=$('mainText').value.split(\/\\r?\\n\/).filter(Boolean)\n  if(lines.length){\n    let longest=0\n    lines.forEach(ln=>{ const w=ctx.measureText(ln).width; if(w>longest) longest=w })\n    if(longest>maxW){ const scale=maxW\/longest; fs=Math.max(12, Math.floor(fs*scale)); ctx.font=`bold ${fs}px ${state.fontFamily}` }\n  }\n  const lh=fs*1.3\n  const totalH=lh*(lines.length-1)\n  const startY=state.anchorTop? y : (y-totalH\/2)\n\n  if(state.strokeWidth>0){\n    ctx.lineWidth=state.strokeWidth\n    ctx.strokeStyle=state.strokeColor\n    lines.forEach((ln,i)=>ctx.strokeText(ln,x,startY+i*lh))\n  }\n  ctx.fillStyle=state.fillColor\n  lines.forEach((ln,i)=>ctx.fillText(ln,x,startY+i*lh))\n}\n\n\/* \u7d81\u63a7\u5236\u9805 *\/\n$('fontFamily').addEventListener('change',e=>{state.fontFamily=e.target.value; draw()})\n$('fontSize').addEventListener('input',e=>{state.fontSize=+e.target.value; draw()})\n$('align').addEventListener('change',e=>{state.align=e.target.value; draw()})\n$('textWidth').addEventListener('input',e=>{state.textWidthP=e.target.value\/100; draw()})\n$('hPos').addEventListener('input',e=>{state.posX=e.target.value\/100; draw()})\n$('vPos').addEventListener('input',e=>{state.posY=e.target.value\/100; draw()})\n$('anchorTop').addEventListener('change',e=>{state.anchorTop=e.target.checked; draw()})\n\n$('fillColor').addEventListener('input',e=>{state.fillColor=e.target.value; draw()})\n$('strokeColor').addEventListener('input',e=>{state.strokeColor=e.target.value; draw()})\n$('strokeWidth').addEventListener('input',e=>{state.strokeWidth=+e.target.value; draw()})\n\n$('bgFile').addEventListener('change',e=>{\n  const f=e.target.files[0]; if(!f) return\n  const url=URL.createObjectURL(f); const img=new Image()\n  img.onload=()=>{bgImg=img; draw(); URL.revokeObjectURL(url)}\n  img.src=url\n})\n\n\/* \u5c3a\u5bf8\u5207\u63db\uff08\u4fdd\u7559\u5168\u90e8\u5c3a\u5bf8\uff09 *\/\nfunction applySize(text){\n  const [w,h]=text.split('x').map(Number)\n  if(w&&h){ c.width=w; c.height=h; updatePreviewWidth(); draw() }\n}\n$('presetSize').addEventListener('change',()=>{\n  $('customSize').value=$('presetSize').value\n  applySize($('presetSize').value)\n})\n$('customSize').addEventListener('change',()=>applySize($('customSize').value))\n\n\/* \u4e0b\u8f09 *\/\n$('download').addEventListener('click',()=>{\n  const fmt=$('saveFormat').value\n  const q=parseFloat($('saveQuality').value)||0.9\n  const url=c.toDataURL(`image\/${fmt}`, q)\n  const a=document.createElement('a')\n  a.href=url; a.download=`verse.${fmt}`; a.click()\n})\n\n\/* \u8996\u7a97\u8abf\u6574 *\/\nwindow.addEventListener('resize', updatePreviewWidth)\nmqMobile.addEventListener?.('change', updatePreviewWidth)\n\n\/* \u2705 \u9810\u8a2d\u80cc\u666f\u907f\u514d\u9ed1\u5c4f *\/\nwindow.addEventListener('load',()=>{\n  const demo=new Image()\n  demo.crossOrigin='anonymous'\n  demo.src=\"https:\/\/images.unsplash.com\/photo-1501785888041-af3ef285b470?auto=format&fit=crop&w=1600&q=80\"\n  demo.onload=()=>{bgImg=demo; draw()}\n})\n\n\/* \u521d\u59cb *\/\nupdatePreviewWidth()\ndraw()\n<\/script>\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>\u7dda\u4e0a\u4f5c\u5716\uff5c\u7d93\u6587\u5716\u751f\u6210\u5668\uff08\u7a69\u5b9a\u9032\u968e\u7248\uff09 \u7dda\u4e0a\u4f5c\u5716\uff5c\u7d93\u6587\u5716\u751f\u6210\u5668\uff08\u7a69\u5b9a\u9032\u968e\u7248\uff09 \u756b\u5e03\u5c3a\u5bf8 \u5feb\u901f\u9078\u64c7 YouTube [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"ocean_post_layout":"","ocean_both_sidebars_style":"","ocean_both_sidebars_content_width":0,"ocean_both_sidebars_sidebars_width":0,"ocean_sidebar":"","ocean_second_sidebar":"","ocean_disable_margins":"enable","ocean_add_body_class":"","ocean_shortcode_before_top_bar":"","ocean_shortcode_after_top_bar":"","ocean_shortcode_before_header":"","ocean_shortcode_after_header":"","ocean_has_shortcode":"","ocean_shortcode_after_title":"","ocean_shortcode_before_footer_widgets":"","ocean_shortcode_after_footer_widgets":"","ocean_shortcode_before_footer_bottom":"","ocean_shortcode_after_footer_bottom":"","ocean_display_top_bar":"default","ocean_display_header":"default","ocean_header_style":"","ocean_center_header_left_menu":"","ocean_custom_header_template":"","ocean_custom_logo":0,"ocean_custom_retina_logo":0,"ocean_custom_logo_max_width":0,"ocean_custom_logo_tablet_max_width":0,"ocean_custom_logo_mobile_max_width":0,"ocean_custom_logo_max_height":0,"ocean_custom_logo_tablet_max_height":0,"ocean_custom_logo_mobile_max_height":0,"ocean_header_custom_menu":"","ocean_menu_typo_font_family":"","ocean_menu_typo_font_subset":"","ocean_menu_typo_font_size":0,"ocean_menu_typo_font_size_tablet":0,"ocean_menu_typo_font_size_mobile":0,"ocean_menu_typo_font_size_unit":"px","ocean_menu_typo_font_weight":"","ocean_menu_typo_font_weight_tablet":"","ocean_menu_typo_font_weight_mobile":"","ocean_menu_typo_transform":"","ocean_menu_typo_transform_tablet":"","ocean_menu_typo_transform_mobile":"","ocean_menu_typo_line_height":0,"ocean_menu_typo_line_height_tablet":0,"ocean_menu_typo_line_height_mobile":0,"ocean_menu_typo_line_height_unit":"","ocean_menu_typo_spacing":0,"ocean_menu_typo_spacing_tablet":0,"ocean_menu_typo_spacing_mobile":0,"ocean_menu_typo_spacing_unit":"","ocean_menu_link_color":"","ocean_menu_link_color_hover":"","ocean_menu_link_color_active":"","ocean_menu_link_background":"","ocean_menu_link_hover_background":"","ocean_menu_link_active_background":"","ocean_menu_social_links_bg":"","ocean_menu_social_hover_links_bg":"","ocean_menu_social_links_color":"","ocean_menu_social_hover_links_color":"","ocean_disable_title":"default","ocean_disable_heading":"default","ocean_post_title":"","ocean_post_subheading":"","ocean_post_title_style":"","ocean_post_title_background_color":"","ocean_post_title_background":0,"ocean_post_title_bg_image_position":"","ocean_post_title_bg_image_attachment":"","ocean_post_title_bg_image_repeat":"","ocean_post_title_bg_image_size":"","ocean_post_title_height":0,"ocean_post_title_bg_overlay":0.5,"ocean_post_title_bg_overlay_color":"","ocean_disable_breadcrumbs":"default","ocean_breadcrumbs_color":"","ocean_breadcrumbs_separator_color":"","ocean_breadcrumbs_links_color":"","ocean_breadcrumbs_links_hover_color":"","ocean_display_footer_widgets":"default","ocean_display_footer_bottom":"default","ocean_custom_footer_template":"","footnotes":""},"class_list":["post-5149","page","type-page","status-publish","hentry","entry","owp-thumbs-layout-horizontal","owp-btn-normal","owp-tabs-layout-horizontal","has-no-thumbnails","has-product-nav"],"_hostinger_reach_plugin_has_subscription_block":false,"_hostinger_reach_plugin_is_elementor":false,"jetpack_sharing_enabled":true,"rttpg_featured_image_url":null,"rttpg_author":{"display_name":"Meiling","author_link":"https:\/\/meiling412.com\/en\/author\/lin576688103gmail-com\/"},"rttpg_comment":0,"rttpg_category":null,"rttpg_excerpt":"\u7dda\u4e0a\u4f5c\u5716\uff5c\u7d93\u6587\u5716\u751f\u6210\u5668\uff08\u7a69\u5b9a\u9032\u968e\u7248\uff09 \u7dda\u4e0a\u4f5c\u5716\uff5c\u7d93\u6587\u5716\u751f\u6210\u5668\uff08\u7a69\u5b9a\u9032\u968e\u7248\uff09 \u756b\u5e03\u5c3a\u5bf8 \u5feb\u901f\u9078\u64c7 YouTube&hellip;","_links":{"self":[{"href":"https:\/\/meiling412.com\/en\/wp-json\/wp\/v2\/pages\/5149","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/meiling412.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/meiling412.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/meiling412.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/meiling412.com\/en\/wp-json\/wp\/v2\/comments?post=5149"}],"version-history":[{"count":10,"href":"https:\/\/meiling412.com\/en\/wp-json\/wp\/v2\/pages\/5149\/revisions"}],"predecessor-version":[{"id":5304,"href":"https:\/\/meiling412.com\/en\/wp-json\/wp\/v2\/pages\/5149\/revisions\/5304"}],"wp:attachment":[{"href":"https:\/\/meiling412.com\/en\/wp-json\/wp\/v2\/media?parent=5149"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}