自从我上次分享一个人开发仿造稿定设计的图片编辑器到现在,不知不觉已过去一年时间了,期间我经历了裁员失业、面试找工作碰壁,寒冬下一直没有很好地履行计划…..这些就放在日后谈吧。
最近挤出时间来完善了这个项目,正式开源后在一天内就收获了上百个Star,今天想向大家分享下这个开源图片编辑器项目——迅排设计,以及我的一些感悟和开源体验。
在线 Demo | 文档网站 | Github 开源地址: palxiao/poster-design
项目速览
1 2 3 4
| git clone https://github.com/palxiao/poster-design.git cd poster-design npm run prepared # 快捷安装依赖指令 npm run serve # 本地运行
|
将同时运行前端界面与图片生成服务(3000
与7001
端口),合成图片时本地会启动一个Chrome浏览器实例。
👇🏻下面一起来看下都有些什么功能吧。
上传 PSD 模板
点击 “我的” - “资源管理”,上传PSD模板按钮,进入PSD解析上传界面界面。选择或拖入 PSD 文件,等待解析完成后开始编辑,调整好模板后点击右上角“上传模板”,等待完成。
上传完成后点击查看作品即可打开模板,之后在 “我的作品” 中可以找到该模板。
线上为功能测试,资源将被上传到 Github,这在某些网络条件下可能会体验不佳,请确认你的网络环境,必要时科学上网。
由于服务器在国内,生成下载图片可能会图裂,这不是BUG。
AI 抠图
上传需要去除背景的图片,自动抠除背景。在线体验
以上在线体验效果Demo所分配的服务器资源仅1核1G内存,可以看到应付简单抠图场景还是不错的,后续我会另开一篇文章介绍如何部署,感兴趣的话提前关注不迷路~
编辑与设计
快捷键
- 保存:Ctrl / Command + S
- 复制(选中元素):Ctrl / Command + C
- 粘贴:Ctrl / Command + V
- 多选:按住 Shift 或 Ctrl / Command 然后鼠标点选
- 组合成组(多选时):Ctrl / Command + G
文字
画布中双击内容,编辑文字,修改颜色,原生吸色器(Chrome):
图片
除了拖拽缩放图片大小,也可对图像内容进行缩放裁剪,裁剪通常用于截取显示原图像的一部分:
支持拖动图片放置到一个容器中显示:
图层
图层面板中可随意拖动元素快速改变层级,图层锁定后将固定在画布中,此时元素变得不可移动,再次点击按钮即可解锁:
标尺
从标尺栏中拖出辅助线,按住线段拖回标尺栏中删除辅助线
项目架构
编辑界面就不多说了,就是对着稿定设计来,主要说说在保存时的操作,实际保存的是两段JSON内容:
其中 Page 是整个页面的 Schema,而 Widgets 则是扁平化的数组,代表着整个页面中的元素集合,拍平是为了高效直观地实现层级以及查找组件。
保存这些 JSON 后,在绘制页面请求这些信息,然后将页面呈现出来,绘制页移除了画布操作、属性菜单面板等编辑页才有的功能,只保留了基础组件的引入(如果有充足开发成本理论上可尝试采用 SSR 进一步提升速度),并通过一系列方法判断字体、图片、SVG等元素是否加载完毕,一旦整个页面以及资源都加载完成则调用 window 下的广播通知开始截图。
在服务端,我们使用 puppeteer 启动无头浏览器,在 Chrome 中打开绘制页,并往其 BOM 中注入广播通知方法,这样就完成了整个图片生成操作的闭环。
技术栈概括
前端:Vue3 、Vite2 、Vuex 、ElementPlus
图片生成:Puppeteer、Express
服务端:Node.js
一些可独立的功能会被抽取出来作为单独的库引入使用。
组件库 Github 地址:front-end-arsenal | 组件文档网站
前端目录详解
/src
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
| ├── App.vue ├── api // 请求接口管理 ├── assets | ├── data // 数据资源 | ├── fonts // 本地字体资源 | └── styles // CSS 样式文件 ├── common // 存放一些公共方法,例如上传下载、弹窗提示等 | ├── hooks | └── methods ├── components | ├── business // 放置业务组件 | | ├── cropper // 裁剪(暂时弃用) | | ├── image-cutout // 抠图 | | ├── moveable // 操作插件 | | ├── picture-selector // 照片库弹窗选择 | | ├── qrcode // 二维码插件 | | ├── right-click-menu // 右键菜单 | | └── save-download // 保存下载弹窗 | ├── common // 公共组件 | | ├── PopoverTip.vue // 气泡提示组件 | | ├── ProgressLoading // 百分比进度条 | | └── Uploader // 上传组件 | └── modules // 核心模块 | ├── index.ts | ├── layout | | ├── designBoard.vue // 主界面 | | ├── lineGuides.vue // 网格(弃用,由moveable提供辅助线功能) | | ├── sizeControl.vue // 元素操作组件(弃用,由moveable代理) | | └── zoomControl.vue // 缩放画布 | ├── panel // 该目录下的所有文件自动导入项目中 | | ├── components | | ├── stylePanel.vue // 右侧属性编辑面板 | | ├── widgetPanel.vue // 左侧功能菜单面板 | | └── wrap | | ├── BgImgListWrap.vue // 背景选择面板 | | ├── PhotoListWrap.vue // 照片面板 | | ├── TempListWrap.vue // 模板列表 | | ├── ToolsListWrap.vue // 工具面板 | | ├── UserWrap.vue // 我的资源作品面板 | | ├── GraphListWrap.vue // 素材面板 | | ├── CompListWrap.vue // 组合列表(目前主要是文字组合) | | └── TextListWrap.vue // 文字面板 | ├── settings // 放置操作面板下的一些组件 | | ├── EffectSelect // 效果选择(未开发) | | ├── colorSelect.vue // 颜色选择 | | ├── iconItemSelect.vue // icon选择 | | ├── numberInput.vue // 数字输入 | | ├── numberSlider.vue // 数字拖拉 | | ├── textInput.vue // 文字输入 | | ├── textInputArea.vue // 文字域输入 | | └── valueSelect.vue // 下拉选择 | └── widgets // 该目录下的所有文件自动导入项目中 | ├── pageStyle.vue // 背景/页面设置 | ├── wGroup // 组合 | | ├── wGroup.vue | | └── wGroupStyle.vue // 对应右侧面板的操作 | ├── wImage // 图片 | | ├── components | | | └── innerToolBar.vue | | ├── wImage.vue | | └── wImageStyle.vue // 对应右侧面板的操作 | ├── wQrcode // 二维码 | | ├── wQrcode.vue | | └── wQrcodeStyle.vue // 对应右侧面板的操作 | ├── wSvg // 矢量图 | | ├── wSvg.vue | | └── wSvgStyle.vue // 对应右侧面板的操作 | └── wText // 文字 | ├── wText.vue | └── wTextStyle.vue // 对应右侧面板的操作 ├── config.ts // 公共配置 ├── main.ts // 项目入口文件 ├── mixins // 一些公共混合代码,考虑优化 | ├── methods | | ├── DealWithCtrl.ts | | └── keyCodeOptions.ts | ├── mouseDragging.ts | ├── move.ts | └── shortcuts.ts ├── router // vue 路由 | ├── ..... ├── store // Vuex 状态管理器 | ├── index.ts | └── modules | ├── base | | ├── ....... | └── design | ├── ....... ├── types // TS类型配置 | ├── ....... ├── utils // 工具函数目录 | ├── axios.ts | ├── index.ts | ├── plugins | | ├── cssLoader.ts // 异步加载css | | ├── modules.ts // 全局加载公共组件 | | ├── pointImg.ts // 图片点位颜色,测试中 | | ├── preload.ts // 加载资源 | | └── psd // 设计稿解析 | ├── utils.ts | └── widgets | └── elementConfig.ts // 配置全局默认导入的element组件 └── views // 页面目录 ├── Draw.vue // 绘制页 ├── Index.vue // 编辑页(首页) ├── Psd.vue // PSD解析页 └── components
|
由于项目当初开发至一半时才改用 Vue3 重构,所以有部分代码混合了 Options 写法,还请各位大佬不要笑话。
开源感受
早在去年我于年中总结文章里分享这个项目后,就收到不少私信留言表示对项目感兴趣,甚至有要花钱买源码或商业化二次开发的,我都回绝了。当时我的想法是:这个项目能受到关注说明一定是有价值的,那么就不应该封闭起来!
与大多数程序员一样,我开始写前端也是从一段段“胶水”代码开始的,遇到问题的第一反应就是打开浏览器搜索,然后从各种问答与笔记中抽丝剥茧式地尝试解决问题。
后来,代码越写越熟练,各种框架库使用起来得心应手,算得上是初窥门径,有时甚至也能一个人扛起整个前端项目了。当然,项目里通常也包含了几十甚至上百个第三方依赖。
不必感到羞耻,这就是许多公司开发的常态,技术细节的探索与学习是永无止境的,但无法保证效率的话,你可能会先丢掉饭碗,所有插件库都手撸,你可能一个项目都做不出来。
在我一开始做这个项目的时候,没有找到现成的开源可以依猫画虎,最后虽然写完了整个项目,但也走了不少弯路。所以我看到了对项目关注的人,就仿佛看到了曾经的自己,因此决定开源,即使我代码写得再烂,兴许也会有需要的人。
事实上,今年有人基于我的项目二次开发,上线了公司内部的编辑器:
有人正打算在公司的搭建器上增加类似的功能,特地加了我微信向我道谢:
虽然这些都不是我的产出成果,但他们至少不用踩我踩过的坑,留出更多的时间,可以去研究自己热爱的东西,去实现自己某方面的技术追求,最终产出更多的轮子,前端的生态就会越来越好,所有人也就都能从中受益,这也是开源的意义之一。
最后附上在掘金发布的相关技术文章:
使用原生 JS 手写鼠标拖拽效果,纵享丝滑 🔥
浏览器快速实现取色器(颜色吸管)- Chrome
Puppeteer + Nodejs 通用全屏网页截图方案(一)基本功能
Puppeteer + Nodejs 通用全屏网页截图方案(二)常用参数实现
Puppeteer + Nodejs 通用全屏网页截图方案(三)页面处理
Puppeteer + Nodejs 通用全屏网页截图方案(四)项目优化及部署相关
目前项目还在不断完善中,可能有很多的不足之处,代码写得烂,我也是一边学习一边成长。开源不易,如果项目对你有帮助或启发,可以点个 Star 支持一下~ 感谢!
Github 仓库地址: palxiao/poster-design