diff --git a/package-lock.json b/package-lock.json index b739054..a51d5f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "elkjs": "^0.9.3", "fflate": "^0.8.2", "mitt": "^3.0.1", + "pako": "^2.1.0", "vue": "^3.2.13", "vue-i18n": "10.0.5", "web-worker": "^1.3.0" @@ -8768,6 +8769,11 @@ "node": ">=6" } }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmmirror.com/param-case/-/param-case-3.0.4.tgz", diff --git a/package.json b/package.json index 2c25a5f..bc5f8ac 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "elkjs": "^0.9.3", "fflate": "^0.8.2", "mitt": "^3.0.1", + "pako": "^2.1.0", "vue": "^3.2.13", "vue-i18n": "10.0.5", "web-worker": "^1.3.0" diff --git a/src/api/index.js b/src/api/index.js index 55cba2f..73bfd46 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -1,16 +1,141 @@ +import { colorManager } from "@/components/setting/color"; +import { increaseBrightness, lowerBrightness, parseColor } from "@/hook/color"; import { globalLookup } from "@/hook/global"; import { pinkLog } from "@/hook/utils"; +import axios from 'axios'; +import pako from 'pako'; const mode = window.acquireVsCodeApi === undefined ? 'debug' : 'release'; pinkLog('digital-netlist-render mode: ' + mode); let vscode = window.acquireVsCodeApi === undefined ? undefined : acquireVsCodeApi(); -export async function saveAsSvg() { - const selection = globalLookup.netlistRender.selection; +function getColorFromMacro(rootStyles, optionName, theme) { + if (theme === 'dark') { + return rootStyles.getPropertyValue(optionName); + } else { + switch (optionName) { + case '--foreground': + case '--wire-color': + case '--cross-dot-color': + return '#2D323B'; + } + const color = rootStyles.getPropertyValue(optionName); + if (!color) { + return color; + } + const rgb = parseColor(color); + const { r, g, b } = increaseBrightness(rgb, 10); + return `rgb(${r}, ${g}, ${b})`; + } +} +function makeStyleString(config = {}) { + const theme = config.theme || 'dark'; + // 加入全局颜色宏 + const colorMacros = []; + const rootStyles = getComputedStyle(document.documentElement); + + for (const item of colorManager.generals) { + const colorOption = `--${item.type}-color`; + const colorFillOption = `--${item.type}-fill-color`; + + const color = getColorFromMacro(rootStyles, colorOption, theme); + const colorFill = getColorFromMacro(rootStyles, colorFillOption, theme); + if (color) { + colorMacros.push(`${colorOption}: ${color};`); + } + if (colorFill) { + colorMacros.push(`${colorFillOption}: ${colorFill};`); + } + } + + for (const item of colorManager.cells) { + const colorOption = `--${item.type}-color`; + const colorFillOption = `--${item.type}-fill-color`; + + const color = getColorFromMacro(rootStyles, colorOption, theme); + const colorFill = getColorFromMacro(rootStyles, colorFillOption, theme); + if (color) { + colorMacros.push(`${colorOption}: ${color};`); + } + if (colorFill) { + colorMacros.push(`${colorFillOption}: ${colorFill};`); + } + } + + const globalSetting = [ + '--foreground', + '--background', + '--main-color' + ]; + + for (const setting of globalSetting) { + const color = getColorFromMacro(rootStyles, setting, theme); + if (color) { + colorMacros.push(`${setting}: ${color};`); + } + } + + const styleString = `:root {\n${colorMacros.join('\n')}\n}`; + return styleString; +} + +function getCompressedSvgBuffer(config = {}) { + const selection = globalLookup.netlistRender.selection; + const node = selection.node(); + + const styleString = makeStyleString(config); + const style = document.createElement('style'); + style.textContent = styleString; + node.insertBefore(style, node.firstChild); + + const serializer = new XMLSerializer(); + const svgString = serializer.serializeToString(node); + const array = pako.gzip(svgString); + + // 还原 + const styleElement = node.querySelector('style'); + if (styleElement) { + styleElement.remove(); + } + + return array; +} + +export async function saveAsSvg() { + const svgBuffer = getCompressedSvgBuffer(); + const moduleName = globalLookup.topModuleName; + if (mode === 'debug') { + const res = await axios.post('http://localhost:3000/netlist/save-as-svg', { svgBuffer, moduleName }); + if (res.success) { + pinkLog('成功保存到”' + res.savePath); + } + } else { + vscode.postMessage({ + command: 'save-as-svg', + data: { svgBuffer, moduleName } + }); + } } export async function saveAsPdf() { - + const svgBuffer = getCompressedSvgBuffer({ theme: 'light' }); + const moduleName = globalLookup.topModuleName; + + const node = globalLookup.netlistRender.selection.node(); + const width = node.getAttribute('width'); + const height = node.getAttribute('height'); + + if (mode === 'debug') { + const res = await axios.post('http://localhost:3000/netlist/save-as-pdf', { svgBuffer, moduleName, width, height }); + if (res.success) { + pinkLog('成功保存到”' + res.savePath); + } + } else { + vscode.postMessage({ + command: 'save-as-pdf', + data: { svgBuffer, moduleName, width, height } + }); + } } \ No newline at end of file diff --git a/src/components/toolbar/file-menu/save-as-svg.vue b/src/components/toolbar/file-menu/save-as-svg.vue index fea1b85..6a3c1e4 100644 --- a/src/components/toolbar/file-menu/save-as-svg.vue +++ b/src/components/toolbar/file-menu/save-as-svg.vue @@ -3,7 +3,7 @@
Shift S