夜雨聆风学习资料网

ARTICLE · 1188658

不用设计软件,纯网页也能做出以假乱真的电子印章

不用设计软件,纯网页也能做出以假乱真的电子印章

前阵子帮朋友处理一份合同,对方要盖个章再回传。朋友犯了难——公司章在办公室,人在外地,拍照抠图又糊得不行。我说这不难,花了点时间给他做了个纯网页的印章工具,打开浏览器拖两下参数,一个透明背景的电子章就出来了,直接贴到 PDF 上严丝合缝。

今天把这个小工具拆开讲讲,代码不复杂,但里面几个细节挺有意思,尤其是环形文字怎么排、透明背景怎么导出,弄明白了你也能自己改。

它能做什么

一句话:左边调参数,右边实时出图,满意了点一下按钮下载透明 PNG。

具体支持这些:

  • 形状:正圆、椭圆、方形、长方形、菱形、八角、长条骑缝章、无边框钢印
  • 边框:单细、单粗、内外双圈(国内公章那种经典样式)
  • 文字:外圈环绕的公司名、中间的大字、底部的小字,字号字距都能调
  • 中心可以放五角星
  • 颜色随便选,大红、朱红、暗红、蓝、黑都行
  • 做旧效果:拖一个滑块,从干净的电子章一路做到斑驳的老旧实物章
  • 顶部还有五个预设模板,懒得一个个调就点一下直接套用

整个页面就三个文件:一个 HTML 管结构,一个 CSS 管样式,一个 JS 管画图。没有任何框架,没有任何依赖,双击就能跑。

为什么用 Canvas,不用现成图片

做印章这事,最笨的办法是提前画好一堆图片,用户选哪个给哪个。但这样形状、文字、颜色一组合,图片数量就爆炸了,而且文字还不能改。

所以我用的是 Canvas 画布,所有东西都是代码实时画出来的。你改一个字、挪一下滑块,右边立刻重画一遍。好处是组合无限多,坏处是得自己把每条线、每个字的位置算清楚。

透明背景也是靠 Canvas 天然支持——画布不填充底色就是透明的,导出 PNG 自动带透明通道,拿去贴合同、贴图片都不会有白底。

最费脑子的一块:环形文字

公章最有辨识度的,就是公司名字沿着圆圈弯过来。这个效果看着简单,写起来得想一会儿。

思路是这样的:把一句话拆成一个个单字,算出每个字应该待在圆弧上的哪个角度,然后挨个把画布原点挪到那个位置、旋转一个角度、把字写上去、再转回来。核心就这么几行:

chars.forEach((ch, i) => {
const ang = start + step * i;        // 当前这个字的角度
  ctx.save();
  ctx.translate(cx + Math.cos(ang) * r, cy + Math.sin(ang) * r); // 挪到圆弧上的点
  ctx.rotate(ang + Math.PI / 2);        // 让字正对圆心外侧
  ctx.fillText(ch, 0, 0);
  ctx.restore();
});

这里有两个关键值:一个是文字总共铺多宽(弧度),一个是起始角度。我把"字间距"做成了一个控制总弧度的滑块——字少的时候让它们挤在上半圈,字多的时候自动散开,不至于叠在一起。起始角度固定在正上方往两边分,这样不管几个字都是居中对称的。

内外双圈怎么画

国内公章的边框通常是外面一圈粗、里面一圈细。实现起来就是画两个同心的圆,外圈线宽设大一点,内圈往里缩一段、线宽设小。缩进的距离要跟着边框粗细走,不然粗边框会把内圈吃掉。

八角和菱形这种,就是按角度算出几个顶点,用线段连起来围成一圈,道理和画圆差不多,只是把平滑的弧换成了折线。

做旧效果:给像素随机"掉墨"

真实的印章盖出来不会是完美的,总有油墨溢出、缺墨、磨损。我做了个"斑驳程度"的滑块来模拟这个。

做法有点取巧:画完整个章之后,把画布的像素数据取出来,按一定概率随机挑一些有颜色的像素,把它们的透明度调低一点。拉满的时候就像一个盖了很多次、墨快干了的老章;拉到零就是干净锐利的电子章。做正式电子签章就归零,想要点真实感就往上拉一点。

一个绕不开的坑:字体

篆书、隶书这种,是书画闲章的灵魂。但问题在于——浏览器默认根本没有这些字体,它只能用你电脑里装了的。所以如果你选了篆书但系统没装,它会悄悄回退到宋体,效果就差远了。

这个没法在纯网页里完美解决,除非把字体文件一起打包进去(体积会很大)。所以我的处理是:优先用你系统已有的字体,缺了就回退,并在说明里讲清楚。真要篆书效果,建议本地装一个篆书字体包。

怎么用

没有任何安装步骤。把三个文件放在同一个文件夹,双击 index.html,浏览器就打开了。

上手建议:先点一个预设模板(比如"圆形公章"),看个大概样子,再慢慢改公司名、颜色、字号。调好之后,下方选个 2 倍清晰度,点下载,透明 PNG 就存到本地了。

写在最后

这工具本身是个小玩意,但它说明了一件事:很多看起来要专业软件才能做的东西,用浏览器自带的 Canvas 就能搞定,不用装任何东西,还能随手改。

需要提醒一句:电子印章请用在正当用途上,比如内部流程、个人练习、设计稿演示。伪造公章是违法的,这点一定拎得清。

工具代码都在,想加功能——比如支持上传自己的字体、加公司 logo、批量生成——都是能往上接的。有需要可以自己动手改,或者留言交流。

