Web截图

123 阅读3分钟

基于浏览器的截图且可编辑组件

使用到 tui-image-editorhtml2canvas

安装方法

npm install --save tui-image-editor 

npm i --save html2canvas

配上官网链接

tui-image-editor: nhn.github.io/tui.image-e…

html2canvas: html2canvas.hertzen.com/

tui-image-editor用于截图之后的编辑操作,有裁切、翻转、旋转、绘画、形状、文本、图标、覆盖、滤镜

image.png

html2canvas用于web浏览器截图

image.png

实践

使用vue3 + vite + element-plus,安装过程略过。。。 完整代码在文末

页面部分 使用element-plus的弹窗,截图之后弹窗内编辑图片

<template>  
    <div>  
        <slot :screenshot="clickGeneratePicture">  
            <el-button class="screenshotBtn button" @click="clickGeneratePicture">  
            一键截图  
            </el-button>  
        </slot>  

        <el-dialog  
        draggable  
        v-model="dialogVisible"  
        title="截图"  
        :width="width"  
        :before-close="handleClose"  
        @opened="opened"  
        :append-to-body="true"  
        align-center  
        >  
            <!-- 用于存放截图 -->  
            <div ref="editor"></div>  
            <template #footer>  
            <div class="dialog-footer">  
            <el-button @click="save">保存</el-button>  
            </div>  
            </template>  
        </el-dialog>  
    </div>  
</template>

css部分

.tui-image-editor-container {  
    width: 1500px;  
    height: 800px !important;  
}

导入所需的包

import "tui-image-editor/dist/tui-image-editor.css";  
import "tui-color-picker/dist/tui-color-picker.css";  
import html2canvas from "html2canvas";  
import ImageEditor from "tui-image-editor";

截图方法,使用 html2canvas

const clickGeneratePicture = () => {  
    html2canvas(props.imageWrapper, {  
        logging: false,  
        allowTaint: true,  
        scale: window.devicePixelRatio,  
        // width: shareContent.clientWidth,  
        // height: shareContent.clientHeight,  
        scrollY: 0,  
        scrollX: 0,  
        useCORS: true,  
        backgroundColor: null,  
        }).then(async function (canvas) {  
        imgUrl.value = canvas.toDataURL("image/png");  
        dialogVisible.value = true;  
    });  
};

修改 tui-image-editor 英文转中文

// 转中文  
const locale_zh = {  
    // override default English locale to your custom  
    Crop: "裁剪",  
    Load: "替换图片",  
    DeleteAll: "全部删除",  
    Delete: "删除",  
    Undo: "撤销",  
    Redo: "反撤销",  
    Reset: "重置",  
    Flip: "镜像",  
    Rotate: "旋转",  
    Draw: "画",  
    Shape: "形状标注",  
    Icon: "图标标注",  
    Text: "文字标注",  
    Mask: "遮罩",  
    Filter: "滤镜",  
    Bold: "加粗",  
    Italic: "斜体",  
    Underline: "下划线",  
    Left: "左对齐",  
    Center: "居中",  
    Right: "右对齐",  
    Color: "颜色",  
    "Text size": "字体大小",  
    Custom: "自定义",  
    Square: "正方形",  
    Apply: "应用",  
    Cancel: "取消",  
    "Flip X": "X 轴",  
    "Flip Y": "Y 轴",  
    Range: "区间",  
    Stroke: "描边",  
    Fill: "填充",  
    Circle: "圆",  
    Triangle: "三角",  
    Rectangle: "矩形",  
    Free: "曲线",  
    Straight: "直线",  
    Arrow: "箭头",  
    "Arrow-2": "箭头2",  
    "Arrow-3": "箭头3",  
    "Star-1": "星星1",  
    "Star-2": "星星2",  
    Polygon: "多边形",  
    Location: "定位",  
    Heart: "心形",  
    Bubble: "气泡",  
    "Custom icon": "自定义图标",  
    "Load Mask Image": "加载蒙层图片",  
    Grayscale: "灰度",  
    Blur: "模糊",  
    Sharpen: "锐化",  
    Emboss: "浮雕",  
    "Remove White": "除去白色",  
    Distance: "距离",  
    Brightness: "亮度",  
    Noise: "噪音",  
    "Color Filter": "彩色滤镜",  
    Sepia: "棕色",  
    Sepia2: "棕色2",  
    Invert: "负片",  
    Pixelate: "像素化",  
    Threshold: "阈值",  
    Tint: "色调",  
    Multiply: "正片叠底",  
    Blend: "混合色",  
    Double: "双击",  
    Download: "预览图片",  

    // etc...  
};

自定义tui-image-editor样式

