Sketch网页截屏插件设计开发
1、需求
在Sketch的Artboard中插入网页截图:
1.1、输入网址,自动截图到Artboard中,并居中显示;
1.2、可截取网页局部图片
2、技术选型
技术的选型主要是针对截图功能的选型,插件技术选用sketch-webview-kit。
截图技术主要有phantomjs、puppeteer、html2canvas等技术可以实现截图功能。
phantomjs、puppeteer是 headless 浏览器技术,puppeteer依赖于node,它们的主要区别如下:
html2canvas可以通过获取HTML的某个元素,然后生成Canvas,能让用户保存为图片。
通过需求分析,puppeteer更适合需求,headless + 部分截图,且node的环境更符合前端技术。
确定使用puppeteer构建一个截图的node服务。
node服务框架采用eggjs。egg.js是阿里推出的基于koa的node开发框架,可为截图提供提供稳定的node服务。
3、设计
3.1 架构
构建node基础的框架egg-common-service,在egg-common-service的基础上提供Screenshot截图服务。
Sketch Plugin调取Screenshot截图服务,将web page的截图插入到sketch中。
3.2 流程
用户在Sketch中发起Screenshot指令;
在Sketch WebView界面中输入截图需要的信息,向egg-common-service 发起Screenshot截图服务请求;
egg-common-service Screenshot服务返回截图的base64信息给Sketch WebView;
Sketch WebView将图片base64信息传递给Sketch Plugin;
Sketch Plugin将base64图片绘制在Sketch Artboard中。
3.3 交互设计
交互设计的主要在WebView部分,详细的设计如下:
4、开发
4.1、Sketch Plugin
4.1.1、主要功能代码:
let win = new BrowserWindow({width: 408,height: 356,title:"Web Screen Shot",resizable:false,minimizable:false,maximizable:false,closable:true});win.on('closed', () => {win = null});const Panel = `http://localhost:8000/screenshot.html#${Math.random()}`; win.loadURL(Panel);const closeWin = () =>{win.destroy();win.close();};var contents = win.webContents;//监听webview的事件:webview->plugincontents.on('fromwebview', function(data) {getImageFrame(data);//在ArtBoard中返回回来的base64图片sketch.UI.message("Successfully screenshot and insert into Artboard!");closeWin();});contents.on('closed', function(s) {closeWin();});
4.1.2、请求处理
使用axios进行数据处理:
安装axios:
$ npm install axios
使用:
const axios = require('axios');axios.get('/user', {params: {ID: 12345}}).then(function (response) {console.log(response);}).catch(function (error) {console.log(error);}).then(function () {// always executed });axios.post('/user', {firstName: 'Fred',lastName: 'Flintstone'}).then(function (response) {console.log(response);}).catch(function (error) {console.log(error);});
主要功能代码:
<Spin spinning={spinning} tip="In the screenshot, it takes some time..."><div className={styles.body}><div className={styles.url}><span className={styles.itemName}>ArtBoard Name:</span><Input size={size} className={styles.urlInputCss} value={artBoardName} onChange={this.artBoardNameChange} placeholder={artBoardNamePlaceholder} onBlur={this.artBoardNameOnBulr}/></div><div className={styles.url}><span className={styles.itemName}>Page Url:</span><Input size={size} className={styles.urlInputCss} value={url} onChange={this.urlChange} placeholder={urlPlaceholder}/></div><div className={styles.line}></div><div className={styles.part}><span className={styles.itemName}><Checkbox size={size} className={styles.checkbox} defaultChecked={false} checked={isPart} onChange={this.partChange} disabled={checkboxDisabled}></Checkbox>Page Part:</span><span className={styles.partTips}>get part of page</span><div className={styles.partPannel}><RadioGroup onChange={this.onRadioChange} value={this.state.radioType} disabled={radioDisabled}><Radio className={styles.radioStyle} value={1} defaultChecked={true}><span className={styles.radioName}>Default:</span><Dropdown.Button overlay={menu} size={size} disabled={dropdownDisabled}>{partTypeDefalt.githubcommits.name}</Dropdown.Button></Radio><Radio className={styles.radioStyle} value={2}><span className={styles.radioName}>Custom:</span><Input addonBefore="." size={size} className={styles.urlInputCss} value={partId} onChange={this.partIdChange} placeholder={partIdPlaceholder} disabled={partIdDisabled}/></Radio><div className={partIdDisabled?styles.partIdTips:styles.partIdTipsLight}>the class name of the part</div></RadioGroup></div><div className={styles.line1}></div><div className={styles.buttons}><Button size={size} onClick={this.onCancel} className={styles.button}>{cancel}</Button><Button size={size} onClick={this.insertPage} type="primary" disabled={buttonDisabled}>{button}</Button></div></div></div></Spin>
4.3.1、参考文档
教程
API
1)、目录结构
2)、跨配置
使用egg-cors插件,配置如下:
config/plugin.js
exports.cors = {enable: true,package: 'egg-cors' };
'use strict';module.exports = appInfo => {const config = exports = {}// use for cookie sign key, should change to your own and keep securityconfig.keys = appInfo.name + '_1513779989145_1674'// add your config here// 加载 errorHandler 中间件config.middleware = [ 'errorHandler' ]// 只对 /api 前缀的 url 路径生效// config.errorHandler = {// match: '/api',// } config.rpc = {// registry: {// address: '127.0.0.1:2181',// },// client: {},// server: {}, };config.security = {csrf: {enable: false,},domainWhiteList: [ 'http://localhost:8000' ],}config.cors = {origin: '*',allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH'};config.multipart = {fileExtensions: [ '.apk', '.pptx', '.docx', '.csv', '.doc', '.ppt', '.pdf', '.pages', '.wav', '.mov' ], // 增加对 .apk 扩展名的支持 }return config }
-get请求
let query = this.ctx.query; let name = query.name; let id = query.id;
let query = this.ctx.request.body; let name = query.name; let id = query.id;
this.ctx.body = {code: 0,data: '返回的数据',msg: '错误数据' }
4.3.2、创建egg-common-service
1)、快速生成项目
$ npm i egg-init -g $ egg-init egg-common-service --type=simple $ cd egg-common-service $ npm i
$ npm run dev $ open localhost:700
使用VS Code开发和调试。
1)、调试配置,在egg-common-service根目录下添加.vscode文件夹,向.vscode中添加launch.json,launch.json内容如下:
{// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"type": "node","request": "launch","name": "Egg Debug","runtimeExecutable": "npm","runtimeArgs": ["run","debug"],"console": "integratedTerminal","restart": true,"protocol": "auto","port": 9999},{"type": "node","request": "launch","name": "Egg Debug with brk","runtimeExecutable": "npm","runtimeArgs": ["run","debug","--","--inspect-brk"],"protocol": "inspector","port": 9229},{"type": "node","request": "launch","name": "Egg Test","runtimeExecutable": "npm","runtimeArgs": ["run","test-local","--","--inspect-brk"],"protocol": "auto","port": 9229},{"type": "node","request": "attach","name": "Egg Attach to remote","localRoot": "${workspaceRoot}","remoteRoot": "/usr/src/app","address": "localhost","protocol": "auto","port": 9999}] }
2)、依次点击,进入调试状态
4.4、 Puppeter
4.4.1、Puppeter能做什么?
Puppeteer 是一个通过 DevTools Protocol 控制 headless chrome 的 high-level Node 库,也可以通过设置使用 非 headless Chrome。
我们手工可以在浏览器上做的事情 Puppeteer 都能胜任:
1)、生成网页截图或者 PDF
2)、爬取大量异步渲染内容的网页,基本就是人肉爬虫
3)、模拟键盘输入、表单自动提交、UI 自动化测试
官方提供了一个 playground,可以快速体验一下。关于其具体使用不在赘述,官网的 demo 足矣让完全不了解的同学入门:
const puppeteer = require('puppeteer');(async () => {const browser = await puppeteer.launch();const page = await browser.newPage();await page.goto('https://example.com');await page.screenshot({path: 'example.png'});await browser.close(); })();
4.4.2、安装
Puppeteer有Puppeteer与Puppeteer-Core二个版本,二者区别:
1).Puppeteer-Core在安装时不会自动下载 Chromium
2).Puppeteer-Core忽略所有的PUPPETEER_* env 变量.
使用npm安装:
npm i puppeteer or puppeteer-core
4.4.3、使用
https://www.cnblogs.com/dolphinX/p/7715268.html
http://www.mamicode.com/info-detail-2302923.html
https://blog.csdn.net/asas1314/article/details/81633423
https://www.jianshu.com/p/8e65fdcb6d85
4.4.4、linux下puppeteer使用要点
1)、pupper下载了一个Chromium,但并没有把依赖都装好。于是要自己把so都装好。
官方给的是Ubuntu版本的各个so包的apt-get安装方式,centos版本居然没有放!但是还是有人给出了centos的库名:
#依赖库 yum install pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXtst.x86_64 cups-libs.x86_64 libXScrnSaver.x86_64 libXrandr.x86_64 GConf2.x86_64 alsa-lib.x86_64 atk.x86_64 gtk3.x86_64 -y#字体 yum install ipa-gothic-fonts xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-utils xorg-x11-fonts-cyrillic xorg-x11-fonts-Type1 xorg-x11-fonts-misc -y
修改启动浏览器的代码,加上args:
const puppeteer = require('puppeteer');(async () => {const browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']});const page = await browser.newPage();await page.goto('https://example.com');await page.screenshot({path: 'example.png'});await browser.close(); })();
3)、Macaca-puppeteer
阿里的Macaca也顺势写了Macaca-puppeteer,可以在Macaca上直接写通用的测试用例,在开发机上用图形界面看效果,上服务器走生产。
Macaca顺便还提供了一个基于Ubuntu的Macaca-puppeteer的Docker。
4)、使用await page.waitFor('div.Card');
来等待页面的指定元素加载完成
4.5、Screenshot 功能代码
4.5.1、router.js
'use strict';module.exports = app => {const { router, controller } = app;router.get('/', controller.home.index);router.post('/service/screenshot', controller.screenshot.screenshot); };
4.5.2、新建controller screenshot.js
'use strict';const Controller = require('egg').Controller;class ScreentshotController extends Controller {constructor(ctx) {super(ctx)this.dataValidate = {appkey: { type: 'string', required: true, allowEmpty: false },url: { type: 'string', required: true, allowEmpty: false },isPart: { type: 'boolean', required: true, allowEmpty: false }}}async screenshot() {const { ctx, service } = this// 校验参数ctx.validate(this.dataValidate)// 组装参数const payload = ctx.request.body || {}// 调用 Service 进行业务处理const res = await service.screenshot.screenshot(payload)// ctx.body = res;// 设置响应内容和响应状态码 ctx.helper.success({ctx, res})} }module.exports = ScreentshotController;
4.5.3、新建service screenshot.js
'use strict'const Service = require('egg').Service const puppeteer = require('puppeteer') const fs = require('fs'); const path = require('path'); const images = require("images"); const mineType = require('mime-types'); const APPKEY = "jingwhale"; const partTypeDefalt = {githubcommits:".commits-listing" }; var part = "";class ScreenshotService extends Service {async base64img(file){//生成base64let filePath = path.resolve(file);let data = fs.readFileSync( path.resolve(filePath));let imageData = images(filePath);var backData = {base64: data,width: imageData.width(),height: imageData.height()}backData.base64 = new Buffer(data).toString('base64');return backData;}async screenshot(payload) {const { ctx, service } = thisif(payload.appkey!=APPKEY){ctx.throw(404, 'appkey不正确!');}const browser = await puppeteer.launch();const page = await browser.newPage();var path = 'screenshot.png'var backData = {};var id = payload.idawait page.goto(payload.url);part = page;var partId = payload.partId;if(payload.isPart){if(payload.partType===1){//自定义 console.log(payload.partType)}else{//默认partId = partTypeDefalt[payload.partType];}var partArr = await page.$$(partId);part = partArr[0];}// //调用页面内Dom对象的screenshot 方法进行截图try { // 截图 await part.screenshot({path: path, type: 'png'}).catch(err => {console.log('截图失败'); console.log(err); });}catch (e) { console.log('执行异常'); ctx.throw(404, '执行异常')} finally { await page.close();await browser.close(); }var base64imgData = this.base64img(path)return base64imgData} }module.exports = ScreenshotService
6、总结
技术给我更多的受益是解决问题的方式与思路。
很多重复单一的任务,都可以使用技术解决。
提高效率,留出更多的时间去设计。
Work Smart,Think more,Do Less,Get More.
转载于:https://www.cnblogs.com/jingwhale/p/10664012.html
Sketch网页截屏插件设计开发相关推荐
- Chrome浏览器截屏插件的开发
目 录 第一章 绪论 1 1.1选题背景及意义 1 1.2发展现状研究 2 1.2.1浏览器简介 2 1.2.2 浏览器发展历程 2 1.2.3 浏览器分类 3 1.2.4 chrome浏览器简介 3 ...
- Java实现网页截屏功能(基于phantomJs)
公司最近有个需求:把用户第一次的测量身体信息和最近一次测量信息进行对比,并且需要把对比的数据截成图片可以发给用户(需要在不打开网页的情况下实时对网页进行截图然后保存到服务器上,返回图片地址),通过网上 ...
- JavaScript实现网页截屏方法总结
" 关注『前端开发博客』公众号,回复 加群 " 最近研究了下如何利用JavaScript实现网页截屏,包括在浏览器运行的JS,以及在后台运行的nodeJs的方法.主要看了以下几个: ...
- java 截图_Java实现网页截屏
下面是编程之家 jb51.cc 通过网络收集整理的代码片段. 编程之家小编现在分享给大家,也给大家做个参考. import java.awt.AWTException; import java.awt ...
- java网页截图_Java实现的简单网页截屏功能示例
本文实例讲述了Java实现的简单网页截屏功能.分享给大家供大家参考,具体如下: package awtDemo; import java.awt.AWTException; import java.a ...
- 利用PhantomJS进行网页截屏,完美解决截取高度的问题
利用PhantomJS进行网页截屏,完美解决截取高度的问题 参考文章: (1)利用PhantomJS进行网页截屏,完美解决截取高度的问题 (2)https://www.cnblogs.com/jaso ...
- JavaScript 实现网页截屏五种方法
JavaScript 实现网页截屏五种方法 最近研究了下如何利用JavaScript实现网页截屏,包括在浏览器运行的JS,以及在后台运行的nodeJs的方法.主要看了以下几个: PhantomJS P ...
- JS 实现网页截屏五种方法
最近研究了下如何利用JavaScript实现网页截屏,包括在浏览器运行的JS,以及在后台运行的nodeJs的方法.主要看了以下几个: PhantomJS Puppeteer(chrome headle ...
- 免费的网页截屏API有哪些?
介绍 网页截屏大师使用真正的Chrome浏览器捕捉像素完美的屏幕截图,我们的核心服务托管在阿里云与腾讯云之上,API天然分布式.高可用. 起步 您可以使用 GET 或者 POST 向下面的入口发起一个 ...
最新文章
- wamp配置多少站点
- 一些恶心的代码片段,你看了就知道!
- JQuery源码-------JQuery中数值型变量的判断isNumeric
- C++文件流操作备忘录
- js中实现base64加密、解密
- Java面向对象练习题之字母输出
- hdu-1877(大数+进制转换)
- SetConsoleCtrlHandler() -- 设置控制台信号处理函数
- 字节跳动开发者工具_FAQ | 字节跳动小游游戏发布常见问题汇总
- 早上起床后喝一杯白开水是非常有好处的
- informatica 常见问题及解决方案
- java epub 删除一页_java如何实现批量删除pdf指定的页数
- java keytool下载_JavaJDK自带工具keytool生成ssl证书
- 2018美国计算机科学专业排名,最新出炉 2018年USNews美国大学研究生计算机科学专业排名榜单...
- Dingo Api请求接口404?
- RFID出入库管理是如何实施的
- MYSQL学习整理(4):函数
- Linux的Locale
- 如何定义visit函数_visit函数具体代码是什么啊
- 今年生男孩取什么名好的超简单起名方法
热门文章
- asp.net面试题
- 在 jetson nano 上构建 isaac SDK 示例时出错:JetPack43 未在任何 .rc 文件中定义
- 一款安全好用的SSH客户端工具
- css button自动调整位置_CSS 小技巧
- 海思Hi3516CV200_Camera芯片产品规格书
- 白光干涉衍射实验的计算机仿真,白光干涉_衍射实验的计算机仿真_蓝海江
- GDAL ogr2ogr 转换mif 为sqlite
- python re库 详解(正则表达式)
- Python程序使用os.system()方法调用exe程序导致主程序进程无响应
- XShell常用命令大全