Upload useExport.ts
Browse files- frontend/src/hooks/useExport.ts +105 -39
frontend/src/hooks/useExport.ts
CHANGED
@@ -1156,12 +1156,20 @@ export default () => {
|
|
1156 |
continue;
|
1157 |
}
|
1158 |
|
1159 |
-
// 检查元素尺寸
|
1160 |
const dimensions = getElementDimensions(targetElement);
|
1161 |
console.log(`Target element dimensions for ${el.id}:`, dimensions);
|
1162 |
|
1163 |
-
|
1164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1165 |
console.log('Falling back to path-based export');
|
1166 |
// 降级处理代码...
|
1167 |
const scale = {
|
@@ -1204,52 +1212,111 @@ export default () => {
|
|
1204 |
continue;
|
1205 |
}
|
1206 |
|
1207 |
-
//
|
1208 |
let base64Image;
|
|
|
|
|
|
|
1209 |
try {
|
1210 |
-
console.log(`
|
1211 |
-
|
1212 |
-
// Canvas渲染选项
|
1213 |
-
const renderOptions = {
|
1214 |
-
scale: 2, // 高分辨率渲染
|
1215 |
-
backgroundColor: null, // 透明背景
|
1216 |
-
useCORS: true,
|
1217 |
-
timeout: 10000, // 10秒超时
|
1218 |
-
format: 'png' as const,
|
1219 |
-
quality: 0.95
|
1220 |
-
};
|
1221 |
|
1222 |
-
|
1223 |
-
|
1224 |
-
|
1225 |
-
|
1226 |
-
|
1227 |
-
|
1228 |
-
|
1229 |
-
|
1230 |
-
|
1231 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1232 |
}
|
1233 |
-
} catch (
|
1234 |
-
console.
|
1235 |
-
|
1236 |
-
|
1237 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1238 |
try {
|
|
|
|
|
1239 |
const svgElement = targetElement.tagName.toLowerCase() === 'svg'
|
1240 |
? targetElement
|
1241 |
: targetElement.querySelector('svg');
|
1242 |
|
1243 |
if (svgElement) {
|
1244 |
-
|
1245 |
-
|
1246 |
-
|
1247 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1248 |
}
|
1249 |
-
} catch (
|
1250 |
-
console.error(`SVG
|
1251 |
-
|
1252 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1253 |
const scale = {
|
1254 |
x: el.width / el.viewBox[0],
|
1255 |
y: el.height / el.viewBox[1],
|
@@ -1288,7 +1355,6 @@ export default () => {
|
|
1288 |
|
1289 |
pptxSlide.addShape('custGeom' as pptxgen.ShapeType, fallbackOptions);
|
1290 |
continue;
|
1291 |
-
}
|
1292 |
}
|
1293 |
|
1294 |
// 添加渲染后的图像到幻灯片
|
|
|
1156 |
continue;
|
1157 |
}
|
1158 |
|
1159 |
+
// 检查元素尺寸 - 使用更智能的检查逻辑
|
1160 |
const dimensions = getElementDimensions(targetElement);
|
1161 |
console.log(`Target element dimensions for ${el.id}:`, dimensions);
|
1162 |
|
1163 |
+
// 更宽松的尺寸检查:只要有任何一种尺寸测量方法返回有效值就继续
|
1164 |
+
const hasValidDimensions = (
|
1165 |
+
dimensions.width > 0 || dimensions.height > 0 ||
|
1166 |
+
dimensions.clientWidth > 0 || dimensions.clientHeight > 0 ||
|
1167 |
+
dimensions.offsetWidth > 0 || dimensions.offsetHeight > 0 ||
|
1168 |
+
dimensions.boundingRect.width > 0 || dimensions.boundingRect.height > 0
|
1169 |
+
);
|
1170 |
+
|
1171 |
+
if (!hasValidDimensions) {
|
1172 |
+
console.warn(`No valid dimensions found for shape ${el.id}:`, dimensions);
|
1173 |
console.log('Falling back to path-based export');
|
1174 |
// 降级处理代码...
|
1175 |
const scale = {
|
|
|
1212 |
continue;
|
1213 |
}
|
1214 |
|
1215 |
+
// 使用多重策略渲染矢量图形
|
1216 |
let base64Image;
|
1217 |
+
let renderSuccess = false;
|
1218 |
+
|
1219 |
+
// 策略1: 优先使用SVG序列化(对矢量图形更可靠)
|
1220 |
try {
|
1221 |
+
console.log(`Attempting SVG serialization for ${el.id}`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1222 |
|
1223 |
+
const svgElement = targetElement.tagName.toLowerCase() === 'svg'
|
1224 |
+
? targetElement
|
1225 |
+
: targetElement.querySelector('svg');
|
1226 |
+
|
1227 |
+
if (svgElement) {
|
1228 |
+
// 确保SVG元素已完全渲染
|
1229 |
+
await new Promise(resolve => {
|
1230 |
+
requestAnimationFrame(() => {
|
1231 |
+
requestAnimationFrame(resolve);
|
1232 |
+
});
|
1233 |
+
});
|
1234 |
+
|
1235 |
+
base64Image = svg2Base64(svgElement);
|
1236 |
+
|
1237 |
+
console.log(`SVG serialization result for ${el.id}:`, {
|
1238 |
+
success: !!base64Image,
|
1239 |
+
length: base64Image ? base64Image.length : 0,
|
1240 |
+
preview: base64Image ? base64Image.substring(0, 100) + '...' : 'null'
|
1241 |
+
});
|
1242 |
+
|
1243 |
+
if (base64Image && base64Image.length > 100) {
|
1244 |
+
renderSuccess = true;
|
1245 |
+
console.log(`SVG serialization successful for ${el.id}`);
|
1246 |
+
}
|
1247 |
}
|
1248 |
+
} catch (svgError) {
|
1249 |
+
console.warn(`SVG serialization failed for ${el.id}:`, svgError);
|
1250 |
+
}
|
1251 |
+
|
1252 |
+
// 策略2: 如果SVG序列化失败,使用Canvas渲染
|
1253 |
+
if (!renderSuccess) {
|
1254 |
+
try {
|
1255 |
+
console.log(`Attempting Canvas rendering for ${el.id}`);
|
1256 |
+
|
1257 |
+
// Canvas渲染选项
|
1258 |
+
const renderOptions = {
|
1259 |
+
scale: 2, // 高分辨率渲染
|
1260 |
+
backgroundColor: null, // 透明背景
|
1261 |
+
useCORS: true,
|
1262 |
+
timeout: 15000, // 增加超时时间
|
1263 |
+
format: 'png' as const,
|
1264 |
+
quality: 0.95
|
1265 |
+
};
|
1266 |
+
|
1267 |
+
base64Image = await renderElementToBase64(targetElement, renderOptions);
|
1268 |
+
|
1269 |
+
console.log(`Canvas rendering result for ${el.id}:`, {
|
1270 |
+
success: !!base64Image,
|
1271 |
+
length: base64Image ? base64Image.length : 0,
|
1272 |
+
preview: base64Image ? base64Image.substring(0, 100) + '...' : 'null'
|
1273 |
+
});
|
1274 |
+
|
1275 |
+
if (base64Image && base64Image.length > 100) {
|
1276 |
+
renderSuccess = true;
|
1277 |
+
console.log(`Canvas rendering successful for ${el.id}`);
|
1278 |
+
}
|
1279 |
+
} catch (canvasError) {
|
1280 |
+
console.error(`Canvas rendering failed for ${el.id}:`, canvasError);
|
1281 |
+
}
|
1282 |
+
}
|
1283 |
+
|
1284 |
+
// 策略3: 如果前两种方法都失败,尝试简化的SVG渲染
|
1285 |
+
if (!renderSuccess) {
|
1286 |
try {
|
1287 |
+
console.log(`Attempting simplified SVG rendering for ${el.id}`);
|
1288 |
+
|
1289 |
const svgElement = targetElement.tagName.toLowerCase() === 'svg'
|
1290 |
? targetElement
|
1291 |
: targetElement.querySelector('svg');
|
1292 |
|
1293 |
if (svgElement) {
|
1294 |
+
// 创建简化的SVG副本
|
1295 |
+
const simplifiedSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
1296 |
+
const rect = svgElement.getBoundingClientRect();
|
1297 |
+
|
1298 |
+
simplifiedSVG.setAttribute('width', (rect.width || 100).toString());
|
1299 |
+
simplifiedSVG.setAttribute('height', (rect.height || 100).toString());
|
1300 |
+
simplifiedSVG.setAttribute('viewBox', `0 0 ${rect.width || 100} ${rect.height || 100}`);
|
1301 |
+
simplifiedSVG.innerHTML = svgElement.innerHTML;
|
1302 |
+
|
1303 |
+
base64Image = svg2Base64(simplifiedSVG);
|
1304 |
+
|
1305 |
+
if (base64Image && base64Image.length > 100) {
|
1306 |
+
renderSuccess = true;
|
1307 |
+
console.log(`Simplified SVG rendering successful for ${el.id}`);
|
1308 |
+
}
|
1309 |
}
|
1310 |
+
} catch (simplifiedError) {
|
1311 |
+
console.error(`Simplified SVG rendering failed for ${el.id}:`, simplifiedError);
|
1312 |
+
}
|
1313 |
+
}
|
1314 |
+
|
1315 |
+
// 如果所有渲染策略都失败,使用路径导出作为最后备选
|
1316 |
+
if (!renderSuccess) {
|
1317 |
+
console.warn(`All rendering strategies failed for ${el.id}, falling back to path export`);
|
1318 |
+
// 最终降级到路径导出
|
1319 |
+
console.log(`Final fallback to path-based export for ${el.id}`);
|
1320 |
const scale = {
|
1321 |
x: el.width / el.viewBox[0],
|
1322 |
y: el.height / el.viewBox[1],
|
|
|
1355 |
|
1356 |
pptxSlide.addShape('custGeom' as pptxgen.ShapeType, fallbackOptions);
|
1357 |
continue;
|
|
|
1358 |
}
|
1359 |
|
1360 |
// 添加渲染后的图像到幻灯片
|