Сравнение буферов
Я хотел бы сравнить два изображения в памяти, а не полагаться на чтение и запись из файловой системы.
Я могу поступить неправильно, и если да, то я был бы признателен за какой-нибудь намек / помощь.
Я создал репо, демонстрирующее то, что я вижу: 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:
Примечание: одна вещь, которая меня сбила с толку, была, когда я читал 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);
Это фактически оболочка для сопоставления пикселей