Сравнение буферов

Я хотел бы сравнить два изображения в памяти, а не полагаться на чтение и запись из файловой системы.

Я могу поступить неправильно, и если да, то я был бы признателен за какой-нибудь намек / помощь.

Я создал репо, демонстрирующее то, что я вижу: https://github.com/philmirez/comparing-screenshots

const puppeteer = require('puppeteer')
const pixelmatch = require('pixelmatch')
const PNG = require('pngjs').PNG
const fs = require('fs')

function getTime(startTime) {
  return Date.now() - startTime
}

async function takeScreenshot(page, options) {
  const startTime = Date.now()
  await page.goto(
    options.url,
    {
      waitUntil: 'networkidle2'
    }
  )
  const totalTime = getTime(startTime)

  await page.setViewport({
    height: options.height,
    width: options.width
  })
  const data = await page.screenshot({
    path: options.path || null,
    fullPage: true
  })

  return {
    data: data,
    time: totalTime
  }
}

async function takeScreenshots(stagingOptions, prodOptions) {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  const staging = await takeScreenshot(page, stagingOptions)
  const prod = await takeScreenshot(page, prodOptions)

  await browser.close();

  return [
    staging,
    prod
  ]
}

const run = async function () {
  try {
    const height = 900
    const width = 640
    const diff = new PNG({width, height})
    const stagingOptions = {
      path: 'stagingScreenshot.png',
      url: 'https://www.google.com/search?q=cat',
      height,
      width
    }
    const prodOptions = {
      path: 'prodScreenshot.png',
      url: 'https://www.google.com/search?q=cat',
      height,
      width
    }
    const [stagingScreenshot, prodScreenshot] = await takeScreenshots(stagingOptions, prodOptions)
    const allocationSize = height * width * 4
    const stagingBuff = Buffer.alloc(allocationSize)
    const prodBuff = Buffer.alloc(allocationSize)
    stagingBuff.fill(stagingScreenshot.data)
    prodBuff.fill(prodScreenshot.data)

    const numDiffPixels = pixelmatch(stagingBuff, prodBuff, diff.data, width, height, { threshold: 0.1 })
    fs.writeFileSync('diff.png', PNG.sync.write(diff))
    console.log('Results', JSON.stringify({
      diffScore: numDiffPixels / (height * width)
    }))
  } catch (error) {
    console.error(error)
  }
}

run()

В результате получается статичное изображение красного цвета.

Оба изображения имеют одинаковые размеры 1101 x 2614.

stagingScreenshot.png:

prodScreenshot.png:

Примечание: одна вещь, которая меня сбила с толку, была, когда я читал pixelmatch/index.js файл, он говорит...

if (img1.length !== width * height * 4) throw new Error('Image data size does not match width/height.')

Я не понимаю, почему ширина и высота умножаются на 4.

2 ответа

Решение

Здесь нужно исправить несколько вещей:

const diff = new PNG({width, height})

Это неправильно, потому что когда вы отправляете ширину и высоту в takeScreenshot, вы используете их для установки viewPort. Но когда вы делаете полноэкранный снимок, результат будет больше, чем это будет.

Поэтому вам следует создать разницу на основе одного из снимков экрана. Что-то вроде этого:

const [stagingScreenshot, prodScreenshot] = await takeScreenshots(stagingOptions, prodOptions)
const prodPng = PNG.sync.read(prodScreenshot.data)
const stgPng = PNG.sync.read(stagingScreenshot.data)
const diff = new PNG({width: prodPng.width, height: prodPng.height})

const numDiffPixels = pixelmatch(prodPng.data, stgPng.data, diff.data, prodPng.width, prodPng.height, { threshold: 0.1 })

Я получал ту же самую ошибку,

      img1.length !== width * height * 4 

было в десять раз меньше, поэтому я обратился к Джимпу: https://www.npmjs.com/package/jimp

      const jimage1 = await Jimp.read(imgBuffer);
const jimage2 = await Jimp.read(imgUrl);
const width = jimage1.bitmap.width;
var diff = Jimp.diff(jimage1, jimage2, .1);
console.log("Percent Difference - ", diff.percent);

Это фактически оболочка для сопоставления пикселей

Другие вопросы по тегам