完成 netlist 保存为 svg & pdf

This commit is contained in:
锦恢 2025-01-04 15:14:06 +08:00
parent 0d7b5acf03
commit dda754830e
7 changed files with 79 additions and 30 deletions

View File

@ -106,5 +106,9 @@
"info.command.structure.reload-vscode": "Vscode neu starten", "info.command.structure.reload-vscode": "Vscode neu starten",
"error.look-up-log": "Fehlerprotokoll anzeigen", "error.look-up-log": "Fehlerprotokoll anzeigen",
"netlist.save-as-svg": "Als SVG speichern", "netlist.save-as-svg": "Als SVG speichern",
"svg-file": "SVG-Datei" "svg-file": "SVG-Datei",
"toolbar.save-as-svg": "Aktuelle Ansicht als SVG speichern",
"toolbar.save-as-pdf": "Aktuelle Ansicht als PDF speichern",
"pdf-file": "PDF-Datei",
"export-pdf": "PDF wird exportiert"
} }

View File

@ -106,5 +106,9 @@
"info.command.structure.reload-vscode": "Restart Vscode", "info.command.structure.reload-vscode": "Restart Vscode",
"error.look-up-log": "View error log", "error.look-up-log": "View error log",
"netlist.save-as-svg": "Save as SVG", "netlist.save-as-svg": "Save as SVG",
"svg-file": "SVG file" "svg-file": "SVG file",
"toolbar.save-as-svg": "Save current view as SVG",
"toolbar.save-as-pdf": "Save current view as PDF",
"pdf-file": "PDF file",
"export-pdf": "Exporting PDF"
} }

View File

@ -106,5 +106,9 @@
"info.command.structure.reload-vscode": "Vscodeを再起動", "info.command.structure.reload-vscode": "Vscodeを再起動",
"error.look-up-log": "エラーログを表示", "error.look-up-log": "エラーログを表示",
"netlist.save-as-svg": "SVGとして保存", "netlist.save-as-svg": "SVGとして保存",
"svg-file": "SVGファイル" "svg-file": "SVGファイル",
"toolbar.save-as-svg": "現在のビューをSVGとして保存",
"toolbar.save-as-pdf": "現在のビューをPDFとして保存",
"pdf-file": "PDFファイル",
"export-pdf": "PDFをエクスポート中"
} }

View File

@ -106,5 +106,9 @@
"info.command.structure.reload-vscode": "重启 Vscode", "info.command.structure.reload-vscode": "重启 Vscode",
"error.look-up-log": "查看错误日志", "error.look-up-log": "查看错误日志",
"netlist.save-as-svg": "保存为 Svg", "netlist.save-as-svg": "保存为 Svg",
"svg-file": "svg 文件" "svg-file": "svg 文件",
"toolbar.save-as-svg": "将当前视图保存为 svg",
"toolbar.save-as-pdf": "将当前视图保存为 pdf",
"pdf-file": "pdf 文件",
"export-pdf": "正在导出 pdf"
} }

View File

@ -106,5 +106,9 @@
"info.command.structure.reload-vscode": "重啟 Vscode", "info.command.structure.reload-vscode": "重啟 Vscode",
"error.look-up-log": "查看錯誤日誌", "error.look-up-log": "查看錯誤日誌",
"netlist.save-as-svg": "保存為Svg", "netlist.save-as-svg": "保存為Svg",
"svg-file": "SVG 檔案" "svg-file": "SVG 檔案",
"toolbar.save-as-svg": "將目前視圖儲存為SVG",
"toolbar.save-as-pdf": "將目前視圖儲存為PDF",
"pdf-file": "PDF檔案",
"export-pdf": "正在匯出PDF"
} }

View File

