CatPtain commited on
Commit
e554064
·
verified ·
1 Parent(s): 8ba8019

Upload 2 files

Browse files
Files changed (1) hide show
  1. test-huggingface-vector-fix.html +711 -0
test-huggingface-vector-fix.html ADDED
@@ -0,0 +1,711 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Huggingface环境矢量图形修复测试</title>
7
+ <style>
8
+ body {
9
+ font-family: 'Microsoft YaHei', Arial, sans-serif;
10
+ margin: 0;
11
+ padding: 20px;
12
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
13
+ color: #333;
14
+ min-height: 100vh;
15
+ }
16
+
17
+ .container {
18
+ max-width: 1200px;
19
+ margin: 0 auto;
20
+ background: white;
21
+ border-radius: 15px;
22
+ box-shadow: 0 20px 40px rgba(0,0,0,0.1);
23
+ overflow: hidden;
24
+ }
25
+
26
+ .header {
27
+ background: linear-gradient(135deg, #ff6b6b, #ee5a24);
28
+ color: white;
29
+ padding: 30px;
30
+ text-align: center;
31
+ }
32
+
33
+ .header h1 {
34
+ margin: 0;
35
+ font-size: 2.5em;
36
+ font-weight: 300;
37
+ }
38
+
39
+ .header p {
40
+ margin: 10px 0 0 0;
41
+ opacity: 0.9;
42
+ font-size: 1.1em;
43
+ }
44
+
45
+ .content {
46
+ padding: 40px;
47
+ }
48
+
49
+ .section {
50
+ margin-bottom: 40px;
51
+ padding: 25px;
52
+ border: 2px solid #f0f0f0;
53
+ border-radius: 10px;
54
+ background: #fafafa;
55
+ }
56
+
57
+ .section h2 {
58
+ color: #2c3e50;
59
+ margin-top: 0;
60
+ border-bottom: 3px solid #3498db;
61
+ padding-bottom: 10px;
62
+ }
63
+
64
+ .test-area {
65
+ display: flex;
66
+ gap: 20px;
67
+ flex-wrap: wrap;
68
+ margin: 20px 0;
69
+ }
70
+
71
+ .svg-container {
72
+ flex: 1;
73
+ min-width: 200px;
74
+ padding: 20px;
75
+ border: 2px dashed #ddd;
76
+ border-radius: 8px;
77
+ text-align: center;
78
+ background: white;
79
+ }
80
+
81
+ .svg-container h3 {
82
+ margin-top: 0;
83
+ color: #34495e;
84
+ }
85
+
86
+ .test-svg {
87
+ margin: 10px;
88
+ border: 1px solid #eee;
89
+ }
90
+
91
+ .controls {
92
+ margin: 20px 0;
93
+ text-align: center;
94
+ }
95
+
96
+ .btn {
97
+ background: linear-gradient(135deg, #667eea, #764ba2);
98
+ color: white;
99
+ border: none;
100
+ padding: 12px 25px;
101
+ margin: 5px;
102
+ border-radius: 25px;
103
+ cursor: pointer;
104
+ font-size: 16px;
105
+ transition: all 0.3s ease;
106
+ box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
107
+ }
108
+
109
+ .btn:hover {
110
+ transform: translateY(-2px);
111
+ box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
112
+ }
113
+
114
+ .btn:active {
115
+ transform: translateY(0);
116
+ }
117
+
118
+ .btn.success {
119
+ background: linear-gradient(135deg, #00b894, #00a085);
120
+ }
121
+
122
+ .btn.warning {
123
+ background: linear-gradient(135deg, #fdcb6e, #e17055);
124
+ }
125
+
126
+ .btn.danger {
127
+ background: linear-gradient(135deg, #fd79a8, #e84393);
128
+ }
129
+
130
+ .results {
131
+ margin-top: 20px;
132
+ padding: 20px;
133
+ background: #f8f9fa;
134
+ border-radius: 8px;
135
+ border-left: 4px solid #007bff;
136
+ }
137
+
138
+ .log {
139
+ background: #2c3e50;
140
+ color: #ecf0f1;
141
+ padding: 15px;
142
+ border-radius: 8px;
143
+ font-family: 'Courier New', monospace;
144
+ font-size: 14px;
145
+ max-height: 300px;
146
+ overflow-y: auto;
147
+ white-space: pre-wrap;
148
+ margin-top: 15px;
149
+ }
150
+
151
+ .environment-info {
152
+ background: linear-gradient(135deg, #74b9ff, #0984e3);
153
+ color: white;
154
+ padding: 20px;
155
+ border-radius: 10px;
156
+ margin-bottom: 20px;
157
+ }
158
+
159
+ .environment-info h3 {
160
+ margin-top: 0;
161
+ }
162
+
163
+ .fix-list {
164
+ background: #d4edda;
165
+ border: 1px solid #c3e6cb;
166
+ border-radius: 8px;
167
+ padding: 20px;
168
+ margin: 20px 0;
169
+ }
170
+
171
+ .fix-item {
172
+ margin: 8px 0;
173
+ padding: 8px 12px;
174
+ background: white;
175
+ border-radius: 5px;
176
+ border-left: 4px solid #28a745;
177
+ }
178
+
179
+ .preview-container {
180
+ display: flex;
181
+ gap: 20px;
182
+ margin-top: 20px;
183
+ flex-wrap: wrap;
184
+ }
185
+
186
+ .preview-item {
187
+ flex: 1;
188
+ min-width: 300px;
189
+ padding: 15px;
190
+ border: 1px solid #ddd;
191
+ border-radius: 8px;
192
+ background: white;
193
+ }
194
+
195
+ .preview-item h4 {
196
+ margin-top: 0;
197
+ color: #495057;
198
+ }
199
+
200
+ .preview-image {
201
+ max-width: 100%;
202
+ border: 1px solid #eee;
203
+ border-radius: 4px;
204
+ }
205
+
206
+ .status {
207
+ display: inline-block;
208
+ padding: 4px 8px;
209
+ border-radius: 12px;
210
+ font-size: 12px;
211
+ font-weight: bold;
212
+ margin-left: 10px;
213
+ }
214
+
215
+ .status.success {
216
+ background: #d4edda;
217
+ color: #155724;
218
+ }
219
+
220
+ .status.error {
221
+ background: #f8d7da;
222
+ color: #721c24;
223
+ }
224
+
225
+ .status.warning {
226
+ background: #fff3cd;
227
+ color: #856404;
228
+ }
229
+ </style>
230
+ </head>
231
+ <body>
232
+ <div class="container">
233
+ <div class="header">
234
+ <h1>🚀 Huggingface环境矢量图形修复测试</h1>
235
+ <p>专门针对Huggingface Spaces部署环境的矢量图形渲染优化</p>
236
+ </div>
237
+
238
+ <div class="content">
239
+ <!-- 环境信息 -->
240
+ <div class="environment-info">
241
+ <h3>🌐 环境检测</h3>
242
+ <div id="environment-status">正在检测环境...</div>
243
+ </div>
244
+
245
+ <!-- 修复说明 -->
246
+ <div class="section">
247
+ <h2>🔧 Huggingface环境修复措施</h2>
248
+ <div class="fix-list">
249
+ <div class="fix-item">✅ 禁用CORS检查,使用allowTaint模式</div>
250
+ <div class="fix-item">✅ 优化html2canvas配置,适配Docker Alpine环境</div>
251
+ <div class="fix-item">✅ 简化SVG序列化,移除problematic属性</div>
252
+ <div class="fix-item">✅ 使用btoa编码替代复杂的Base64实现</div>
253
+ <div class="fix-item">✅ 添加多级回退机制,确保渲染成功</div>
254
+ <div class="fix-item">✅ 针对Chromium浏览器优化SVG处理</div>
255
+ <div class="fix-item">✅ 禁用foreignObject渲染,避免跨域问题</div>
256
+ </div>
257
+ </div>
258
+
259
+ <!-- 测试SVG图形 -->
260
+ <div class="section">
261
+ <h2>🎨 测试SVG图形</h2>
262
+ <div class="test-area">
263
+ <div class="svg-container">
264
+ <h3>几何图形</h3>
265
+ <svg class="test-svg" width="150" height="100" id="svg1">
266
+ <rect x="10" y="10" width="60" height="40" fill="#ff6b6b" stroke="#c0392b" stroke-width="2"/>
267
+ <circle cx="100" cy="30" r="20" fill="#3498db" stroke="#2980b9" stroke-width="2"/>
268
+ <polygon points="80,60 100,80 120,60 110,90 90,90" fill="#2ecc71" stroke="#27ae60" stroke-width="2"/>
269
+ </svg>
270
+ </div>
271
+
272
+ <div class="svg-container">
273
+ <h3>路径图形</h3>
274
+ <svg class="test-svg" width="150" height="100" id="svg2">
275
+ <path d="M20,50 Q40,20 60,50 T100,50" stroke="#9b59b6" stroke-width="3" fill="none"/>
276
+ <path d="M10,80 L50,60 L90,80 L130,60" stroke="#f39c12" stroke-width="2" fill="none"/>
277
+ <ellipse cx="75" cy="30" rx="30" ry="15" fill="#e74c3c" opacity="0.7"/>
278
+ </svg>
279
+ </div>
280
+
281
+ <div class="svg-container">
282
+ <h3>文本图形</h3>
283
+ <svg class="test-svg" width="150" height="100" id="svg3">
284
+ <rect width="100%" height="100%" fill="#ecf0f1"/>
285
+ <text x="75" y="30" text-anchor="middle" font-family="Arial" font-size="14" fill="#2c3e50">SVG文本</text>
286
+ <text x="75" y="50" text-anchor="middle" font-family="Arial" font-size="12" fill="#7f8c8d">Huggingface</text>
287
+ <text x="75" y="70" text-anchor="middle" font-family="Arial" font-size="10" fill="#95a5a6">优化测试</text>
288
+ </svg>
289
+ </div>
290
+
291
+ <div class="svg-container">
292
+ <h3>复杂图形</h3>
293
+ <svg class="test-svg" width="150" height="100" id="svg4">
294
+ <defs>
295
+ <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
296
+ <stop offset="0%" style="stop-color:#667eea;stop-opacity:1" />
297
+ <stop offset="100%" style="stop-color:#764ba2;stop-opacity:1" />
298
+ </linearGradient>
299
+ </defs>
300
+ <rect width="100%" height="100%" fill="url(#grad1)"/>
301
+ <circle cx="75" cy="50" r="30" fill="white" opacity="0.8"/>
302
+ <text x="75" y="55" text-anchor="middle" font-family="Arial" font-size="16" fill="#333">HF</text>
303
+ </svg>
304
+ </div>
305
+ </div>
306
+ </div>
307
+
308
+ <!-- 测试控制 -->
309
+ <div class="section">
310
+ <h2>🧪 测试控制</h2>
311
+ <div class="controls">
312
+ <button class="btn" onclick="testEnvironmentDetection()">检测环境</button>
313
+ <button class="btn success" onclick="testSvgConversion()">测试SVG转换</button>
314
+ <button class="btn warning" onclick="testHuggingfaceRenderer()">测试HF渲染器</button>
315
+ <button class="btn danger" onclick="testExportFunction()">测试导出功能</button>
316
+ <button class="btn" onclick="clearResults()">清除结果</button>
317
+ </div>
318
+ </div>
319
+
320
+ <!-- 测试结果 -->
321
+ <div class="section">
322
+ <h2>📊 测试结果</h2>
323
+ <div id="test-results" class="results">
324
+ <p>点击上方按钮开始测试...</p>
325
+ </div>
326
+
327
+ <!-- 预览区域 -->
328
+ <div class="preview-container" id="preview-container" style="display: none;">
329
+ <div class="preview-item">
330
+ <h4>原始SVG</h4>
331
+ <div id="original-svg"></div>
332
+ </div>
333
+ <div class="preview-item">
334
+ <h4>转换结果</h4>
335
+ <div id="converted-result"></div>
336
+ </div>
337
+ </div>
338
+
339
+ <!-- 日志区域 -->
340
+ <div class="log" id="log-area"></div>
341
+ </div>
342
+ </div>
343
+ </div>
344
+
345
+ <script>
346
+ // 模拟Huggingface环境检测
347
+ function isHuggingfaceEnvironment() {
348
+ return (
349
+ window.location.hostname.includes('hf.space') ||
350
+ window.location.hostname.includes('huggingface.co') ||
351
+ window.location.hostname.includes('localhost') || // 本地测试
352
+ window.location.hostname.includes('127.0.0.1')
353
+ );
354
+ }
355
+
356
+ // 日志函数
357
+ function log(message, type = 'info') {
358
+ const logArea = document.getElementById('log-area');
359
+ const timestamp = new Date().toLocaleTimeString();
360
+ const logEntry = `[${timestamp}] ${type.toUpperCase()}: ${message}\n`;
361
+ logArea.textContent += logEntry;
362
+ logArea.scrollTop = logArea.scrollHeight;
363
+ console.log(logEntry);
364
+ }
365
+
366
+ // 更新结果显示
367
+ function updateResults(content) {
368
+ document.getElementById('test-results').innerHTML = content;
369
+ }
370
+
371
+ // 清除结果
372
+ function clearResults() {
373
+ document.getElementById('test-results').innerHTML = '<p>结果已清除,点击测试按钮开始新的测试...</p>';
374
+ document.getElementById('log-area').textContent = '';
375
+ document.getElementById('preview-container').style.display = 'none';
376
+ }
377
+
378
+ // 测试环境检测
379
+ function testEnvironmentDetection() {
380
+ log('开始环境检测测试');
381
+
382
+ const isHF = isHuggingfaceEnvironment();
383
+ const userAgent = navigator.userAgent;
384
+ const hostname = window.location.hostname;
385
+
386
+ const envInfo = {
387
+ isHuggingface: isHF,
388
+ hostname: hostname,
389
+ userAgent: userAgent,
390
+ isChromium: userAgent.includes('Chrome'),
391
+ isDocker: userAgent.includes('HeadlessChrome'),
392
+ viewport: `${window.innerWidth}x${window.innerHeight}`
393
+ };
394
+
395
+ log(`环境检测结果: ${JSON.stringify(envInfo, null, 2)}`);
396
+
397
+ const statusHtml = `
398
+ <h3>环境检测结果</h3>
399
+ <p><strong>Huggingface环境:</strong> <span class="status ${isHF ? 'success' : 'warning'}">${isHF ? '是' : '否'}</span></p>
400
+ <p><strong>主机名:</strong> ${hostname}</p>
401
+ <p><strong>浏览器:</strong> ${envInfo.isChromium ? 'Chromium/Chrome' : '其他'}</p>
402
+ <p><strong>Docker环境:</strong> ${envInfo.isDocker ? '是' : '否'}</p>
403
+ <p><strong>视口尺寸:</strong> ${envInfo.viewport}</p>
404
+ `;
405
+
406
+ updateResults(statusHtml);
407
+
408
+ // 更新环境状态显示
409
+ document.getElementById('environment-status').innerHTML = `
410
+ <strong>当前环境:</strong> ${isHF ? 'Huggingface Spaces' : '本地开发'}
411
+ <span class="status ${isHF ? 'success' : 'warning'}">${isHF ? 'HF环境' : '本地环境'}</span>
412
+ `;
413
+ }
414
+
415
+ // 模拟Huggingface优化的SVG转Base64
416
+ function huggingfaceOptimizedSvg2Base64(element) {
417
+ try {
418
+ log('开始Huggingface优化的SVG转换');
419
+
420
+ const clonedElement = element.cloneNode(true);
421
+
422
+ if (clonedElement.tagName.toLowerCase() === 'svg') {
423
+ const svgElement = clonedElement;
424
+
425
+ // 设置基本属性
426
+ svgElement.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
427
+
428
+ // 获取尺寸
429
+ const rect = element.getBoundingClientRect();
430
+ const width = rect.width || 100;
431
+ const height = rect.height || 100;
432
+
433
+ // 设置明确的尺寸
434
+ svgElement.setAttribute('width', width.toString());
435
+ svgElement.setAttribute('height', height.toString());
436
+ svgElement.setAttribute('viewBox', `0 0 ${width} ${height}`);
437
+
438
+ // 移除问题属性
439
+ const removeProblematicAttrs = (elem) => {
440
+ const problematicAttrs = ['vector-effect', 'xmlns:xlink'];
441
+ problematicAttrs.forEach(attr => {
442
+ if (elem.hasAttribute && elem.hasAttribute(attr)) {
443
+ elem.removeAttribute(attr);
444
+ }
445
+ });
446
+
447
+ if (elem.children) {
448
+ Array.from(elem.children).forEach(child => {
449
+ removeProblematicAttrs(child);
450
+ });
451
+ }
452
+ };
453
+
454
+ removeProblematicAttrs(svgElement);
455
+
456
+ // 序列化
457
+ let svgString = svgElement.outerHTML;
458
+
459
+ // 清理
460
+ svgString = svgString.replace(/vector-effect="[^"]*"/g, '');
461
+ svgString = svgString.replace(/xmlns:xlink="[^"]*"/g, '');
462
+
463
+ // 确保命名空间
464
+ if (!svgString.includes('xmlns="http://www.w3.org/2000/svg"')) {
465
+ svgString = svgString.replace('<svg', '<svg xmlns="http://www.w3.org/2000/svg"');
466
+ }
467
+
468
+ log(`SVG字符串准备完成: 长度=${svgString.length}`);
469
+
470
+ // 编码
471
+ const base64 = btoa(unescape(encodeURIComponent(svgString)));
472
+ const result = `data:image/svg+xml;base64,${base64}`;
473
+
474
+ log('SVG转换成功');
475
+ return result;
476
+ }
477
+
478
+ throw new Error('不是SVG元素');
479
+
480
+ } catch (error) {
481
+ log(`SVG转换失败: ${error.message}`, 'error');
482
+
483
+ // 备选方案
484
+ const rect = element.getBoundingClientRect();
485
+ const width = rect.width || 100;
486
+ const height = rect.height || 100;
487
+
488
+ const placeholderSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
489
+ <rect width="100%" height="100%" fill="#f5f5f5" stroke="#ddd" stroke-width="1"/>
490
+ <text x="50%" y="50%" text-anchor="middle" dy="0.3em" font-family="Arial, sans-serif" font-size="14" fill="#999">SVG</text>
491
+ </svg>`;
492
+
493
+ const base64 = btoa(unescape(encodeURIComponent(placeholderSvg)));
494
+ log('使用占位符SVG');
495
+ return `data:image/svg+xml;base64,${base64}`;
496
+ }
497
+ }
498
+
499
+ // 测试SVG转换
500
+ function testSvgConversion() {
501
+ log('开始SVG转换测试');
502
+
503
+ const svgElements = document.querySelectorAll('.test-svg');
504
+ let successCount = 0;
505
+ let totalCount = svgElements.length;
506
+ const results = [];
507
+
508
+ svgElements.forEach((svg, index) => {
509
+ try {
510
+ const startTime = performance.now();
511
+ const base64Result = huggingfaceOptimizedSvg2Base64(svg);
512
+ const endTime = performance.now();
513
+ const duration = (endTime - startTime).toFixed(2);
514
+
515
+ if (base64Result && base64Result.length > 100) {
516
+ successCount++;
517
+ results.push({
518
+ id: svg.id,
519
+ status: 'success',
520
+ duration: duration,
521
+ size: base64Result.length,
522
+ preview: base64Result.substring(0, 100) + '...'
523
+ });
524
+ log(`SVG ${svg.id} 转换成功: ${duration}ms, 大小=${base64Result.length}`);
525
+ } else {
526
+ results.push({
527
+ id: svg.id,
528
+ status: 'error',
529
+ error: '转换结果无效'
530
+ });
531
+ log(`SVG ${svg.id} 转换失败: 结果无效`, 'error');
532
+ }
533
+ } catch (error) {
534
+ results.push({
535
+ id: svg.id,
536
+ status: 'error',
537
+ error: error.message
538
+ });
539
+ log(`SVG ${svg.id} 转换失败: ${error.message}`, 'error');
540
+ }
541
+ });
542
+
543
+ const successRate = ((successCount / totalCount) * 100).toFixed(1);
544
+
545
+ let resultHtml = `
546
+ <h3>SVG转换测试结果</h3>
547
+ <p><strong>成功率:</strong> ${successRate}% (${successCount}/${totalCount})</p>
548
+ <div style="margin-top: 15px;">
549
+ `;
550
+
551
+ results.forEach(result => {
552
+ const statusClass = result.status === 'success' ? 'success' : 'error';
553
+ resultHtml += `
554
+ <div style="margin: 10px 0; padding: 10px; border: 1px solid #ddd; border-radius: 5px;">
555
+ <strong>${result.id}:</strong>
556
+ <span class="status ${statusClass}">${result.status}</span>
557
+ ${result.duration ? `<br>耗时: ${result.duration}ms` : ''}
558
+ ${result.size ? `<br>大小: ${result.size} 字符` : ''}
559
+ ${result.error ? `<br>错误: ${result.error}` : ''}
560
+ </div>
561
+ `;
562
+ });
563
+
564
+ resultHtml += '</div>';
565
+ updateResults(resultHtml);
566
+
567
+ log(`SVG转换测试完成: 成功率=${successRate}%`);
568
+ }
569
+
570
+ // 测试Huggingface渲染器
571
+ function testHuggingfaceRenderer() {
572
+ log('开始Huggingface渲染器测试');
573
+
574
+ const isHF = isHuggingfaceEnvironment();
575
+
576
+ // 模拟渲染配置
577
+ const config = {
578
+ useCORS: false,
579
+ allowTaint: true,
580
+ foreignObjectRendering: false,
581
+ scale: isHF ? 1 : 2,
582
+ logging: false,
583
+ timeout: 30000
584
+ };
585
+
586
+ log(`渲染配置: ${JSON.stringify(config, null, 2)}`);
587
+
588
+ // 测试每个SVG元素
589
+ const svgElements = document.querySelectorAll('.test-svg');
590
+ const testResults = [];
591
+
592
+ svgElements.forEach((svg, index) => {
593
+ try {
594
+ const rect = svg.getBoundingClientRect();
595
+ const hasValidDimensions = rect.width > 0 && rect.height > 0;
596
+
597
+ testResults.push({
598
+ id: svg.id,
599
+ dimensions: `${rect.width}x${rect.height}`,
600
+ hasValidDimensions,
601
+ childCount: svg.children.length,
602
+ status: hasValidDimensions ? 'ready' : 'warning'
603
+ });
604
+
605
+ log(`${svg.id}: 尺寸=${rect.width}x${rect.height}, 子元素=${svg.children.length}`);
606
+ } catch (error) {
607
+ testResults.push({
608
+ id: svg.id,
609
+ status: 'error',
610
+ error: error.message
611
+ });
612
+ log(`${svg.id}: 检查失败 - ${error.message}`, 'error');
613
+ }
614
+ });
615
+
616
+ let resultHtml = `
617
+ <h3>Huggingface渲染器测试</h3>
618
+ <p><strong>环境:</strong> ${isHF ? 'Huggingface Spaces' : '本地环境'}</p>
619
+ <p><strong>配置:</strong> CORS=${config.useCORS}, AllowTaint=${config.allowTaint}, Scale=${config.scale}</p>
620
+ <div style="margin-top: 15px;">
621
+ `;
622
+
623
+ testResults.forEach(result => {
624
+ const statusClass = result.status === 'ready' ? 'success' :
625
+ result.status === 'warning' ? 'warning' : 'error';
626
+ resultHtml += `
627
+ <div style="margin: 10px 0; padding: 10px; border: 1px solid #ddd; border-radius: 5px;">
628
+ <strong>${result.id}:</strong>
629
+ <span class="status ${statusClass}">${result.status}</span>
630
+ ${result.dimensions ? `<br>尺寸: ${result.dimensions}` : ''}
631
+ ${result.childCount !== undefined ? `<br>子元素: ${result.childCount}` : ''}
632
+ ${result.error ? `<br>错误: ${result.error}` : ''}
633
+ </div>
634
+ `;
635
+ });
636
+
637
+ resultHtml += '</div>';
638
+ updateResults(resultHtml);
639
+
640
+ log('Huggingface渲染器测试完成');
641
+ }
642
+
643
+ // 测试导出功能
644
+ function testExportFunction() {
645
+ log('开始导出功能测试');
646
+
647
+ const testSvg = document.getElementById('svg1');
648
+ if (!testSvg) {
649
+ log('找不到测试SVG元素', 'error');
650
+ return;
651
+ }
652
+
653
+ try {
654
+ // 显示预览区域
655
+ document.getElementById('preview-container').style.display = 'flex';
656
+
657
+ // 显示原始SVG
658
+ const originalContainer = document.getElementById('original-svg');
659
+ const svgClone = testSvg.cloneNode(true);
660
+ originalContainer.innerHTML = '';
661
+ originalContainer.appendChild(svgClone);
662
+
663
+ // 转换SVG
664
+ const base64Result = huggingfaceOptimizedSvg2Base64(testSvg);
665
+
666
+ // 显示转换结果
667
+ const resultContainer = document.getElementById('converted-result');
668
+ const img = document.createElement('img');
669
+ img.src = base64Result;
670
+ img.className = 'preview-image';
671
+ img.onload = () => {
672
+ log('转换结果图片加载成功');
673
+ };
674
+ img.onerror = () => {
675
+ log('转换结果图片加载失败', 'error');
676
+ };
677
+
678
+ resultContainer.innerHTML = '';
679
+ resultContainer.appendChild(img);
680
+
681
+ const resultHtml = `
682
+ <h3>导出功能测试结果</h3>
683
+ <p><strong>状态:</strong> <span class="status success">成功</span></p>
684
+ <p><strong>Base64长度:</strong> ${base64Result.length} 字符</p>
685
+ <p><strong>数据类型:</strong> ${base64Result.substring(0, 30)}...</p>
686
+ <p>请查看下方预览区域对比原始SVG和转换结果。</p>
687
+ `;
688
+
689
+ updateResults(resultHtml);
690
+ log('导出功能测试完成');
691
+
692
+ } catch (error) {
693
+ const resultHtml = `
694
+ <h3>导出功能测试结果</h3>
695
+ <p><strong>状态:</strong> <span class="status error">失败</span></p>
696
+ <p><strong>错误:</strong> ${error.message}</p>
697
+ `;
698
+
699
+ updateResults(resultHtml);
700
+ log(`导出功能测试失败: ${error.message}`, 'error');
701
+ }
702
+ }
703
+
704
+ // 页面加载完成后自动检测环境
705
+ window.addEventListener('load', () => {
706
+ log('页面加载完成,开始初始化');
707
+ testEnvironmentDetection();
708
+ });
709
+ </script>
710
+ </body>
711
+ </html>