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 @@
{{ t('toolbar.save-as-svg') }} - + Shift S
@@ -29,11 +29,11 @@ async function manualLoadView() { loading.close(); } -// document.addEventListener('keydown', async event => { -// if (event.ctrlKey && event.key === 'k') { -// event.preventDefault(); -// manualLoadView(); -// } -// }); +document.addEventListener('keydown', async event => { + if (event.ctrlKey && event.key === 's') { + event.preventDefault(); + manualLoadView(); + } +}); \ No newline at end of file diff --git a/src/hook/color.js b/src/hook/color.js index b7fa996..8b5650e 100644 --- a/src/hook/color.js +++ b/src/hook/color.js @@ -68,6 +68,28 @@ export function increaseBrightness(rgb, percent) { } +/** + * @description 降低颜色的亮度 + * @param {RgbColor} rgb + * @param {number} percent 0 - 100 的数字,代表增强的亮度比例 + * @returns {RgbColor} + */ +export function lowerBrightness(rgb, percent) { + // 确保 percent 在 0 到 100 之间 + percent = Math.max(0, Math.min(100, percent)); + + // 计算每个颜色分量的增量 + const increment = (percent / 100) * 255; + + // 提升每个颜色分量的亮度 + const r = Math.min(255, Math.round(rgb.r - increment)); + const g = Math.min(255, Math.round(rgb.g - increment)); + const b = Math.min(255, Math.round(rgb.b - increment)); + + return { r, g, b }; +} + + /** * @description gamma 修正 * @param {number} c 颜色通道值,取值范围为 0 - 255