1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
| <template> <el-dialog v-model="editImageDialogVisible" width="90vw" center top="10px" :header="null" :title="null" :close-on-click-modal="false" :show-close="false" class="edit-image-dialog" > <div class="drawing-container"> <!-- 绘图组件容器DOM --> <div id="tui-image-editor"></div> <el-button class="save" type="primary" @click="handleCopySaveImage" >保存</el-button > <el-button class="cancel" type="default" @click="editImageDialogVisible = false" > 取消 </el-button> </div> </el-dialog> </template> <script setup lang="ts"> import { ref, nextTick, defineExpose } from "vue"; import "tui-image-editor/dist/tui-image-editor.css"; import "tui-color-picker/dist/tui-color-picker.css"; import ImageEditor from "tui-image-editor"; import { base64ToBlob, blobImageToCopy } from "@/utils/common";
const editImageDialogVisible = ref(false);
const openEditImageDialog = (url: string) => { editImageDialogVisible.value = true; nextTick(() => { init(url); }); };
// 保存复制图片 const handleCopySaveImage = () => { const base64String = instance.value.toDataURL(); const data = base64ToBlob(base64String); blobImageToCopy(data); editImageDialogVisible.value = false; };
// 中文菜单 const locale_zh = { ZoomIn: "放大", ZoomOut: "缩小", Hand: "手掌", History: "历史", Resize: "调整宽高", Crop: "裁剪", 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: "混合色", Width: "宽度", Height: "高度", "Lock Aspect Ratio": "锁定宽高比例", };
// 画布组件自定义样式 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",
// load button "loadButton.backgroundColor": "#fff", "loadButton.border": "1px solid #ddd", "loadButton.color": "#222", "loadButton.fontFamily": "NotoSans, sans-serif", "loadButton.fontSize": "12px", "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", };
const instance = ref(null);
const init = (url?: string) => { instance.value = new ImageEditor( document.querySelector("#tui-image-editor"), { includeUI: { loadImage: { path: url || "https://rocket-chat.oss-cn-hangzhou.aliyuncs.com/202401/6663/cba53b4f477343898ef2ab5cc1e60229.jpg", name: "image", }, menu: [ "resize", "crop", "rotate", "draw", "shape", "icon", "text", "filter", ], // 底部菜单按钮列表 隐藏镜像flip和遮罩mask initMenu: "draw", // 默认打开的菜单项 menuBarPosition: "bottom", // 菜单所在的位置 locale: locale_zh, // 本地化语言为中文 theme: customTheme, // 自定义样式 }, cssMaxWidth: 400, // canvas 最大宽度 cssMaxHeight: 400, // canvas 最大高度 } ); document.getElementsByClassName("tui-image-editor-main")[0].style.top = "30px"; // 调整图片显示位置 document.getElementsByClassName( "tie-btn-reset tui-image-editor-item help" )[0].style.display = "none"; // 隐藏顶部重置按钮 };
defineExpose({ openEditImageDialog, }); </script> <style lang="scss"> /* 强制压缩菜单的高度 ,减少占用屏幕的空间*/ .tui-image-editor-container .tui-image-editor-submenu { height: auto !important; } .tui-image-editor-container.bottom .tui-image-editor-submenu > div { padding: 0 !important; } .tui-image-editor-container .tui-image-editor-help-menu.top { background-color: white; }
/* 顶部工具栏定位 */ .tui-image-editor-container { overflow: visible; }
.edit-image-dialog { :deep() .el-dialog__body { padding: 0 !important; } .el-dialog__header { padding: 0 !important; } } </style> <style scoped lang="scss"> .drawing-container { width: 100%; height: 80vh; position: relative; .save { position: absolute; right: 50px; top: 15px; } .cancel { position: absolute; right: 120px; top: 15px; } } </style>
|