
在 PGFPlotsEdt 视频 的 结尾 处通过一个延时影像序列展示了 PGFPlotsEdt 四年来的前端变迁,该段序列大概包含了 400 张图像(双语版本总共 800 张图像),如果一个一个版本去截图,不仅效率很慢,而且可能会导致截图区域前后不一致。此处展示了这段序列是如何通过自动化方法生成的。
包配置
首先安装 Node.js,然后在项目文件夹中写入下面的 package.json
配置文件:
{
"name": "git-screenshot-webpage",
"version": "1.0.0",
"description": "Get the screenshot sequence of a git repository.",
"main": "screenshot.js",
"scripts": {
"start": "node screenshot.js",
"git-txt": "node git-history.js"
},
"author": "Log Creative",
"license": "MIT",
"dependencies": {
"live-server": "^1.2.2",
"puppeteer": "^22.12.1"
}
}
然后通过 npm install
安装 live-sever
和 puppeteer
包:
live-server
用来为前端项目建立开发服务器,能够通过检测文件变化自动更新前端页面,非常适合本文需要文件更新的场景。- puppeteer 提供浏览器的高层次 API,其中包含了对网页截图导出的 API,也被用于自动化测试及 Mermaid 图导出。
接着在该项目文件夹下克隆项目存储库备用,比如本文中的 PGFPlotsEdt
,注意不能是从 Download ZIP 下载的文件夹,必须要包含 git 记录。
截图导出
建立下面的 screenshot.js
,运行后主要进行下面的操作:
- 启动
live-server
,其他线程/进程可以通过http://127.0.0.1:5500/
访问当前项目存储库的前端网页(默认根网页产生于index.html
)。 - 启动
puppeteer
浏览器,建立合适的视口尺寸(此处 1280x720)。 - 通过 git 命令行,签出最新版本后,对每个版本从后向前遍历:
- 进行版本号更新操作(如有);
- 计算到此为止的提交数目;
- 通过
puppeteer
打开网页,并等待网络资源加载完毕,此处还添加了额外的等待时间保证网页已经稳定不再变化; - 截图并存储到文件,文件名后缀为按照补全前置零的提交数目,以下划线(
_
)分隔主序列名和图像编号,用于后续导入到 After Effects。
- 关闭
live-server
和puppeteer
实例。
const puppeteer = require('puppeteer');
const fs = require('fs');
const { execSync } = require('child_process');
const liveServer = require('live-server');
const { error } = require('console');
// Your screenshot folder to save.
const screenFolder = 'screenshots';
if (fs.existsSync(screenFolder))
fs.rmSync(screenFolder, {recursive: true, force: true});
fs.mkdirSync(screenFolder);
// The port of live-server.
const PORT = 5500
// Start the live-server first
liveServer.start({
root: 'PGFPlotsEdt',
open: false,
logLevel: 0,
port: PORT,
});
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
};
async function run() {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({width: 1280, height: 720});
let version = 1000;
let filename;
execSync('git checkout master', { cwd: 'PGFPlotsEdt' });
while(version > 1) {
try{ execSync('python version_updater.py', { cwd: 'PGFPlotsEdt/res' }); } catch (error) {}
version = parseInt(execSync("git rev-list HEAD --count", { cwd: 'PGFPlotsEdt' }).toString().trim());
filename = "pgfplotsedt_" + version.toString().padStart(3, '0');
await page.goto(`http://127.0.0.1:${PORT}/`, {waitUntil: 'networkidle2'});
await timeout(1000); // Wait for 1 seconds to ensure the server is up and running
await page.screenshot({path: `${screenFolder}/${filename}.png`});
try {execSync('git checkout HEAD^', { cwd: 'PGFPlotsEdt' });} catch (error) {}
}
browser.close();
liveServer.shutdown(); // Shutdown live-server after taking the screenshot
}
run();
之后在命令行中通过 npm run start
运行该脚本。
历史信息导出
历史信息通过建立下面的 git-history.js
文件实现,实际上也可以通过命令行脚本,此处统一起见皆写为 JavaScript 脚本。
const { execSync } = require('child_process');
const fs = require('fs');
// The commit details
result = execSync('git log --oneline --reverse', { cwd: 'PGFPlotsEdt' });
fs.writeFileSync('git-history.txt', result.toString());
// the time of every commit
result = execSync('git log --pretty=format:"%ad" --date=short --reverse', { cwd: 'PGFPlotsEdt' });
fs.writeFileSync('git-time.txt', result.toString());
之后在命令行中通过 npm run git-txt
运行该脚本。
导入 After Effects
After Effects 可以通过 JavaScript API 来程式化地合成动画,此处使用了下面的步骤:
- 将
screenshot/
文件夹中的图像序列导入;生成的历史文件git-history.txt
和git-time.txt
也导入项目。 - 从图像序列新建合成。
- 在画面左下角建立版本号文字对象,对“源文本”建立下面的表达式:
"v" + (timeToFrames()+1)/100
- 在画面右下角建立版本日期文字对象,对“源文本”建立下面的表达式:
footage("git-time.txt").sourceText.split('\n')[timeToFrames()]
- 在画面右下角继续建立版本提交描述文字对象,对“源文本”建立下面的表达式:
footage("git-history.txt").sourceText.split('\n')[timeToFrames()]
之后可以通过动态链接功能将 After Effects 合成导入 Premiere Pro 项目中。注意如果 Premiere Pro 没有正确显示文字内容,可以通过同时打开 After Effects 项目来解决这个问题。