Greasy Fork

来自缓存

Greasy Fork is available in English.

Processon-SVG2PNG辅助器

svg转png

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Processon-SVG2PNG辅助器
// @namespace    https://www.processon.com/
// @version      0.3.3
// @description  svg转png
// @author       Aasee
// @match        https://www.processon.com/diagraming/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=https://www.processon.com/
// @license      MIT
// @require      https://cdn.jsdelivr.net/npm/[email protected]/lib/umd.js
// @connect      cdn.jsdelivr.net
// ==/UserScript==

(function() {
    'use strict';

    // 确保 canvg 已加载
    if (typeof canvg === 'undefined') {
        console.error('canvg is not loaded');
        return;
    }

    // 创建按钮容器
    const container = document.createElement('div');
    container.style.position = 'fixed';
    container.style.top = '70px';
    container.style.right = '10px';
    container.style.zIndex = '1000';

    // 创建主按钮
    const mainButton = document.createElement('button');
    mainButton.textContent = '下载图表';
    mainButton.style.width = '150px';
    mainButton.style.height = '50px';
    mainButton.style.padding = '10px';
    mainButton.style.backgroundColor = '#007bff';
    mainButton.style.color = 'white';
    mainButton.style.border = 'none';
    mainButton.style.borderRadius = '5px';
    mainButton.style.cursor = 'pointer';
    mainButton.style.transition = 'all 0.3s ease';
    mainButton.style.position = 'relative';

    // 创建下拉菜单
    const dropdown = document.createElement('div');
    dropdown.style.position = 'absolute';
    dropdown.style.top = '100%';
    dropdown.style.left = '0';
    dropdown.style.width = '100%';
    dropdown.style.display = 'none';
    dropdown.style.flexDirection = 'column';
    dropdown.style.gap = '5px';
    dropdown.style.marginTop = '5px';
    dropdown.style.transition = 'all 0.3s ease';
    dropdown.style.zIndex = '1001';

    // 创建PNG选项
    const pngOption = document.createElement('button');
    pngOption.textContent = '下载为PNG';
    pngOption.style.width = '100%';
    pngOption.style.height = '40px';
    pngOption.style.padding = '5px';
    pngOption.style.backgroundColor = '#007bff';
    pngOption.style.color = 'white';
    pngOption.style.border = 'none';
    pngOption.style.borderRadius = '5px';
    pngOption.style.cursor = 'pointer';
    pngOption.style.opacity = '0.9';

    // 创建SVG选项
    const svgOption = document.createElement('button');
    svgOption.textContent = '下载为SVG';
    svgOption.style.width = '100%';
    svgOption.style.height = '40px';
    svgOption.style.padding = '5px';
    svgOption.style.backgroundColor = '#28a745';
    svgOption.style.color = 'white';
    svgOption.style.border = 'none';
    svgOption.style.borderRadius = '5px';
    svgOption.style.cursor = 'pointer';
    svgOption.style.opacity = '0.9';

    // 拖动状态和位置偏移
    let offsetX, offsetY, startX, startY, isDragging = false;

    // 记录拖动状态和鼠标起始位置
    mainButton.addEventListener('mousedown', function(e) {
        startX = e.clientX;
        startY = e.clientY;
        isDragging = false;
        offsetX = e.clientX - container.getBoundingClientRect().left;
        offsetY = e.clientY - container.getBoundingClientRect().top;
        document.addEventListener('mousemove', onMouseMove);
        document.addEventListener('mouseup', onMouseUp);
        e.preventDefault();
    });

    function onMouseMove(e) {
        if (isDragging || Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5) {
            isDragging = true;
            container.style.left = (e.clientX - offsetX) + 'px';
            container.style.top = (e.clientY - offsetY) + 'px';
        }
    }

    function onMouseUp(e) {
        document.removeEventListener('mousemove', onMouseMove);
        document.removeEventListener('mouseup', onMouseUp);
    }

    // 点击显示/隐藏菜单
    let isMenuVisible = false;

    function toggleMenu() {
        if (isMenuVisible) {
            dropdown.style.display = 'none';
            mainButton.style.borderRadius = '5px';
        } else {
            dropdown.style.display = 'flex';
            mainButton.style.borderRadius = '5px 5px 0 0';
        }
        isMenuVisible = !isMenuVisible;
    }

    mainButton.addEventListener('click', function(e) {
        if (isDragging) return;
        toggleMenu();
    });

    // 点击其他地方关闭菜单
    document.addEventListener('click', function(e) {
        if (!container.contains(e.target) && isMenuVisible) {
            toggleMenu();
        }
    });

    // 获取SVG内容实际包围盒
    function getSVGBoundingBox(svgElement) {
        let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
        const elements = svgElement.querySelectorAll('*');
        elements.forEach(el => {
            if (typeof el.getBBox === 'function') {
                try {
                    const bbox = el.getBBox();
                    if (bbox.width && bbox.height) {
                        minX = Math.min(minX, bbox.x);
                        minY = Math.min(minY, bbox.y);
                        maxX = Math.max(maxX, bbox.x + bbox.width);
                        maxY = Math.max(maxY, bbox.y + bbox.height);
                    }
                } catch (e) {}
            }
        });
        if (minX === Infinity || minY === Infinity || maxX === -Infinity || maxY === -Infinity) {
            // fallback
            return {minX: 0, minY: 0, width: 1000, height: 1000};
        }
        return {minX, minY, width: maxX - minX, height: maxY - minY};
    }

    // 修改水印文字并移除根style属性,保证SVG完整显示
    function modifyWatermark(svgContent, userInput) {
        const parser = new DOMParser();
        const svgDoc = parser.parseFromString(svgContent, 'image/svg+xml');
        const svgElement = svgDoc.documentElement;

        // 移除根节点 style 属性
        svgElement.removeAttribute('style');

        // 修改水印文字
        const textElements = svgDoc.querySelectorAll('text');
        textElements.forEach(textElement => {
            if (textElement.textContent.includes('ProcessOn.com免费流程图')) {
                textElement.textContent = userInput;
            }
        });

        // 获取原始尺寸并去除单位
        let width = svgElement.getAttribute('width');
        let height = svgElement.getAttribute('height');
        if (width) width = width.replace(/[^\d.]/g, '');
        if (height) height = height.replace(/[^\d.]/g, '');

        // 如果没有width/height,尝试从viewBox获取
        let viewBox = svgElement.getAttribute('viewBox');
        if ((!width || !height) && viewBox) {
            const vb = viewBox.split(/\s+|,/);
            if (vb.length === 4) {
                width = width || vb[2];
                height = height || vb[3];
            }
        }

        // fallback
        if (!width) width = 1000;
        if (!height) height = 1000;

        // 强制viewBox从0,0开始
        svgElement.setAttribute('viewBox', `0 0 ${width} ${height}`);
        svgElement.setAttribute('width', width);
        svgElement.setAttribute('height', height);

        return new XMLSerializer().serializeToString(svgDoc.documentElement);
    }

    // PNG下载功能
    pngOption.addEventListener('click', function() {
        if (isDragging) return;
        try {
            var selectConfirm = confirm("是否修改为指定名字");
            var userInput = "";
            if(selectConfirm == true){
                userInput = prompt("请输入所需要的内容:", "");
            }
            const divElement = document.querySelector('.water_perview');

            if (!divElement) {
                alert('No SVG element found.');
                return;
            }

            const svgContent = divElement.querySelector('svg').outerHTML.replace(/ /g, ' ');
            const modifiedSvgString = modifyWatermark(svgContent, userInput);
            const parser = new DOMParser();
            const svgDoc = parser.parseFromString(modifiedSvgString, 'image/svg+xml');
            const svgElement = svgDoc.documentElement;

            const canvas = document.createElement('canvas');
            let width = svgElement.getAttribute('width');
            canvas.width = width;
            let height = svgElement.getAttribute('height');
            canvas.height = height;
            const ctx = canvas.getContext('2d');

            canvg.Canvg.fromString(ctx, modifiedSvgString).start();

            const pngData = canvas.toDataURL('image/png');
            const link = document.createElement('a');
            link.href = pngData;
            link.download = 'image.png';
            link.click();
            toggleMenu(); // 下载后关闭菜单

        } catch (error) {
            console.error('Error converting SVG to PNG:', error);
            alert('An error occurred while converting SVG to PNG.');
        }
    });

    // SVG下载功能
    svgOption.addEventListener('click', function() {
        if (isDragging) return;
        try {
            var selectConfirm = confirm("是否修改为指定名字");
            var userInput = "";
            if(selectConfirm == true){
                userInput = prompt("请输入所需要的内容:", "");
            }
            const divElement = document.querySelector('.water_perview');
            if (!divElement) {
                alert('No SVG element found.');
                return;
            }

            const svgContent = divElement.querySelector('svg').outerHTML.replace(/ /g, ' ');
            const modifiedSvgString = modifyWatermark(svgContent, userInput);
            const blob = new Blob([modifiedSvgString], { type: 'image/svg+xml' });
            const url = URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.href = url;
            link.download = 'diagram.svg';
            link.click();
            URL.revokeObjectURL(url);
            toggleMenu(); // 下载后关闭菜单
        } catch (error) {
            console.error('Error downloading SVG:', error);
            alert('An error occurred while downloading SVG.');
        }
    });

    // 组装界面
    dropdown.appendChild(pngOption);
    dropdown.appendChild(svgOption);
    mainButton.appendChild(dropdown);
    container.appendChild(mainButton);
    document.body.appendChild(container);
})();