feat(phone-image): codeFontScale+代碼塊預渲染+純圖片頁HTML

- config新增codeFontScale:1, applyFontScale新增--pi-code-font-scale CSS變量
- 新增async preRenderCodeBlocks(): 超長代碼塊(>contentAreaHeight)用SnapDOM截圖替換為img
- render()在parseHtmlToBlocks之前await preRenderCodeBlocks
- saveConfig payload新增codeFontScale
- renderPureImageToCanvas標記@deprecated
- 純圖片頁在renderDomPages中檢測並添加flex居中樣式
This commit is contained in:
augushong
2026-05-19 00:09:26 +08:00
parent 9915f1c887
commit f274691ba7

View File

@@ -101,6 +101,7 @@ var PhoneImageEngine = (function () {
contentPadding: 20,
fontScale: 1,
tableFontScale: 1,
codeFontScale: 1,
useDomPreview: true
};
@@ -172,15 +173,18 @@ var PhoneImageEngine = (function () {
function applyFontScale() {
var scale = config.fontScale || 1;
var tableScale = config.tableFontScale || 1;
var codeScale = config.codeFontScale || 1;
var preview = document.getElementById('render-preview');
if (preview) {
preview.style.setProperty('--pi-font-scale', scale);
preview.style.setProperty('--pi-table-font-scale', tableScale);
preview.style.setProperty('--pi-code-font-scale', codeScale);
}
var staging = document.getElementById('render-staging');
if (staging) {
staging.style.setProperty('--pi-font-scale', scale);
staging.style.setProperty('--pi-table-font-scale', tableScale);
staging.style.setProperty('--pi-code-font-scale', codeScale);
}
}
@@ -217,7 +221,10 @@ var PhoneImageEngine = (function () {
// 等待预览区内所有图片加载完成,否则 getBoundingClientRect 测高为0
PhoneImageLogPanel.log('等待图片加载...', 'info');
waitForImages(previewEl).then(function () {
waitForImages(previewEl).then(async function () {
// 预渲染超长代码块为图片
await preRenderCodeBlocks(contentAreaHeight);
var cleanHtml = previewEl ? previewEl.innerHTML : '';
var blocks = parseHtmlToBlocks(cleanHtml);
PhoneImageLogPanel.log('解析内容: ' + blocks.length + ' 个块', 'info');
@@ -1154,7 +1161,9 @@ var PhoneImageEngine = (function () {
}
/**
* @deprecated 纯图片页已统一走SnapDOM截图流程此函数不再被调用
* @deprecated DOM预览模式下不再使用Canvas绘制纯图片页。
* 纯图片页已统一使用HTML结构品牌header+居中图片+页脚)渲染。
* 保留函数供JPEG截图备用路径使用。
* 将原始图片绘制到canvas用于高质量保存路径
* @param {string} src - 图片src
* @param {number} width - 目标宽度
@@ -1328,6 +1337,49 @@ var PhoneImageEngine = (function () {
return deferred.promise();
}
/**
* 代码块预渲染:将超长代码块(>contentAreaHeight)用SnapDOM截图替换为img
* 短代码块保持HTML渲染
*/
async function preRenderCodeBlocks(contentAreaHeight) {
var previewEl = document.getElementById('render-preview');
if (!previewEl) return;
var preElements = previewEl.querySelectorAll('pre');
for (var i = 0; i < preElements.length; i++) {
var preEl = preElements[i];
var rect = preEl.getBoundingClientRect();
// 只对超出一页高度的代码块预渲染
if (rect.height > contentAreaHeight) {
try {
var canvas = await snapdom.toCanvas(preEl, {
scale: 2,
backgroundColor: '#f6f8fa'
});
var dataUrl = canvas.toDataURL('image/png');
// 创建替换img元素
var imgEl = document.createElement('img');
imgEl.setAttribute('data-converted', 'true');
imgEl.setAttribute('data-original-width', Math.round(rect.width));
imgEl.setAttribute('data-original-height', Math.round(rect.height));
imgEl.setAttribute('src', dataUrl);
imgEl.style.maxWidth = '100%';
imgEl.style.display = 'block';
imgEl.style.margin = '10px 0';
// 替换原pre元素
preEl.parentNode.replaceChild(imgEl, preEl);
} catch(e) {
// SnapDOM截图失败时保留原pre
console.warn('Code block pre-render failed:', e);
}
}
}
}
/**
* DOM分页预览 - 将pages[]转换为domPages格式
* 替代canvas截图方案直接操作DOM渲染
@@ -1346,12 +1398,46 @@ var PhoneImageEngine = (function () {
// 遍历pages创建domPage对象
for (var i = 0; i < pages.length; i++) {
var page = pages[i];
var pageHtml = page.html || '';
var pageType = page.type || 'content';
// 检测纯图片页:内容页中 .page-content 内仅有1个img且无文字
var isPureImage = false;
if (pageType === 'content') {
var $tempDiv = $('<div>').html(pageHtml);
var $pageContent = $tempDiv.find('.page-content');
if ($pageContent.length > 0) {
var contentText = $pageContent.text().replace(/\s/g, '');
if (contentText.length === 0) {
var $imgs = $pageContent.find('img');
if ($imgs.length === 1) {
var imgSrc = $imgs.first().attr('src');
if (imgSrc && imgSrc.length > 0 && $imgs.first().attr('data-converted') !== 'true') {
isPureImage = true;
// 为纯图片页调整 .page-content 样式:居中显示图片,保持原始宽高比
$pageContent.css({
'display': 'flex',
'align-items': 'center',
'justify-content': 'center'
});
$imgs.first().css({
'max-width': '100%',
'max-height': '100%',
'object-fit': 'contain'
});
pageHtml = $tempDiv.html();
}
}
}
}
}
var domPage = {
html: page.html || '',
type: page.type || 'content',
html: pageHtml,
type: pageType,
pageNum: page.pageNum || (i + 1),
valign: (config.pageAlignments && config.pageAlignments[i]) || 'top',
isPureImage: page.type === 'pure-image'
isPureImage: isPureImage
};
domPages.push(domPage);
}
@@ -1678,6 +1764,7 @@ var PhoneImageEngine = (function () {
watermark: saveConfig.watermark || config.watermark,
fontScale: config.fontScale || 1,
tableFontScale: config.tableFontScale || 1,
codeFontScale: config.codeFontScale || 1,
pageAlignments: config.pageAlignments || {}
},
content_html: saveConfig.content_html || postData.content_html