diff --git a/public/static/js/phone-image.js b/public/static/js/phone-image.js index 739d9f0..dc35539 100644 --- a/public/static/js/phone-image.js +++ b/public/static/js/phone-image.js @@ -621,6 +621,75 @@ var PhoneImageEngine = (function () { // ===== DOM渲染 ===== + /** + * 将 #render-staging 中的代码块转为图片 + * 使用 prismjs 高亮 + html2canvas 截图替换 + * @returns {jQuery Deferred} resolves when all code blocks are converted + */ + function convertCodeBlocks() { + var deferred = $.Deferred(); + var $staging = $('#render-staging'); + + // 检查 Prism 是否可用 + if (typeof Prism === 'undefined') { + deferred.resolve(); + return deferred.promise(); + } + + // 给没有语言类的代码块添加默认语言 + $staging.find('pre > code:not([class*="language-"])').addClass('language-plaintext'); + + // 高亮所有代码块 + $staging.find('pre code').each(function () { + Prism.highlightElement(this); + }); + + // 找到所有代码块,逐个截图替换 + var $preBlocks = $staging.find('pre'); + if ($preBlocks.length === 0) { + deferred.resolve(); + return deferred.promise(); + } + + var idx = 0; + var total = $preBlocks.length; + + function convertNext() { + if (idx >= total) { + deferred.resolve(); + return; + } + + var $pre = $preBlocks.eq(idx); + html2canvas($pre[0], { + scale: 2, + useCORS: true, + backgroundColor: '#f5f5f5', + logging: false + }).then(function (canvas) { + var imgData = canvas.toDataURL('image/jpeg', 0.92); + var $img = $(''); + $img.attr('src', imgData); + $img.css({ + maxWidth: '100%', + height: 'auto', + display: 'block', + margin: '10px 0' + }); + $pre.replaceWith($img); + idx++; + convertNext(); + }).catch(function () { + // 截图失败则保留原始代码块 + idx++; + convertNext(); + }); + } + + convertNext(); + return deferred.promise(); + } + /** * 渲染到隐藏区域 → 截图 → 显示缩略图 * @param {Object} sizeConfig @@ -640,44 +709,86 @@ var PhoneImageEngine = (function () { // 等待一帧确保 DOM 渲染完成 requestAnimationFrame(function () { - var $pageElems = $staging.find('.phone-image-page'); - if ($pageElems.length === 0) { - displayThumbnails([], sizeConfig); - deferred.resolve(pages); - return; - } - - // 串行截图每一页 - var thumbnailDataUrls = []; - var idx = 0; - var total = $pageElems.length; - - function captureNext() { - if (idx >= total) { - $staging.empty(); - displayThumbnails(thumbnailDataUrls, sizeConfig); + // 先转换代码块为图片 + convertCodeBlocks().then(function () { + var $pageElems = $staging.find('.phone-image-page'); + if ($pageElems.length === 0) { + displayThumbnails([], sizeConfig); deferred.resolve(pages); return; } - var $elem = $pageElems.eq(idx); - html2canvas($elem[0], { - scale: 1, - useCORS: true, - backgroundColor: '#ffffff', - width: $elem.outerWidth(), - height: $elem.outerHeight(), - logging: false - }).then(function (canvas) { - thumbnailDataUrls.push(canvas.toDataURL('image/jpeg', 0.85)); - idx++; - captureNext(); - }).catch(function (err) { - deferred.reject('截图失败(第' + (idx + 1) + '页): ' + err); - }); - } + // 串行截图每一页 + var thumbnailDataUrls = []; + var idx = 0; + var total = $pageElems.length; - captureNext(); + function captureNext() { + if (idx >= total) { + $staging.empty(); + displayThumbnails(thumbnailDataUrls, sizeConfig); + deferred.resolve(pages); + return; + } + + var $elem = $pageElems.eq(idx); + html2canvas($elem[0], { + scale: 1, + useCORS: true, + backgroundColor: '#ffffff', + width: $elem.outerWidth(), + height: $elem.outerHeight(), + logging: false + }).then(function (canvas) { + thumbnailDataUrls.push(canvas.toDataURL('image/jpeg', 0.85)); + idx++; + captureNext(); + }).catch(function (err) { + deferred.reject('截图失败(第' + (idx + 1) + '页): ' + err); + }); + } + + captureNext(); + }).catch(function () { + // 代码块转换失败,继续截图流程 + var $pageElems = $staging.find('.phone-image-page'); + if ($pageElems.length === 0) { + displayThumbnails([], sizeConfig); + deferred.resolve(pages); + return; + } + + var thumbnailDataUrls = []; + var idx = 0; + var total = $pageElems.length; + + function captureNext() { + if (idx >= total) { + $staging.empty(); + displayThumbnails(thumbnailDataUrls, sizeConfig); + deferred.resolve(pages); + return; + } + + var $elem = $pageElems.eq(idx); + html2canvas($elem[0], { + scale: 1, + useCORS: true, + backgroundColor: '#ffffff', + width: $elem.outerWidth(), + height: $elem.outerHeight(), + logging: false + }).then(function (canvas) { + thumbnailDataUrls.push(canvas.toDataURL('image/jpeg', 0.85)); + idx++; + captureNext(); + }).catch(function (err) { + deferred.reject('截图失败(第' + (idx + 1) + '页): ' + err); + }); + } + + captureNext(); + }); }); return deferred.promise(); @@ -750,40 +861,79 @@ var PhoneImageEngine = (function () { $staging.append($wrapper); requestAnimationFrame(function () { - var $pageElems = $staging.find('.phone-image-page'); - if ($pageElems.length === 0) { - deferred.reject('没有可渲染的页面'); - return; - } - - var canvases = []; - var idx = 0; - var total = $pageElems.length; - - function captureNext() { - if (idx >= total) { - $staging.empty(); - deferred.resolve(canvases); + // 先转换代码块为图片 + convertCodeBlocks().then(function () { + var $pageElems = $staging.find('.phone-image-page'); + if ($pageElems.length === 0) { + deferred.reject('没有可渲染的页面'); return; } - html2canvas($pageElems.eq(idx)[0], { - scale: 2, - useCORS: true, - backgroundColor: '#ffffff', - width: $pageElems.eq(idx).outerWidth(), - height: $pageElems.eq(idx).outerHeight(), - logging: false - }).then(function (canvas) { - canvases.push(canvas); - idx++; - captureNext(); - }).catch(function (err) { - deferred.reject('截图失败(第' + (idx + 1) + '页): ' + err); - }); - } + var canvases = []; + var idx = 0; + var total = $pageElems.length; - captureNext(); + function captureNext() { + if (idx >= total) { + $staging.empty(); + deferred.resolve(canvases); + return; + } + + html2canvas($pageElems.eq(idx)[0], { + scale: 2, + useCORS: true, + backgroundColor: '#ffffff', + width: $pageElems.eq(idx).outerWidth(), + height: $pageElems.eq(idx).outerHeight(), + logging: false + }).then(function (canvas) { + canvases.push(canvas); + idx++; + captureNext(); + }).catch(function (err) { + deferred.reject('截图失败(第' + (idx + 1) + '页): ' + err); + }); + } + + captureNext(); + }).catch(function () { + // 代码块转换失败,继续截图流程 + var $pageElems = $staging.find('.phone-image-page'); + if ($pageElems.length === 0) { + deferred.reject('没有可渲染的页面'); + return; + } + + var canvases = []; + var idx = 0; + var total = $pageElems.length; + + function captureNext() { + if (idx >= total) { + $staging.empty(); + deferred.resolve(canvases); + return; + } + + html2canvas($pageElems.eq(idx)[0], { + scale: 2, + useCORS: true, + backgroundColor: '#ffffff', + width: $pageElems.eq(idx).outerWidth(), + height: $pageElems.eq(idx).outerHeight(), + logging: false + }).then(function (canvas) { + canvases.push(canvas); + idx++; + captureNext(); + }).catch(function (err) { + deferred.reject('截图失败(第' + (idx + 1) + '页): ' + err); + }); + } + + captureNext(); + }); }); return deferred.promise();