Home > Article > Web Front-end > Implement a pixel comparison service based on casper.js and resemble.js
This time I share a node service that provides pixel comparison between design drafts and front-end pages. It is designed to complete an auxiliary test for testing or front-end personnel themselves. Believe me, under the comparison at the pixel level, the degree of restoration of the design draft on the web page will immediately become apparent. Not much to say below, let’s take a look at the detailed introduction, I hope it can help everyone.
Effect preview
Pre-knowledge
The following two libraries are used as auxiliary tools:
casperjs: written based on PhantomJS. It provides an interfaceless browser internally. Simply put, you can use it to complete the operation of simulating a human to operate the browser in the form of code, which involves various mouse events and many other functions. This time it is mainly used. It comes with a screenshot function.
resemble.js: Image pixel comparison tool. The simple understanding of the calling method is that two images are passed in and a composite image is returned with comparison parameters such as difference and so on. The basic implementation idea can be understood as converting the image to canvas, obtaining its image pixels, and then comparing each pixel.
So we should already have a big idea for the entire service, which is to use casperjs to enter a website to intercept a page, and then compare it with the design drawing to get the result.
Overall idea
We should be able to sort out a rough process through the above picture:
From the front end The page receives the design draft pictures and the website address and node information that need to be intercepted
Save the design draft to the images folder
Start the sub-process, Start casperjs and complete the interception of the target website
After interception, request form.html to fill in the image address information and re-transmit it back to the server
The server obtains the picture information and compares the screenshot with the design draft through resemblejs
The result is sent back to the front-end page
There is a problem Someone may have noticed: Why can't I directly send the information back to the server when I take a screenshot of the target website in casperjs? Instead, I choose to open a form page to submit the information through the form?
Answer: First of all, I don’t know much about casperjs and node. What I understand is that first of all, casperjs is not a node module. It runs in the operating system. I have not yet found out how to create a link with casperjs in casperjs. If there is a way to communicate with the node service, please tell me, because I really don’t know much about casper! Secondly, since communication cannot be established, I can only resort to the next best thing, quickly open a form page I wrote through casper and fill in the image information and send it back to the server. This can complete the initial request. So there is the above operation from.html.
Implementation details
Implementing a simple static server
Because it involves the return of index.html and form.html pages, it is necessary to implement a super Simple static server. The code is as follows:
const MIME_TYPE = { "css": "text/css", "gif": "image/gif", "html": "text/html", "ico": "image/x-icon", "jpeg": "image/jpeg", "jpg": "image/jpg", "js": "text/javascript", "json": "application/json", "pdf": "application/pdf", "png": "image/png", "svg": "image/svg+xml", "swf": "application/x-shockwave-flash", "tiff": "image/tiff", "txt": "text/plain", "wav": "audio/x-wav", "wma": "audio/x-ms-wma", "wmv": "video/x-ms-wmv", "xml": "text/xml" } function sendFile(filePath, res) { fs.open(filePath, 'r+', function(err){ //根据路径打开文件 if(err){ send404(res) }else{ let ext = path.extname(filePath) ext = ext ? ext.slice(1) : 'unknown' let contentType = MIME_TYPE[ext] || "text/plain" //匹配文件类型 fs.readFile(filePath,function(err,data){ if(err){ send500(res) }else{ res.writeHead(200,{'content-type':contentType}) res.end(data) } }) } }) }
Parse the form and store the image in the images folder
const multiparty = require('multiparty') //解析表单 let form = new multiparty.Form() form.parse(req, function (err, fields, files) { let filename = files['file'][0].originalFilename, targetPath = __dirname + '/images/' + filename, if(filename){ fs.createReadStream(files['file'][0].path).pipe(fs.createWriteStream(targetPath)) ... } })
Read the file content by creating a readable stream, and then write it to the specified path through pipe. Uploaded pictures can be saved.
Run casperjs
const { spawn } = require('child_process') spawn('casperjs', ['casper.js', filename, captureUrl, selector, id]) casperjs.stdout.on('data', (data) => { ... })
You can create a child process to start casperjs through spawn, and you can also use exec, etc.
Screenshot and submit the data to form.html
const system = require('system') const host = 'http://10.2.45.110:3033' const casper = require('casper').create({ // 浏览器窗口大小 viewportSize: { width: 1920, height: 4080 } }) const fileName = decodeURIComponent(system.args[4]) const url = decodeURIComponent(system.args[5]) const selector = decodeURIComponent(system.args[6]) const id = decodeURIComponent(system.args[7]) const time = new Date().getTime() casper.start(url) casper.then(function() { console.log('正在截图请稍后') this.captureSelector('./images/casper'+ id + time +'.png', selector) }) casper.then(function() { casper.start(host + '/form.html', function() { this.fill('form#contact-form', { 'diff': './images/casper'+ id + time +'.png', 'point': './images/' + fileName, 'id': id }, true) }) }) casper.run()
The code is relatively simple. The main process is to open a page, then pass your operation in then, and finally execute run . During this process, I didn't quite know how to communicate with the node service, so I chose to open another page. . If you want to study in depth, you can check out the official website of casperjs which is very detailed!
Perform pixel comparison and return data through resemble.js
function complete(data) { let imgName = 'diff'+ new Date().getTime() +'.png', imgUrl, analysisTime = data.analysisTime, misMatchPercentage = data.misMatchPercentage, resultUrl = './images/' + imgName fs.writeFileSync(resultUrl, data.getBuffer()) imgObj = { ... } let resEnd = resObj[id] // 找回最开始的res返回给页面数据 resEnd.writeHead(200, {'Content-type':'application/json'}) resEnd.end(JSON.stringify(imgObj)) } let result = resemble(diff).compareTo(point).ignoreColors().onComplete(complete)
This involves a point, that is, the result I get now needs to be returned to the original request, and I have been redirected many times from the initial request to now, so now I can't find my original return body res. After thinking about it for a long time, I can only temporarily set the global object. After receiving the initial request, set the requester's IP and timestamp as a unique ID and store it as the key of the object, and the value is the current res. At the same time, the id is passed all the time during the entire transfer process, and finally the initial return body and data are obtained by calling resObj[id]. I don't think this method is the optimal solution, but since I can't think of a good way now, I have to do it in order to run through the entire service. . If you have any new ideas, please let us know! !
Deployment
Install PhantomJS (osx)
Official website download: phantomjs-2.1.1-macosx.zip
Decompression path :/User/xxx/phantomjs-2.1.1-macosx
Add environment variables: Add
export PATH="$PATH:/Users/xxx/phantomjs- in the ~/.bash_profile file 2.1.1-macosx/bin"
Terminal input: phantomjs --version
If you can see the version number, the installation is successful
Install casperjs
brew update && brew install casperjs
Install resemble.js
cnpm i resemblejs //已写进packjson可不用安装 brew install pkg-config cairo libpng jpeg giflib cnpm i canvas //node内运行canvas
node service
git clone https://github.com/Aaaaaaaty/gui-auto-test.git cd gui-auto-test cnpm i cd pxdiff nodemon server.js
Open http://localhost:3033/index.html
related suggestion:
Css Sample Code to Implement a 0.5 Pixel Border
Detailed introduction to resolution, pixels and PPI
The above is the detailed content of Implement a pixel comparison service based on casper.js and resemble.js. For more information, please follow other related articles on the PHP Chinese website!