const customTheme = {  
    // image 坐上角度图片  
    "common.bi.image": "", // 在这里换上你喜欢的logo图片  
    "common.bisize.width": "0px",  
    "common.bisize.height": "0px",  
    "common.backgroundImage": "none",  
    "common.backgroundColor": "#f3f4f6",  
    "common.border": "1px solid #444",  

    // header  
    "header.backgroundImage": "none",  
    "header.backgroundColor": "#f3f4f6",  
    "header.border": "0px",  
    "header.margin": "0px auto",  

    // load button  
    "loadButton.backgroundColor": "#fff",  
    "loadButton.border": "1px solid #ddd",  
    "loadButton.color": "#222",  
    "loadButton.fontFamily": "NotoSans, sans-serif",  
    "loadButton.fontSize": "12px",  
    "loadButton.width": "150px",  
    "loadButton.display": "none", // 可以直接隐藏掉  

    // download button  
    "downloadButton.backgroundColor": "#fdba3b",  
    "downloadButton.border": "1px solid #fdba3b",  
    "downloadButton.color": "#fff",  
    "downloadButton.fontFamily": "NotoSans, sans-serif",  
    "downloadButton.fontSize": "12px",  
    // "downloadButton.display": "none", // 可以直接隐藏掉  

    // icons default  
    "menu.normalIcon.color": "#8a8a8a",  
    "menu.activeIcon.color": "#555555",  
    "menu.disabledIcon.color": "#434343",  
    "menu.hoverIcon.color": "#e9e9e9",  
    "submenu.normalIcon.color": "#8a8a8a",  
    "submenu.activeIcon.color": "#e9e9e9",  

    "menu.iconSize.width": "24px",  
    "menu.iconSize.height": "24px",  
    "submenu.iconSize.width": "32px",  
    "submenu.iconSize.height": "32px",  

    // submenu primary color  
    "submenu.backgroundColor": "#1e1e1e",  
    "submenu.partition.color": "#858585",  

    // submenu labels  
    "submenu.normalLabel.color": "#858585",  
    "submenu.normalLabel.fontWeight": "lighter",  
    "submenu.activeLabel.color": "#fff",  
    "submenu.activeLabel.fontWeight": "lighter",  

    // checkbox style  
    "checkbox.border": "1px solid #ccc",  
    "checkbox.backgroundColor": "#fff",  

    // rango style  
    "range.pointer.color": "#fff",  
    "range.bar.color": "#666",  
    "range.subbar.color": "#d1d1d1",  

    "range.disabledPointer.color": "#414141",  
    "range.disabledBar.color": "#282828",  
    "range.disabledSubbar.color": "#414141",  

    "range.value.color": "#fff",  
    "range.value.fontWeight": "lighter",  
    "range.value.fontSize": "11px",  
    "range.value.border": "1px solid #353535",  
    "range.value.backgroundColor": "#151515",  
    "range.title.color": "#fff",  
    "range.title.fontWeight": "lighter",  

    // colorpicker style  
    "colorpicker.button.border": "1px solid #1e1e1e",  
    "colorpicker.title.color": "#fff",  
};

tui-image-editor 实例化

const options = {  
    usageStatistics: false,  
    includeUI: {  
        loadImage: {  
            path: imgUrl.value,  
            name: "imgName",  
        },  
        //操作菜单栏  
        menu: [  
            "crop", // 裁切  
            "flip", // 翻转  
            "rotate", // 旋转  
            "draw", // 添加绘画  
            "shape", // 添加形状  
            "text", // 添加文本  
            "icon", // 图标  
            // "mask", // 添加覆盖,  
            // 'filter' // 滤镜  
        ],  
        menuBarPosition: "top", //操作栏位置  
        locale: locale_zh, // 中文  
        theme: customTheme, //主题样式  
        },  
        cssMaxWidth: props.imgWidth, // 图片宽度  
        cssMaxHeight: props.imgHeight, // 图片高度  
        selectionStyle: {  
            cornerSize: 20,  
            rotatingPointOffset: 70,  
        },  
};  
// 实例化编辑器  
imageEditor.value = new ImageEditor(editor.value, options);

使用 tui-image-editor 回调保存编辑后的图片

const base64 = imageEditor.value.toDataURL();

附上完整代码

<!--  
    截图组件 用于dom的截图 并提供编辑操作  
-->  
<template>  
    <div>  
        <slot :screenshot="clickGeneratePicture">  
            <el-button class="screenshotBtn button" @click="clickGeneratePicture">  
            一键截图  
            </el-button>  
        </slot>  

        <el-dialog  
            draggable  
            v-model="dialogVisible"  
            title="截图"  
            :width="width"  
            :before-close="handleClose"  
            @opened="opened"  
            :append-to-body="true"  
            align-center  
        >  
            <!-- 用于存放截图 -->  
            <div ref="editor"></div>  
            <template #footer>  
                <div class="dialog-footer">  
                    <el-button @click="save">保存</el-button>  
                </div>  
            </template>  
        </el-dialog>  
    </div>  
