casperjs、resembleに基づく.jsは画素対比サービスを実現する

7000 ワード

いちばん前に書く


今回は、設計原稿とフロントエンドページをピクセル対比するnodeサービスを提供し、テストまたはフロントエンド担当者自身のために補助的なテストを完了することを目的としています.私を信じて、ピクセルレベルの対比の下で、ホームページの設計原稿に対する復元の程度は一気に明らかになります.もしどの子供靴がこの機能である前端のお兄さんのページを測って問題を発見したら、私が提供したこのツール=.=

効果のプレビュー


先行知識


今回は、次の2つのライブラリを補助ツールとして使用しました.
  • casperjs:PhantomJSに基づく作成.内部にはインタフェースのないブラウザが用意されており、簡単に言えば、シミュレータがブラウザを操作する操作をコードの形で行うことができ、マウスの様々なイベントなど、非常に多くの機能があり、今回は主に付属のスクリーンショット機能を使用しています.
  • resemble.js:ピクチャピクセルコントラストツール.呼び出し方法は,2枚の図を入力し,合成図を1枚返し,差分などのコントラストパラメータを付加することと簡単に理解できる.基本的な実装構想は、画像をcanvasに変換した後、その画像画素点を取得し、その後、各画素点を1回比較することと理解できる.

  • だから、サービス全体にはcasperjsを通じてあるサイトに入ってあるページを切り取って、設計図と比較して結果を出すという大きな問題があるはずです.

    全体的な考え方.


    image
    上の図では、大まかな流れを整理することができます.
  • フロントエンドページから設計原稿画像及び切り取る必要のあるウェブサイトアドレスとノード情報
  • を受信する.
  • 設計原稿をimagesフォルダ
  • に保存する
  • サブプロセスを開き、casperjsを起動し、ターゲットサイトの切り取り
  • を完了する.
  • 切り取ってformを要求する.html画像アドレス情報を入力してサーバ
  • に再送する.
  • サービス側が取得する画像情報はresemblejsを介して切り取り図を設計原稿と比較する
  • である.
  • 結果は、フロントエンドページ
  • に戻る.
    この問題の1つは、casperjsでターゲットサイトをスクリーンショットしてサーバに直接情報を返すのではなく、フォームページを開いてフォームの形式で情報を提出することを選択した理由に気づくかもしれません.
    答え:まず私はcasperjsとnodeについてそんなに深く理解していません.私が理解しているのは、まずcasperjsはnodeモジュールではありません.それはオペレーティングシステムの中で走っています.私はまだcasperjsの中でnodeサービスとの通信を確立する方法を発見していません.もし方法があれば、私に教えてください.私は本当にcasperをよく知らないからです.次に通信が確立できないため、私は退くしかありません.次に、casperを通じて私が書いたフォームページをすばやく開き、画像情報を記入してサーバーに返信することで、最初の訴えを完成することができます.だから上にあるんだhtmlの部分の操作.

    実装の詳細


    簡易静的サーバの実装


    indexにかかわるからです.htmlとform.htmlページの戻りは、超簡易な静的サーバを実現する必要があります.コードは次のとおりです.
    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)
                    }
                })
            }
        })
    }
    

    フォームを解析し、イメージフォルダに画像を格納

    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))
                ...
            } 
        })
    

    読み取り可能なストリームを作成してファイル内容を読み出し、pipeを介して所定のパスに書き込むことでアップロードされたピクチャを保存します.

    casperjsの実行

    const { spawn } = require('child_process')
    spawn('casperjs', ['casper.js', filename, captureUrl, selector, id])
    casperjs.stdout.on('data', (data) => {
        ...
    }) 
    

    spawnではサブプロセスを作成してcasperjsを起動し、execなども使用できます.

    図面を切り取って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()
    

    コードは簡単ですが、主なプロセスはページを開き、thenで操作を入力し、runを実行することです.この過程でnodeサービスとの通信方法がよく分からないので、もう一つのページを開くことを選びました.深く研究したいのはcasperjsの公式サイトを見てとても詳しいです!

    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)
    

    これは、私が今得た結果が最初のリクエストに返されるという点に関連しています.最初のリクエストから今まで何度も中継されていたので、最初のリターン体resが見つかりませんでした.グローバルオブジェクトの設定はしばらくしか採用できないと考え、最初のリクエストを受信した後、リクエスト者のipとタイムスタンプを一意idとしてそのオブジェクトに格納するkey、valueは現在のresとする.同時に中継プロセス全体でidが時刻伝達され、最後にresObj[id]が呼び出されることによって最初の戻り体が得られ、データが返される.この方法は最良解とは思いませんが、今は良い方法が思いつかないので、サービス全体を駆け抜けるためにやむを得ないです.新しいアイディアがあればぜひ教えてください!!

    配置


    PhantomJS(osx)のインストール

     : phantomjs-2.1.1-macosx.zip
    
     :/User/xxx/phantomjs-2.1.1-macosx
    
     :~/.bash_profile  
    
    export PATH="$PATH:/Users/xxx/phantomjs-2.1.1-macosx/bin"
    
    terminal :phantomjs --version
    
     
    

    casperjsのインストール

    brew update && brew install casperjs
    

    インストールresemble.js

    cnpm i resemblejs // packjson 
    brew install pkg-config cairo libpng jpeg giflib
    cnpm i canvas //node canvas
    

    Nodeサービス

    git clone https://github.com/Aaaaaaaty/gui-auto-test.git
    
    cd gui-auto-test
    
    cnpm i
    
    cd pxdiff
    
    nodemon server.js
    
     http://localhost:3033/index.html
    

    参考文献

  • PhantomJSインストール
  • casperjsドキュメント
  • resemble.jsドキュメント
  • 最後に


    恒例po作者のブログ、不定期更新中--issuesでの交流を歓迎します.