refactor(typesetting): 替换html2canvas为SnapDOM v2.12.0 - 解决渲染不一致问题

- 新增 public/static/lib/snapdom/snapdom.js (IIFE构建)
- phone_image.html script引用从html2canvas改为snapdom
- phone-image.js 3处截图调用全部替换为snapdom.toCanvas()
  - capturePageViaHtml2Canvas (分页截图)
  - 长图生成 (scale:2)
  - 导出单页 (scale:2)
- API映射: html2canvas(elem,{scale,useCORS,width,height,logging}) -> snapdom.toCanvas(elem,{scale,backgroundColor})
- 返回值兼容: Promise<Canvas> 下游toDataURL不受影响
- 保留html2canvas目录不删除(output.html仍引用)
This commit is contained in:
augushong
2026-05-17 13:25:58 +08:00
parent eb392ff1d7
commit 665a9cc9e5
3 changed files with 27 additions and 28 deletions

View File

@@ -81,9 +81,9 @@ var PhoneImageLogPanel = (function () {
* PhoneImageEngine - 手机图片排版引擎 * PhoneImageEngine - 手机图片排版引擎
* *
* 将文章HTML内容自动分页并渲染为手机尺寸图片 * 将文章HTML内容自动分页并渲染为手机尺寸图片
* 依赖: jQuery, html2canvas (项目已有) * 依赖: jQuery, SnapDOM (项目已有)
* *
* 渲染宽度540px, html2canvas scale=2 输出1080px * 渲染宽度540px, SnapDOM scale=2 输出1080px
* 小红书: 540x720 (输出1080x1440) * 小红书: 540x720 (输出1080x1440)
* 抖音: 540x960 (输出1080x1920) * 抖音: 540x960 (输出1080x1920)
*/ */
@@ -1111,7 +1111,7 @@ var PhoneImageEngine = (function () {
/** /**
* 共享截图核心逻辑 - 将pages渲染到staging并逐页截图 * 共享截图核心逻辑 - 将pages渲染到staging并逐页截图
* @param {Object} opts - { scale, outputCanvas, quality, sizeConfig } * @param {Object} opts - { scale, outputCanvas, quality, sizeConfig }
* scale: html2canvas缩放 (1=缩略图, 2=保存) * scale: SnapDOM缩放 (1=缩略图, 2=保存)
* outputCanvas: true=输出canvas对象, false=输出dataURL字符串 * outputCanvas: true=输出canvas对象, false=输出dataURL字符串
* quality: JPEG质量 (0-1) * quality: JPEG质量 (0-1)
* sizeConfig: 尺寸配置(用于纯图片页canvas渲染) * sizeConfig: 尺寸配置(用于纯图片页canvas渲染)
@@ -1142,7 +1142,7 @@ var PhoneImageEngine = (function () {
// 字体加载失败不影响截图,继续执行 // 字体加载失败不影响截图,继续执行
}).then(function () { }).then(function () {
requestAnimationFrame(function () { requestAnimationFrame(function () {
// html2canvas会跳过visibility:hidden的元素临时切换为可见 // SnapDOM会跳过visibility:hidden的元素临时切换为可见
$staging.css({ visibility: 'visible' }); $staging.css({ visibility: 'visible' });
// 表格和代码块已在中间栏中转为图片,无需再次转换 // 表格和代码块已在中间栏中转为图片,无需再次转换
runCaptureLoop($staging, opts, deferred, pageProgressCallback); runCaptureLoop($staging, opts, deferred, pageProgressCallback);
@@ -1197,7 +1197,7 @@ var PhoneImageEngine = (function () {
idx++; idx++;
captureNext(); captureNext();
}).catch(function () { }).catch(function () {
// 加载失败,回退到html2canvas // 加载失败,回退到SnapDOM截图
capturePageViaHtml2Canvas($elem, $staging, opts, results, deferred, function () { if (opts.streaming && opts.onPageReady) opts.onPageReady(results[results.length - 1], idx); if (pageProgressCallback) pageProgressCallback(idx + 1, total); idx++; captureNext(); }); capturePageViaHtml2Canvas($elem, $staging, opts, results, deferred, function () { if (opts.streaming && opts.onPageReady) opts.onPageReady(results[results.length - 1], idx); if (pageProgressCallback) pageProgressCallback(idx + 1, total); idx++; captureNext(); });
}); });
return; return;
@@ -1220,16 +1220,12 @@ var PhoneImageEngine = (function () {
} }
/** /**
* 用html2canvas截图单页 * 用SnapDOM截图单页
*/ */
function capturePageViaHtml2Canvas($elem, $staging, opts, results, deferred, onDone) { function capturePageViaHtml2Canvas($elem, $staging, opts, results, deferred, onDone) {
html2canvas($elem[0], { snapdom.toCanvas($elem[0], {
scale: opts.scale, scale: opts.scale,
useCORS: true, backgroundColor: '#ffffff'
backgroundColor: '#ffffff',
width: $elem.outerWidth(),
height: $elem.outerHeight(),
logging: false
}).then(function (canvas) { }).then(function (canvas) {
if (opts.outputCanvas) { if (opts.outputCanvas) {
results.push(canvas); results.push(canvas);
@@ -1574,13 +1570,9 @@ var PhoneImageEngine = (function () {
$('body').append($container); $('body').append($container);
requestAnimationFrame(function () { requestAnimationFrame(function () {
html2canvas($container[0], { snapdom.toCanvas($container[0], {
scale: 2, scale: 2,
useCORS: true, backgroundColor: '#ffffff'
backgroundColor: '#ffffff',
width: $container.outerWidth(),
height: $container[0].scrollHeight,
logging: false
}).then(function (canvas) { }).then(function (canvas) {
$container.remove(); $container.remove();
// 使用JPEG压缩减少体积 // 使用JPEG压缩减少体积
@@ -1643,16 +1635,9 @@ var PhoneImageEngine = (function () {
$('body').append($container); $('body').append($container);
requestAnimationFrame(function () { requestAnimationFrame(function () {
var width = $container.outerWidth(); snapdom.toCanvas($container[0], {
var height = $container[0].scrollHeight;
html2canvas($container[0], {
scale: 2, scale: 2,
useCORS: true, backgroundColor: '#ffffff'
backgroundColor: '#ffffff',
width: width,
height: height,
logging: false
}).then(function (canvas) { }).then(function (canvas) {
$container.remove(); $container.remove();
var link = document.createElement('a'); var link = document.createElement('a');

File diff suppressed because one or more lines are too long

View File

@@ -279,7 +279,7 @@
<script src="/static/lib/jquery/jquery-3.4.1.min.js"></script> <script src="/static/lib/jquery/jquery-3.4.1.min.js"></script>
<script src="/static/lib/layui/layui.js"></script> <script src="/static/lib/layui/layui.js"></script>
<script src="/static/lib/wangeditor/index.js"></script> <script src="/static/lib/wangeditor/index.js"></script>
<script src="/static/lib/html2canvas/html2canvas.js"></script> <script src="/static/lib/snapdom/snapdom.js"></script>
<script src="/static/js/phone-image.js"></script> <script src="/static/js/phone-image.js"></script>
<script> <script>
layui.use(['form', 'layer'], function () { layui.use(['form', 'layer'], function () {