</template>  
  
<script setup>  
import "tui-image-editor/dist/tui-image-editor.css";  
import "tui-color-picker/dist/tui-color-picker.css";  
import html2canvas from "html2canvas";  
import ImageEditor from "tui-image-editor";  
import { computed, ref } from "vue";  
  
const props = defineProps({  
    /**  
    * 需要截图的dom的ref  
    */  
    imageWrapper: {  
        required: true,  
    },  
    /**  
    * dialog的宽度  
    */  
    width: {  
        type: Number,  
        default: 1500,  
        required: false,  
    },  
    /**  
    * 截图宽度  
    */  
    imgWidth: {  
        type: Number,  
        required: false,  
        default: 1600,  
    },  
    /**  
    * 截图高度  
    */  
    imgHeight: {  
        type: Number,  
        required: false,  
        default: 700,  
    },  
    /**  
    * 截图宽度  
    */  
    containerWidth: {  
        type: Number,  
        required: false,  
        default: 1500,  
    },  
    /**  
    * 截图高度  
    */  
    containerHeight: {  
        type: Number,  
        required: false,  
        default: 800,  
    },  
});  
  
const emit = defineEmits(["save"]);  
  
const customTheme = {  
    // image 坐上角度图片  
    "common.bi.image": "", // 在这里换上你喜欢的logo图片  
    "common.bisize.width": "0px",  
    "common.bisize.height": "0px",  
    "common.backgroundImage": "none",  
    "common.backgroundColor": "#f3f4f6",  
    "common.border": "1px solid #444",  

    // header  
    "header.backgroundImage": "none",  
    "header.backgroundColor": "#f3f4f6",  
    "header.border": "0px",  
    "header.margin": "0px auto",  

    // load button  
    "loadButton.backgroundColor": "#fff",  
    "loadButton.border": "1px solid #ddd",  
    "loadButton.color": "#222",  
    "loadButton.fontFamily": "NotoSans, sans-serif",  
    "loadButton.fontSize": "12px",  
    "loadButton.width": "150px",  
    "loadButton.display": "none", // 可以直接隐藏掉  

    // download button  
    "downloadButton.backgroundColor": "#fdba3b",  
    "downloadButton.border": "1px solid #fdba3b",  
    "downloadButton.color": "#fff",  
    "downloadButton.fontFamily": "NotoSans, sans-serif",  
    "downloadButton.fontSize": "12px",  
    // "downloadButton.display": "none", // 可以直接隐藏掉  

    // icons default  
    "menu.normalIcon.color": "#8a8a8a",  
    "menu.activeIcon.color": "#555555",  
    "menu.disabledIcon.color": "#434343",  
    "menu.hoverIcon.color": "#e9e9e9",  
    "submenu.normalIcon.color": "#8a8a8a",  
    "submenu.activeIcon.color": "#e9e9e9",  

    "menu.iconSize.width": "24px",  
    "menu.iconSize.height": "24px",  
    "submenu.iconSize.width": "32px",  
    "submenu.iconSize.height": "32px",  

    // submenu primary color  
    "submenu.backgroundColor": "#1e1e1e",  
    "submenu.partition.color": "#858585",  

    // submenu labels  
    "submenu.normalLabel.color": "#858585",  
    "submenu.normalLabel.fontWeight": "lighter",  
    "submenu.activeLabel.color": "#fff",  
    "submenu.activeLabel.fontWeight": "lighter",  

    // checkbox style  
    "checkbox.border": "1px solid #ccc",  
    "checkbox.backgroundColor": "#fff",  

    // rango style  
    "range.pointer.color": "#fff",  
    "range.bar.color": "#666",  
    "range.subbar.color": "#d1d1d1",  

    "range.disabledPointer.color": "#414141",  
    "range.disabledBar.color": "#282828",  
    "range.disabledSubbar.color": "#414141",  

    "range.value.color": "#fff",  
    "range.value.fontWeight": "lighter",  
    "range.value.fontSize": "11px",  
    "range.value.border": "1px solid #353535",  
    "range.value.backgroundColor": "#151515",  
    "range.title.color": "#fff",  
    "range.title.fontWeight": "lighter",  

    // colorpicker style  
    "colorpicker.button.border": "1px solid #1e1e1e",  
    "colorpicker.title.color": "#fff",  
};  
  
