feat(phone-image): 生成圖片SnapDOM截圖流程改造

- 新增captureDomPages(): 從右側DOM容器串行截圖
- 新增generateLongImageFromCanvases(): canvas拼接長圖
- saveImages()條件分支: useDomPreview走DOM截圖, 否則走舊路徑
- 截圖參數scale=2, backgroundColor=#ffffff
- 保留doCapturePages/capturePagesFromStaging作為備用
This commit is contained in:
augushong
2026-05-19 00:35:30 +08:00
parent 94039d026e
commit 8bb232a3f0

View File

@@ -1644,7 +1644,119 @@ var PhoneImageEngine = (function () {
} }
/** /**
* 将页面渲染到隐藏区域并高质量截图(用于保存 * 从右侧DOM分页容器截图DOM预览模式
* 串行截图每个 .dom-page-container避免并行导致内存溢出
* @param {Function} [onProgress] 进度回调 function(current, total)
* @returns {jQuery Deferred} resolves with canvas array
*/
function captureDomPages(onProgress) {
var deferred = $.Deferred();
var containers = document.querySelectorAll('#paginated-preview .dom-page-container');
if (!containers || containers.length === 0) {
deferred.reject('未找到DOM分页容器');
return deferred.promise();
}
var sizeConfig = config.sizes[config.size] || config.sizes.xiaohongshu;
var outputWidth = sizeConfig.width * 2; // scale=2
var outputHeight = sizeConfig.height * 2;
var totalPages = containers.length;
var canvases = [];
console.log('[PhoneImage] DOM截图开始共' + totalPages + '页');
PhoneImageLogPanel.log('DOM截图开始共' + totalPages + '页', 'info');
var idx = 0;
function captureNext() {
if (idx >= totalPages) {
console.log('[PhoneImage] DOM截图完成成功' + canvases.length + '/' + totalPages + '页');
PhoneImageLogPanel.log('DOM截图完成成功' + canvases.length + '/' + totalPages + '页', 'success');
deferred.resolve(canvases);
return;
}
// 进度显示
if (onProgress) onProgress(idx + 1, totalPages);
PhoneImageLogPanel.log('截图中 ' + (idx + 1) + '/' + totalPages, 'info');
try {
snapdom.toCanvas(containers[idx], {
scale: 2,
backgroundColor: '#ffffff'
}).then(function (canvas) {
// 确保尺寸正确
if (canvas.width !== outputWidth || canvas.height !== outputHeight) {
var resizedCanvas = document.createElement('canvas');
resizedCanvas.width = outputWidth;
resizedCanvas.height = outputHeight;
var ctx = resizedCanvas.getContext('2d');
ctx.drawImage(canvas, 0, 0, outputWidth, outputHeight);
canvas = resizedCanvas;
}
canvases.push(canvas);
idx++;
captureNext();
}).catch(function (err) {
console.error('[PhoneImage] 第' + (idx + 1) + '页截图失败:', err);
PhoneImageLogPanel.log('第' + (idx + 1) + '页截图失败: ' + err, 'error');
// 继续下一页
idx++;
captureNext();
});
} catch (e) {
console.error('[PhoneImage] 第' + (idx + 1) + '页截图异常:', e);
PhoneImageLogPanel.log('第' + (idx + 1) + '页截图异常: ' + e, 'error');
idx++;
captureNext();
}
}
captureNext();
return deferred.promise();
}
/**
* 将canvas数组拼接为长图base64
* @param {Array} canvases - canvas对象数组
* @returns {jQuery Deferred} resolves with base64 string or null
*/
function generateLongImageFromCanvases(canvases) {
var deferred = $.Deferred();
if (!canvases || canvases.length === 0) {
deferred.resolve(null);
return deferred.promise();
}
var maxWidth = 0;
var totalHeight = 0;
for (var i = 0; i < canvases.length; i++) {
totalHeight += canvases[i].height;
if (canvases[i].width > maxWidth) {
maxWidth = canvases[i].width;
}
}
var longCanvas = document.createElement('canvas');
longCanvas.width = maxWidth;
longCanvas.height = totalHeight;
var ctx = longCanvas.getContext('2d');
var y = 0;
for (var j = 0; j < canvases.length; j++) {
ctx.drawImage(canvases[j], 0, y);
y += canvases[j].height;
}
deferred.resolve(longCanvas.toDataURL('image/jpeg', 0.85));
return deferred.promise();
}
/**
* 将页面渲染到隐藏区域并高质量截图(用于保存,旧流程备用)
* @returns {jQuery Deferred} resolves with canvas array * @returns {jQuery Deferred} resolves with canvas array
*/ */
function capturePagesFromStaging() { function capturePagesFromStaging() {
@@ -1695,15 +1807,32 @@ var PhoneImageEngine = (function () {
var deferred = $.Deferred(); var deferred = $.Deferred();
// 第一步:生成分页图片和长图 // 第一步:生成分页图片和长图
capturePagesFromStaging().then(function (canvases) { // DOM预览模式直接从右侧DOM容器截图旧模式从隐藏渲染区截图
var capturePromise;
if (config.useDomPreview) {
capturePromise = captureDomPages(function (current, total) {
if (onProgress) onProgress(current, total, null);
});
} else {
capturePromise = capturePagesFromStaging();
}
capturePromise.then(function (canvases) {
if (onProgress) onProgress(canvases.length, canvases.length, null); if (onProgress) onProgress(canvases.length, canvases.length, null);
var pagesData = []; var pagesData = [];
for (var i = 0; i < canvases.length; i++) { for (var i = 0; i < canvases.length; i++) {
pagesData.push(canvases[i].toDataURL('image/jpeg', 0.92)); pagesData.push(canvases[i].toDataURL('image/jpeg', 0.92));
} }
// 第二步:生成长图 // 第二步:生成长图DOM模式用canvas拼接旧模式用编辑器DOM截图
return generateLongImageBase64().then(function(longBase64) { var longImagePromise;
if (config.useDomPreview) {
longImagePromise = generateLongImageFromCanvases(canvases);
} else {
longImagePromise = generateLongImageBase64();
}
return longImagePromise.then(function(longBase64) {
return { pages: pagesData, longImage: longBase64 }; return { pages: pagesData, longImage: longBase64 };
}); });
}).then(function(result) { }).then(function(result) {