首页 > 其他分享 >js生成书法字帖

js生成书法字帖

时间:2024-07-23 09:18:10浏览次数:6  
标签:const 书法 svg param js 字帖 num pdf cn

偶然的机会看到一个生成书法字帖的工具网站,一时之间不知道田字格是怎么生成的,写个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")

标签:const,书法,svg,param,js,字帖,num,pdf,cn
From: https://www.cnblogs.com/caroline2016/p/18316486

相关文章

  • 进程占高 jstack
     1、使用top命令找到cpu,内存使用率高得进程,得到进程id2、top-Hp进程id,获取当前进程的线程,比如:top-Hp 269373、将得到线程号转换为16进制printf”%x\n“线程id  printf”%x\n“ 271554、利用jstack获取信息 jstack进程id|grep转换的16进制线程-A30,通......
  • 使用 json 配置文件进行 Python 日志记录
    我玩弄了日志模块,发现了一些我不太清楚的事情。首先,因为这是一个大程序,我希望代码尽可能简单,因此我使用了json配置文件.{"version":1,"disable_existing_loggers":false,"formatters":{"simple":{"format":"%(asctime)s-%(name)s......
  • JS劫持、DNS劫持与页面劫持跳转详解
    网络安全威胁种类繁多,其中JS劫持、DNS劫持和页面劫持跳转是常见的攻击手段。本文将详细讲解这些攻击的原理、方法和防御措施,帮助你更好地保护你的网络环境。一、JS劫持1.什么是JS劫持?JS劫持(JavaScriptHijacking)是一种通过恶意JavaScript代码控制或篡改网页内容的攻击手段......
  • Gson的基本使用:解析Json格式数据 序列化与反序列化
    目录一,Gson和Json1,Gson2,Json3,Gson处理对象的几个重要点4,序列化和反序列化二,Gson的使用1,Gson的创建2,简单对象序列化3,对象序列化,格式化输出日期4,嵌套对象序列化5,对象数组序列化6,对象集合序列化一,Gson和Json1,Gson        Gson是Google发布的一个Java库,可......
  • js 保留几位小数 不进行四舍五入
    1.使用Math.floor,负数的会先转正数进行计算,再转为负数,不进行四舍五入/***保留n位小数,不四舍五入*@param[n=1]保留小数点后几位*/exportfunctionkeepDigitDecimal(num:number,n=1):number{//小于零,先转正数计算if(num<0){return(Mat......
  • js 调用浏览器复制功能
      functioncopyWord(dom){    vardom='.'+dom;    varcopyText=$(dom).text().trim();//使用trim()移除两端空白    //navigatorclipboard需要https等安全上下文    if(navigator.clipboard&&window.isSecureContext){ ......
  • Python - Adob​​e InDesign Javascript 脚本帮助从 Python 调用 JSX
    提前致谢。希望每个人都表现出色。我试图从python调用Adob​​eIndesignJSX文件,下面是示例代码:我想在Adob​​eINdesign2024或更高版本上运行它。我在PythonInDesign脚本编写上看到了一些示例:从预检中获取溢出文本框以自动调整大小作为参考,可能适用于Ado......
  • jstat&jamp命令使用
    进制在线转换工具:https://www.uutils.com/enc/num_hex_convert.htm#google_vignette1jstackjstack简介:jstack是用于生成java虚拟机当前时刻的线程快照。线程快照是当前iava虚拟机内存每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因。......
  • jsdoc
    介绍:JSDoc3是一个用于JavaScript的API文档生成器,类似于Javadoc或phpDocumentor。可以将文档注释直接添加到源代码中。JSDoc工具将扫描您的源代码并为您生成一个HTML文档网站。说明:这里介绍的是把注释以一种类型文档的显示做标注,不是普通的做个文本描述。所以JSDoc......
  • 【GeoJSON】Java 使用 GeoTools 将 SHP 文件转成 GeoJSON 文件
    文章目录引言Mavensettings.xml配置配置项目中的pom.xml引入GeoToolsJar包使用引言在使用GeoTools时,我们没办法直接使用Maven中央库的GeoTools,所以就需要我们配置一下关于GeoTools自己的镜像,所以我们才需要以下这几个步骤:1、检查一下自己本机maven的......