// 编辑器的实例  
let imageEditor = ref();  
// 编辑器的容器  
const editor = ref();  
// 截图的url  
let imgUrl = ref("");  
// 转中文  
const locale_zh = {  
    // override default English locale to your custom  
    Crop: "裁剪",  
    Load: "替换图片",  
    DeleteAll: "全部删除",  
    Delete: "删除",  
    Undo: "撤销",  
    Redo: "反撤销",  
    Reset: "重置",  
    Flip: "镜像",  
    Rotate: "旋转",  
    Draw: "画",  
    Shape: "形状标注",  
    Icon: "图标标注",  
    Text: "文字标注",  
    Mask: "遮罩",  
    Filter: "滤镜",  
    Bold: "加粗",  
    Italic: "斜体",  
    Underline: "下划线",  
    Left: "左对齐",  
    Center: "居中",  
    Right: "右对齐",  
    Color: "颜色",  
    "Text size": "字体大小",  
    Custom: "自定义",  
    Square: "正方形",  
    Apply: "应用",  
    Cancel: "取消",  
    "Flip X": "X 轴",  
    "Flip Y": "Y 轴",  
    Range: "区间",  
    Stroke: "描边",  
    Fill: "填充",  
    Circle: "圆",  
    Triangle: "三角",  
    Rectangle: "矩形",  
    Free: "曲线",  
    Straight: "直线",  
    Arrow: "箭头",  
    "Arrow-2": "箭头2",  
    "Arrow-3": "箭头3",  
    "Star-1": "星星1",  
    "Star-2": "星星2",  
    Polygon: "多边形",  
    Location: "定位",  
    Heart: "心形",  
    Bubble: "气泡",  
    "Custom icon": "自定义图标",  
    "Load Mask Image": "加载蒙层图片",  
    Grayscale: "灰度",  
    Blur: "模糊",  
    Sharpen: "锐化",  
    Emboss: "浮雕",  
    "Remove White": "除去白色",  
    Distance: "距离",  
    Brightness: "亮度",  
    Noise: "噪音",  
    "Color Filter": "彩色滤镜",  
    Sepia: "棕色",  
    Sepia2: "棕色2",  
    Invert: "负片",  
    Pixelate: "像素化",  
    Threshold: "阈值",  
    Tint: "色调",  
    Multiply: "正片叠底",  
    Blend: "混合色",  
    Double: "双击",  
    Download: "预览图片",  

    // etc...  
};  
// 弹窗显隐  
let dialogVisible = ref(false);  
  
/**  
* 弹窗关闭  
*/  
const handleClose = () => {  
    dialogVisible.value = false;  
    imageEditor.value.destroy();  
};  
  
/**  
* 保存图片  
* 返回截图编辑之后的图片 base64格式  
*/  
const save = () => {  
    const base64 = imageEditor.value.toDataURL();  
    emit("save", { url: base64 });  
};  
  
/**  
* 弹窗显示之后的回调  
*/  
const opened = () => {  
    const options = {  
        usageStatistics: false,  

        includeUI: {  
            loadImage: {  
                path: imgUrl.value,  
                name: "imgName",  
            },  
            //操作菜单栏  
            menu: [  
                "crop", // 裁切  
                "flip", // 翻转  
                "rotate", // 旋转  
                "draw", // 添加绘画  
                "shape", // 添加形状  
                "text", // 添加文本  
                "icon", // 图标  
                // "mask", // 添加覆盖,  
                // 'filter' // 滤镜  
            ],  
            menuBarPosition: "top", //操作栏位置  
            locale: locale_zh, // 中文  
            theme: customTheme, //主题样式  
        },  
        cssMaxWidth: props.imgWidth, // 图片宽度  
        cssMaxHeight: props.imgHeight, // 图片高度  
        selectionStyle: {  
            cornerSize: 20,  
            rotatingPointOffset: 70,  
        },  
    };  
    // 实例化编辑器  
    imageEditor.value = new ImageEditor(editor.value, options);  
};  
  
/**  
* 截图  
*/  
const clickGeneratePicture = () => {  
    html2canvas(props.imageWrapper, {  
        logging: false,  
        allowTaint: true,  
        scale: window.devicePixelRatio,  
        // width: shareContent.clientWidth,  
        // height: shareContent.clientHeight,  
        scrollY: 0,  
        scrollX: 0,  
        useCORS: true,  
        backgroundColor: null,  
    }).then(async function (canvas) {  
        imgUrl.value = canvas.toDataURL("image/png");  
        dialogVisible.value = true;  
    });  
};  
</script>  
  
<style scoped lang="scss">  
.tui-image-editor-container {  
    width: 1500px;  
    height: 800px !important;  
}  
</style>

完结~~~