LoginSignup
3
0

More than 3 years have passed since last update.

E2Eテスト 番外編 -シャープで画像連結-

Last updated at Posted at 2020-10-23

前回の記事では、reg-cliを使った画像差分比較について紹介しました。
E2Eテストの始め方 番外編 - reg-cliで差分比較 -
そして今回は、TestCafeで撮影した複数枚のスクリーンショット画像を連結するためのsharpについて書いていきたいと思います。

sharp とは

某電機メーカーが強すぎてググラビリティが残念なライブラリ。。。:weary:
同じようなライブラリとしてImageMagickやGraphicsMagickも有名ですが、ドキュメントによるとそれらより4倍~5倍速いそうです。
読み込みはJPEG,PNG,WebP,TIFF,GIF,SVGをサポート。
様々なサイズのJPEG,PNG,WebPに変換可能で、リサイズ以外に回転、抽出、合成、ガンマ補正、圧縮などの操作も可能となっています。
今回sharpを選んだ理由としてImageMagickらはしばらくメンテナンスされていない(sharpは執筆時点で10h前と活発に動いてる)ことと、処理の速さでsharpを採用しました。

シャープならサイズも画質も自由に選べる!
sharp.png

install

$ npm install sharp

usage

convert.js
const sharp = require('sharp');

【ソース全文】

convert.js

const fs = require('fs')
const config = require('../config')
const { imgPath, imgPc, imgSp  } = config;

//出力先フォルダの作成
const makeDir = () => {
  fs.mkdir('screenshots/convert', { recursive: true }, (err) => {
    if (err) throw err;
  });
}

//sharp
const convert = async (imagePaths, imageName) => {
  const imageAttrs = [];

  // 連結する画像の情報取得
  const promises = [];
  const imagePromise = path =>
    new Promise(async resolve => {
      const image = await sharp(path);
      let width = 0,
          height = 0;
      await image
        .metadata()
        .then(meta => ([width, height] = [meta.width, meta.height]));
      const buf = await image.toBuffer();
      resolve({ width, height, buf });
    });
  imagePaths.forEach(path => promises.push(imagePromise(path)));
  await Promise.all(promises).then(values => {
    values.forEach(value => imageAttrs.push(value));
  });

  // outputする画像の設定
  const outputImgWidth = imageAttrs.reduce((acc, cur) => acc + cur.width, 0);
  const outputImgHeight = Math.max(...imageAttrs.map(v => v.height));
  let totalLeft = 0;
  const compositeParams = imageAttrs.map(image => {
    const left = totalLeft;
    totalLeft += image.width;
    return {
      input: image.buf,
      //合成場所
      gravity: "northwest",
      left: left,
      top: 0
    };
  });

  // 連結処理
  sharp({
    create: {
      width: outputImgWidth,
      height: outputImgHeight,
      channels: 4,
      background: { r: 255, g: 255, b: 255, alpha: 0 }
    }
  })
    //合成
    .composite(compositeParams)
    //圧縮
    .png({
      quality: 80,
      compressionLevel: 9
    })
    .toFile(`screenshots/convert/${imageName}.png`,(err, info)=>{
      if(err){ throw err }
      console.log(info)
    });
}

(async () => {
  await
    makeDir()
    convert(imgPc, 'pc')
    convert(imgSp, 'sp')
})()

解説

まず、出力先のフォルダを作成します。
フォルダがないと「どこに保存するのか分からないよ!」と怒られてしまうので、sharpを実行する前にフォルダを用意してあげます。

convert.js
//出力先フォルダの作成
const makeDir = () => {
  fs.mkdir('screenshots/convert/corporate', { recursive: true }, (err) => {
    if (err) throw err;
  });
}

画像の情報取得や連結処理などのソースはこちらを参考にさせていただきました。
NodeJSの画像処理ライブラリ「sharp」を使って画像を連結する

私は、連結したい画像がたくさんあるためconfig.jsに画像パスの配列を記述し呼び出して使っています。
第一引数imagePathsに呼び出した画像パスの配列imgPcimgSpを指定し、
第二引数のimageNameには出力される画像のファイル名を指定します。
(デフォルトのピクセル制限(268402689)を超えてしまうので複数枚に分けて出力しています)

convert.js
const config = require('../config')
const { imgPath, imgPc, imgSp  } = config;

const convert = async (imagePaths, imageName) => {

 .toFile(`screenshots/convert/corporate/${imageName}.png`,(err, info)=>{
  });
}

(async () => {
  await
    convert(imgPc, 'pc')
    convert(imgSp, 'sp')
})()
config.js
const imgDir = `screenshots/${year}${month}${date}/`

exports.imgPc = [
  `${imgDir}/top_pc.png`,
  `${imgDir}/company_pc.png`,
  `${imgDir}/company_access_pc.png`,
];
exports.imgSp = [
  `${imgDir}/top.png`,
  `${imgDir}/company.png`,
  `${imgDir}/company_access.png`,
];

圧縮

生成された画像の圧縮も設定可能です。

jpeg
convert.js
.jpeg({
  quality: 80
})

options.quality:整数1〜100,デフォルト80
options.compressionLevel:zlib圧縮レベル、0〜9(デフォルト9)

png
convert.js
.png({
  quality: 100,
  compressionLevel: 9
})

options.quality:デフォルト100
options.compressionLevel:zlib圧縮レベル、0〜9(デフォルト9

webp
convert.js
.webp({
    quality: 80,
    lossless: true
})

options.quality:整数1〜100,デフォルト80
options.lossless:可逆圧縮モード,デフォルトfalse

このほか、gifやtiff,heifも対応可能でオプションで細かい設定もできるので詳細は公式をご覧ください。
https://sharp.pixelplumbing.com/api-output

実行

$ node e2e/convert.js

完成!

横並びにがっちゃんこして出力してくれました!
各ページフルサイズのスクリーンショットを連結させると出力サイズがかなり大きくなるので圧縮率を大きくしたり、連結枚数を少なくして何枚かに分けるなど工夫が必要ですが良い感じにできたのではないかと思います:ok_hand:
sample.png

参考

NodeJSの画像処理ライブラリ「sharp」を使って画像を連結する

公式

sharp
GitHub

SHARP Be Original

SHARP

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0