@ -2,7 +2,7 @@ import * as vscode from 'vscode';
import * as path from 'path'; import * as path from 'path';
import * as fs from 'fs'; import * as fs from 'fs';
import pako from 'pako'; import * as pako from 'pako';
import puppeteer, { LowerCasePaperFormat, PDFOptions } from 'puppeteer-core'; import puppeteer, { LowerCasePaperFormat, PDFOptions } from 'puppeteer-core';
import { AbsPath, opeParam } from '../../global'; import { AbsPath, opeParam } from '../../global';
import { hdlPath } from '../../hdlFs'; import { hdlPath } from '../../hdlFs';
@ -28,12 +28,9 @@ export async function saveAsSvg(data: any, panel: vscode.WebviewPanel) {
// 询问新的路径 // 询问新的路径
const defaultFilename = moduleName + '.svg'; const defaultFilename = moduleName + '.svg';
const defaultPath = hdlPath.join(opeParam.workspacePath, defaultFilename); const defaultPath = hdlPath.join(opeParam.workspacePath, defaultFilename);
const vcdFilters: Record<string, string[]> = {};
vcdFilters[""] = ['svg'];
vcdFilters[t('info.vcd-viewer.all-file')] = ['*'];
const saveUri = await vscode.window.showSaveDialog({ const saveUri = await vscode.window.showSaveDialog({
title: t('info.vcd-viewer.save-as-view'), title: t('netlist.save-as-svg'),
defaultUri: vscode.Uri.file(defaultPath), defaultUri: vscode.Uri.file(defaultPath),
saveLabel: t('info.vcd-viewer.save'), saveLabel: t('info.vcd-viewer.save'),
filters: { filters: {
@ -66,48 +63,59 @@ export async function saveAsSvg(data: any, panel: vscode.WebviewPanel) {
} }
} }
export async function saveAsPdf(req: Request, res: Response) { export async function saveAsPdf(data: any, panel: vscode.WebviewPanel) {
try { try {
const { svgBuffer, moduleName, width, height } = req.body; const { svgBuffer, moduleName, width, height } = data;
const svgString = pako.ungzip(svgBuffer, { to: 'string' }); const svgString = pako.ungzip(svgBuffer, { to: 'string' });
// 询问新的路径 // 询问新的路径
const defaultFilename = moduleName + '.pdf'; const defaultFilename = moduleName + '.pdf';
const savePath = await showSaveViewDialog({ const defaultPath = hdlPath.join(opeParam.workspacePath, defaultFilename);
title: 'Save As pdf',
defaultPath: path.resolve(__dirname, '../test', defaultFilename), const saveUri = await vscode.window.showSaveDialog({
buttonLabel: 'Save', title: t('toolbar.save-as-pdf'),
filters: [ defaultUri: vscode.Uri.file(defaultPath),
{ name: 'pdf', extensions: ['pdf'] }, saveLabel: t('info.vcd-viewer.save'),
{ name: 'All Files', extensions: ['*'] }, filters: {
], [t('pdf-file')]: ['pdf'],
[t("info.vcd-viewer.all-file")]: ['*']
}
}); });
if (savePath) { if (saveUri) {
const savePath = saveUri.fsPath;
// 先保存 html // 先保存 html
const htmlPath = savePath.slice(0, -4) + '.html'; const htmlPath = savePath.slice(0, -4) + '.html';
fs.writeFileSync(htmlPath, svgString); fs.writeFileSync(htmlPath, svgString);
await html2pdf(htmlPath, savePath, moduleName, width, height); await vscode.window.withProgress({
// removeBlankPages(savePath); title: t('export-pdf'),
location: vscode.ProgressLocation.Notification
}, async () => {
await html2pdf(htmlPath, savePath, moduleName, width, height);
});
fs.rmSync(htmlPath);
res.send({ panel.webview.postMessage({
savePath, command: 'save-as-pdf',
success: true arguments: [{ success: true }]
}); });
} else { } else {
res.send({ panel.webview.postMessage({
success: false command: 'save-as-pdf',
arguments: [{ success: false }]
}); });
} }
} catch (error) { } catch (error) {
console.log('error happen in /save-as-pdf, ' + error); console.log('error happen in /save-as-pdf, ' + error);
res.send({ panel.webview.postMessage({
success: false command: 'save-as-pdf',
arguments: [{ success: false }]
}); });
} }
} }
async function html2pdf(htmlPath: string, pdfPath: string, moduleName: string, width: number, height: number) { async function html2pdf(htmlPath: string, pdfPath: string, moduleName: string, width: number, height: number) {
const browserPath = getDefaultBrowerPath();
const browser = await puppeteer.launch({ const browser = await puppeteer.launch({
executablePath: browserPath, executablePath: browserPath,
args: ['--lang=en-US', '--no-sandbox', '--disable-setuid-sandbox'] args: ['--lang=en-US', '--no-sandbox', '--disable-setuid-sandbox']

View File

@ -12,6 +12,7 @@ import { t } from '../../i18n';
import { HdlLangID } from '../../global/enum'; import { HdlLangID } from '../../global/enum';
import { getIconConfig } from '../../hdlFs/icons'; import { getIconConfig } from '../../hdlFs/icons';
import { PathSet } from '../../global/util'; import { PathSet } from '../../global/util';
import { saveAsPdf, saveAsSvg } from './api';
type SynthMode = 'before' | 'after' | 'RTL'; type SynthMode = 'before' | 'after' | 'RTL';
@ -240,6 +241,8 @@ class Netlist {
.replace('dide.skin', skin); .replace('dide.skin', skin);
this.panel.webview.html = preprocessHtml; this.panel.webview.html = preprocessHtml;
registerMessageEvent(this.panel);
} else { } else {
YosysOutput.report('preview html in <Netlist.create> is empty', { YosysOutput.report('preview html in <Netlist.create> is empty', {
level: ReportType.Warn level: ReportType.Warn
@ -297,3 +300,21 @@ export async function openNetlistViewer(context: vscode.ExtensionContext, uri: v
const viewer = new Netlist(context); const viewer = new Netlist(context);
viewer.open(uri, moduleName); viewer.open(uri, moduleName);
} }
function registerMessageEvent(panel: vscode.WebviewPanel) {
panel.webview.onDidReceiveMessage(message => {
const { command, data } = message;
switch (command) {
case 'save-as-svg':
saveAsSvg(data, panel);
break;
case 'save-as-pdf':
saveAsPdf(data, panel);
break;
default:
break;
}
});
}