<!DOCTYPE html><htmllang="zh-CN"><head>  <metacharset="UTF-8" />  <metaname="viewport"content="width=device-width, initial-scale=1.0" />  <title>电子印章生成器</title>  <linkrel="stylesheet"href="style.css" /></head><body>  <headerclass="topbar">    <h1>电子印章生成器</h1>    <spanclass="hint">左侧调参数,右侧实时预览,下方下载透明 PNG</span>  </header>  <mainclass="layout">    <!-- 左侧参数面板 -->    <asideclass="panel"id="panel">      <divclass="group">        <labelclass="group-title">预设模板</label>        <divclass="preset-row">          <buttonclass="preset"data-preset="round">圆形公章</button>          <buttonclass="preset"data-preset="square">方形闲章</button>          <buttonclass="preset"data-preset="strip">骑缝章</button>          <buttonclass="preset"data-preset="steel">钢印</button>          <buttonclass="preset"data-preset="rect">竖长方章</button>        </div>      </div>      <divclass="group">        <labelclass="group-title">印章形状</label>        <selectid="shape">          <optionvalue="circle">正圆形</option>          <optionvalue="ellipse">椭圆形</option>          <optionvalue="square">正方形</option>          <optionvalue="rect">长方形</option>          <optionvalue="diamond">菱形</option>          <optionvalue="octagon">八角形</option>          <optionvalue="strip">骑缝章(长条)</option>          <optionvalue="steel">钢印(无边框浮雕)</option>        </select>      </div>      <divclass="group">        <labelclass="group-title">画布大小:<spanid="sizeVal">420</span> px</label>        <inputtype="range"id="size"min="200"max="700"value="420" />        <labelclass="group-title">宽高比例</label>        <selectid="ratio">          <optionvalue="1:1">1:1 正圆 / 正方</option>          <optionvalue="3:2">3:2 横椭圆</option>          <optionvalue="2:3">2:3 竖长方</option>          <optionvalue="4:1">4:1 长条骑缝</option>        </select>      </div>      <divclass="group">        <labelclass="group-title">边框样式</label>        <selectid="border">          <optionvalue="single-thin">单细边框</option>          <optionvalue="single-thick">单粗边框</option>          <optionvalue="double">内外双圈(内细外粗)</option>          <optionvalue="none">无边框</option>        </select>        <labelclass="group-title">边框粗细:<spanid="bwVal">6</span> px</label>        <inputtype="range"id="borderWidth"min="1"max="20"value="6" />      </div>      <divclass="group">        <labelclass="group-title">环绕文字(外圈)</label>        <inputtype="text"id="arcText"value="青岛示例科技有限公司" />        <labelclass="group-title">环绕字号:<spanid="arcSizeVal">30</span></label>        <inputtype="range"id="arcSize"min="12"max="60"value="30" />        <labelclass="group-title">字间距(弧度展开):<spanid="arcSpreadVal">260</span>°</label>        <inputtype="range"id="arcSpread"min="120"max="340"value="260" />      </div>      <divclass="group">        <labelclass="group-title">中心元素</label>        <labelclass="inline"><inputtype="checkbox"id="star"checked /> 显示五角星</label>        <labelclass="group-title">五角星大小:<spanid="starSizeVal">60</span></label>        <inputtype="range"id="starSize"min="20"max="160"value="60" />      </div>      <divclass="group">        <labelclass="group-title">中心 / 底部文字</label>        <inputtype="text"id="centerText"placeholder="中心大字(可空,如 合同专用章)"value="" />        <inputtype="text"id="bottomText"placeholder="底部小字(可空,如 专用章)"value="专用章" />        <labelclass="group-title">底部字号:<spanid="bottomSizeVal">26</span></label>        <inputtype="range"id="bottomSize"min="12"max="50"value="26" />      </div>      <divclass="group">        <labelclass="group-title">字体</label>        <selectid="font">          <optionvalue='"SimSun","宋体",serif'>宋体</option>          <optionvalue='"KaiTi","楷体",serif'>楷体</option>          <optionvalue='"SimHei","黑体",sans-serif'>黑体</option>          <optionvalue='"LiSu","隶书",serif'>隶书</option>          <optionvalue='"STZhongsong","FangSong","仿宋",serif'>仿宋</option>        </select>      </div>      <divclass="group">        <labelclass="group-title">印泥颜色</label>        <divclass="color-row">          <inputtype="color"id="color"value="#d4001a" />          <buttonclass="swatch"data-color="#d4001a"style="background:#d4001a"></button>          <buttonclass="swatch"data-color="#b01722"style="background:#b01722"></button>          <buttonclass="swatch"data-color="#e8362d"style="background:#e8362d"></button>          <buttonclass="swatch"data-color="#1f4fd4"style="background:#1f4fd4"></button>          <buttonclass="swatch"data-color="#111111"style="background:#111111"></button>        </div>      </div>      <divclass="group">        <labelclass="group-title">做旧 / 斑驳程度:<spanid="distressVal">0</span>%</label>        <inputtype="range"id="distress"min="0"max="80"value="0" />      </div>    </aside>    <!-- 右侧预览 -->    <sectionclass="preview">      <divclass="canvas-wrap">        <canvasid="canvas"width="420"height="420"></canvas>      </div>    </section>  </main>  <!-- 下方导出 -->  <footerclass="exportbar">    <labelclass="inline">导出倍数:      <selectid="scale">        <optionvalue="1">1x</option>        <optionvalue="2"selected>2x(更清晰)</option>        <optionvalue="3">3x</option>      </select>    </label>    <buttonid="download"class="download-btn">下载透明 PNG</button>  </footer>  <scriptsrc="app.js"></script></body></html>

相关学习资料