js生成书法字帖

偶然的机会看到一个生成书法字帖的工具网站,一时之间不知道田字格是怎么生成的,写个demo记录下

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <script src="./plugins/jquery/jquery-1.9.1.js"></script>
    <script src="./plugins/html2canvas.min.js"></script>
    <script src="./plugins/jspdf/dist/jspdf.umd.min.js"></script>
    <script src="./plugins/hanzi-writer.min.js"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      body {
        font-family: "msyh";
        letter-spacing: 0.01px; /*解决jspdf的英文字母间隔问题  */
      }
      table {
        font-size: 2.5rem;
        border-spacing: 0.5rem;
        border: 1px solid black;
      }
      table.tb_cn tr td {
        width: 3.45rem;
        height: 3.45rem;
        line-height: 3.45rem;
        text-align: center;
        color: rgb(153, 153, 153);
        border: 1px solid black;
      }
      table.tb_cn tr td :nth-child(odd) {
        height: 2rem;
        line-height: 2rem;
      }
      table tr td:first-child {
        color: black;
      }
      table tr td.with-line {
        position: relative;
      }
      table tr td.with-line::before {
        content: "";
        position: absolute;
        height: 1px;
        width: 100%;
        left: 0;
        top: 50%;
        transform: translateY(-50%);
        border-top: 1px dashed silver;
        z-index: -1;
      }
      table tr td.with-line::after {
        content: "";
        position: absolute;
        height: 100%;
        width: 1px;
        left: 50%;
        top: 0;
        transform: translateX(-50%);
        border-left: 1px dashed silver;
        z-index: -1;
      }
      table.tb_img tr td {
        width: 6 * 3.45rem;
        height: 4 * 3.45rem;
        line-height: 6 * 3.45rem;
        text-align: center;
        border: 1px solid black;
        padding: 0.25rem;
      }
      #container {
        display: flex;
      }
      #content-con {
        width: 210mm;
      }
      #content-con .content {
        height: 300.5mm;
      }
    </style>
  </head>
  <body>
    <div id="container">
      <div id="content-con"></div>
      <div id="toolbar">
        <textarea id="text" type="textarea" onchange="changeContent()" rows="5">你好世界你好世界你好世界你好世界你好世界</textarea>
        <br />
        <button onclick="exportPdf('content-con')">export Pdf</button>
      </div>
    </div>
  </body>
  <script>
    const gbl_param = {
      page_num: 3,
      cn_col_num: 12,
      cn_row_num: 8,
      char_size: 36,
      img_bg_id: 0,
      img_row_num: 2,
      img_col_num: 3,
    };

    function exportPdf(domId) {
      html2canvas(document.getElementById(domId)).then((canvas) => {
        const contentWidth = canvas.width;
        const contentHeight = canvas.height;
        console.log("content", contentWidth, contentHeight);

        const s_w = 595.28;
        const s_h = 841.89;
        const sd_w = 7;

        const pageHeight = (contentWidth / s_w) * s_h; //每页pdf的canvas高度;
        console.log("page", pageHeight);

        let leftHeight = contentHeight; //未生成pdf的canvas高度
        let position = 10; //pdf页面偏移

        //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
        const imgWidth = s_w - sd_w;
        // const imgWidth = s_w;
        const imgHeight = (imgWidth / contentWidth) * contentHeight; //canvas转为图片后适配A4纸宽度的高度
        console.log("img", imgWidth, imgHeight);

        const pageData = canvas.toDataURL("image/jpeg", 1.0);

        const pdf = new jspdf.jsPDF("p", "pt", "a4");
        //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
        //当内容未超过pdf一页显示的范围,无需分页
        if (leftHeight < pageHeight) {
          pdf.addImage(pageData, "JPEG", sd_w, position, imgWidth, imgHeight);
        } else {
          while (leftHeight > 0) {
            pdf.addImage(pageData, "JPEG", sd_w, position, imgWidth, imgHeight);
            leftHeight -= pageHeight;
            position -= s_h;

            console.log("leftHeight", leftHeight);
            // console.log("position", position);
            //避免添加空白页
            if (leftHeight > 0) {
              pdf.addPage();
            }
          }

          let targetPage = pdf.internal.getNumberOfPages();
          pdf.deletePage(targetPage); // 删除最后一页
        }

        // pdf.save("xxxx.pdf");
        window.open(pdf.output("bloburl")); //预览pdf
      });
    }

    function renderFanningStrokes(target, strokes) {
      const char_size = gbl_param.char_size;
      // createElementNS() 方法可创建带有指定命名空间的元素节点
      const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
      svg.style.width = char_size + "px";
      svg.style.height = char_size + "px";
      svg.style.border = "1px solid #EEE";
      svg.style.marginRight = "3px";
      target.appendChild(svg);
      const group = document.createElementNS("http://www.w3.org/2000/svg", "g");

      const transformData = HanziWriter.getScalingTransform(char_size, char_size);
      group.setAttributeNS(null, "transform", transformData.transform);
      svg.appendChild(group);

      strokes.forEach(function (strokePath) {
        const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
        path.setAttributeNS(null, "d", strokePath);
        path.style.fill = "#555";
        group.appendChild(path);
      });
    }

    function getCharOrder(domId, char_cn) {
      HanziWriter.loadCharacterData(char_cn).then(function (charData) {
        const target = document.getElementById(domId);
        target.innerHTML = "";
        for (let i = 0; i < charData.strokes.length; i++) {
          const strokesPortion = charData.strokes.slice(0, i + 1);
          renderFanningStrokes(target, strokesPortion);
        }
      });
    }

    function changeContent() {
      let str = $("#text").val();
      if (str.length < gbl_param.page_num * Math.floor(gbl_param.cn_row_num / 2) || containsNonChineseChar(str)) return;

      const cn_char_num = Math.floor(gbl_param.cn_row_num / 2);
      let cnt = 0;
      for (let i = 0; i < gbl_param.page_num; i++) {
        for (let j = 0; j < cn_char_num; j++) {
          getCharOrder("charOrder" + cnt, str[cnt]);
          $(".content .tb_cn")
            .eq(i)
            .find("tr")
            .eq(2 * j + 1)
            .find("td")
            .text(str[cnt]);
          cnt++;
        }
      }
    }
    initPage();
    changeContent();

    function initPage() {
      const cn_col_num = gbl_param.cn_col_num;
      const cn_row_num = gbl_param.cn_row_num;

      $("#content-con").html("");
      let cnt = -1;
      for (let i = 0; i < gbl_param.page_num; i++) {
        $("#content-con").append(
          "<div class='content'><table class='tb_cn'>" +
            Array(cn_row_num)
              .fill(null)
              .map((val, idx) => {
                if (idx % 2 == 0) {
                  cnt++;
                  return `<tr><td id="charOrder${cnt}" colspan="${cn_col_num}"></td></tr>`;
                } else {
                  return `<tr>${Array(cn_col_num)
                    .fill(null)
                    .map((val, idx) => {
                      return `<td class="with-line"></td>`;
                    })
                    .join("")}
                    </tr>`;
                }
              })
              .join("") +
            "</table><table class='tb_img'>" +
            Array(gbl_param.img_row_num)
              .fill(null)
              .map((val, idx) => {
                gbl_param.img_bg_id += 1;
                const url = "./images/test_svg/" + "0".repeat(5 - gbl_param.img_bg_id.toString().length) + gbl_param.img_bg_id + ".svg";
                return `<tr>${Array(gbl_param.img_col_num)
                  .fill(null)
                  .map((val, idx) => {
                    return `<td><img src="${url}" width="240" height="240" ></td>`;
                  })
                  .join("")}</tr>`;
              })
              .join("") +
            "</table></div>"
        );
      }
    }

    function containsNonChineseChar(str) {
      return /[^\u4e00-\u9fa5]/.test(str);
    }
  </script>
</html>

抓svg图的python

import requests
import time

# 发送HTTP请求获取网页内容
response = requests.get(url_pre)
response.raise_for_status()  # 检查请求是否成功

path = "../files/images/svg/"
i = 1440
while i <= 1440:
    url = url_pre + "svg/0" + str(i).zfill(4) + ".svg"
    print(url)

    img_response = requests.get(url)
    with open(path + url.split("/")[-1], "wb") as f:
        f.write(img_response.content)

    if i % 36 == 0:
        # break
        time.sleep(2)

    i += 1
else:
    print("done")

posted @ 2024-07-23 09:14  carol2014  阅读(3)  评论(0编辑  收藏  举报