Home  >  Article  >  Web Front-end  >  Implement a pixel comparison service based on casper.js and resemble.js

Implement a pixel comparison service based on casper.js and resemble.js

小云云
小云云Original
2018-01-11 09:04:051484browse

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:

Summary of Pixel Display Problems in Mobile Terminal Development Tutorials_Experiences and Tips_Web Page Production

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!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn