figma-restoration-tools
Version:
Professional Figma Component Restoration Kit - MCP tools with snapDOM-powered high-quality screenshots, intelligent shadow detection, and smart debugging for Vue component restoration. Includes figma_compare and snapdom_screenshot tools.
144 lines (121 loc) • 5.34 kB
JavaScript
import fs from 'fs';
import path from 'path';
import { PNG } from 'pngjs';
import pixelmatch from 'pixelmatch';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
async function generateDiffImage(expectedPath, actualPath, outputPath) {
try {
console.log('Loading images...');
// 读取图片文件
const expectedBuffer = fs.readFileSync(expectedPath);
const actualBuffer = fs.readFileSync(actualPath);
// 解析PNG
const expectedPng = PNG.sync.read(expectedBuffer);
const actualPng = PNG.sync.read(actualBuffer);
// 使用较小的尺寸进行比较
const width = Math.min(expectedPng.width, actualPng.width);
const height = Math.min(expectedPng.height, actualPng.height);
console.log(`Expected: ${expectedPng.width}x${expectedPng.height}`);
console.log(`Actual: ${actualPng.width}x${actualPng.height}`);
console.log(`Comparing: ${width}x${height}`);
// 创建输出图像
const diffPng = new PNG({ width, height });
// 生成差异图像
const numDiffPixels = pixelmatch(expectedPng.data, actualPng.data, diffPng.data, width, height, {
threshold: 0.1,
includeAA: false
});
// 保存差异图像
const buffer = PNG.sync.write(diffPng);
fs.writeFileSync(outputPath, buffer);
const matchPercentage = ((width * height - numDiffPixels) / (width * height) * 100).toFixed(2);
console.log(`Diff image saved to: ${outputPath}`);
console.log(`Match percentage: ${matchPercentage}%`);
console.log(`Different pixels: ${numDiffPixels}`);
return {
success: true,
matchPercentage: parseFloat(matchPercentage),
diffPixels: numDiffPixels,
dimensions: { width, height }
};
} catch (error) {
console.error('Error generating diff image:', error);
return { success: false, error: error.message };
}
}
// 处理所有组件
async function processAllComponents() {
const resultsDir = path.join(__dirname, '../results');
const publicResultsDir = path.join(__dirname, '../public/results');
const components = ['ModalRemoveMember', 'ExchangeSuccess', 'AssignmentComplete', 'ScanComplete'];
const results = {};
for (const component of components) {
const expectedPath = path.join(resultsDir, component, `${component}_expected.png`);
const actualPath = path.join(resultsDir, component, 'actual.png');
const diffPath = path.join(resultsDir, component, 'diff.png');
const publicDiffPath = path.join(publicResultsDir, component, 'diff.png');
if (fs.existsSync(expectedPath) && fs.existsSync(actualPath)) {
console.log(`Processing ${component}...`);
const result = await generateDiffImage(expectedPath, actualPath, diffPath);
if (result.success) {
// 复制到public目录
fs.copyFileSync(diffPath, publicDiffPath);
console.log(`✅ ${component} diff image generated`);
// 生成报告JSON
const reportData = {
componentName: component,
timestamp: new Date().toISOString(),
summary: {
matchPercentage: result.matchPercentage,
pixelMatch: result.diffPixels,
componentCreated: true,
componentRendered: true,
screenshotTaken: true,
comparisonAvailable: true,
files: {
component: `/mcp-vue-tools/src/components/${component}/index.vue`,
screenshot: `/results/${component}/actual.png`,
expected: `/results/${component}/expected.png`,
diff: `/results/${component}/diff.png`
},
urls: {
test: `http://localhost:83/component/${component}`,
figma: "https://www.figma.com/design/"
}
},
comparison: {
expectedDimensions: result.dimensions,
actualDimensions: result.dimensions,
diffDimensions: result.dimensions,
dimensionMismatch: false
},
steps: {
create: { success: true, message: "Component created successfully" },
render: { success: true, message: "Component rendered successfully" },
screenshot: { success: true, message: "Screenshot captured successfully" },
comparison: { success: true, message: `Image comparison completed with ${result.matchPercentage}% match` }
}
};
// 保存报告
const reportPath = path.join(publicResultsDir, component, 'report.json');
fs.writeFileSync(reportPath, JSON.stringify(reportData, null, 2));
results[component] = result;
} else {
console.log(`❌ ${component} diff image failed: ${result.error}`);
results[component] = result;
}
} else {
console.log(`⚠️ ${component} missing images`);
console.log(`Expected: ${fs.existsSync(expectedPath) ? '✓' : '✗'} ${expectedPath}`);
console.log(`Actual: ${fs.existsSync(actualPath) ? '✓' : '✗'} ${actualPath}`);
results[component] = { success: false, error: 'Missing images' };
}
}
return results;
}
if (import.meta.url === `file://${process.argv[1]}`) {
processAllComponents().catch(console.error);
}
export { generateDiffImage, processAllComponents };