Метод из библиотеки pngjs странно действует в Node.js

Я упорядочиваю изображения по баллу, рассчитанномуgetImageScore, который заключен в обещание, так как загрузка пикселей, с которыми он должен работать, занимает довольно много времени. Я заметил, что обещания блокируются, никогда не выполняются. Это была начальная вся программа:

const fs = require('fs');
const { resolve } = require('path');
const { reject } = require('q');
const { Console } = require('console');
const gm = require('gm').subClass({imageMagick: true});
const PNG = require("pngjs").PNG;
let pathToFolder = '/home/eugen/Pictures/wallpapers1';
let pathToImage = '';

let promiseImageScore = new Promise((resolve, reject) => {
  getImageScore(resolve, reject);
});

function getImageScore(resolve, reject) {
  console.log('entered this promise....');
  let img = gm(pathToImage);
  // Get the PNG buffer
  img.toBuffer("PNG", (err, buff) => {
    if (err) return reject(err);
    console.log('got buffer...');
    // Get the image size
    img.size((err, size) => {
      if (err) {
        console.log(err);
        return reject(err);
      }
      console.log('got image size...');
      // Parse the PNG buffer
      let str = new PNG();
      str.end(buff);
      // After it's parsed...
      str.on("parsed", buffer => {
        // Get the pixels from the image
        let idx, score = 0, rgb = {r: 0, g: 0, b: 0};

        for (let y = 0; y < size.height; y++)
          for (let x = 0; x < size.width; x++) {
            idx = (size.width * y + x) << 2;
            rgb.r = buffer[idx];
            rgb.g = buffer[idx + 1];
            rgb.b = buffer[idx + 2];
            score += (rgb.r + rgb.g + rgb.b) / 765;
          }
          console.log('one promise finished...');
          return resolve(score / (size.height * size.width));
      });
      str.on("error", e => {
        return reject(e);
      });
    });
  });
}

// see which images are to be found in the specificd directory
fs.readdir(pathToFolder, function (err, files) {
    if (err) return console.log('Unable to scan directory: ' + err);
    console.log('files in directory:\n');
    files.forEach(function (file) {
        pathToImage = pathToFolder + '/' + file;
        //showImageScore();
        promiseImageScore
        .then(imageScore => {
          console.log(file + ' has a score of ' + imageScore);
        })
        .catch(e => {
          throw e;
        })
    });
});

Выполнение приведенного выше кода приведет к следующему выводу:

entered this promise....
files in directory:

got buffer...

После регистрации got buffer сообщение, программа просто будет работать непрерывно... Я увидел, что, изменив способ обращения к изображениям, я наконец-то получил got image sizeвойдите в консоль. Таким образом, вот как я изменилgetImageScore метод:

function getImageScore(resolve, reject) {
  console.log('entered this promise....');
  //let img = gm(pathToImage);
  // Get the PNG buffer
  //img.toBuffer("PNG", (err, buff) => {
  gm(pathToImage).toBuffer("PNG", (err, buff) => {
    if (err) return reject(err);
    console.log('got buffer...');
    // Get the image size
    //img.size((err, size) => {
    gm(pathToImage).size((err, size) => {
      if (err) {
        console.log(err);
        return reject(err);
      }
      console.log('got image size...');
      // Parse the PNG buffer
      let str = new PNG();
      console.log('created str...');
      str.end(buff);
      console.log('got str...');
      // After it's parsed...
      str.on("parsed", buffer => {
        // Get the pixels from the image
        let idx, score = 0, rgb = {r: 0, g: 0, b: 0};

        for (let y = 0; y < size.height; y++)
          for (let x = 0; x < size.width; x++) {
            idx = (size.width * y + x) << 2;
            rgb.r = buffer[idx];
            rgb.g = buffer[idx + 1];
            rgb.b = buffer[idx + 2];
            score += (rgb.r + rgb.g + rgb.b) / 765;
          }
          console.log('one promised finished...');
          return resolve(score / (size.height * size.width));
      });
      str.on("error", e => {
        return reject(e);
      });
    });
  });
}

После внесения этих изменений я получаю в консоли следующий вывод:

entered this promise....
files in directory:

got buffer...
got image size...
created str...
events.js:174
      throw er; // Unhandled 'error' event
      ^

Error: Invalid file signature
    at module.exports.Parser._parseSignature (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/parser.js:53:18)
    at module.exports.ChunkStream._processRead (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/chunkstream.js:174:13)
    at module.exports.ChunkStream._process (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/chunkstream.js:193:14)
    at module.exports.ChunkStream.write (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/chunkstream.js:61:8)
    at module.exports.ChunkStream.end (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/chunkstream.js:74:10)
    at exports.PNG.PNG.end (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/png.js:98:16)
    at gm.size (/home/eugen/Documents/scripts/sort_pictures_by_brightness/index.js:34:11)
    at gm.emit (events.js:198:13)
    at gm.<anonymous> (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/gm/lib/getters.js:82:14)
    at cb (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/gm/lib/command.js:322:16)
Emitted 'error' event at:
    at module.exports.emit (events.js:198:13)
    at module.exports.ChunkStream._process (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/chunkstream.js:207:10)
    at module.exports.ChunkStream.write (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/pngjs/lib/chunkstream.js:61:8)
    [... lines matching original stack trace ...]
    at cb (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/gm/lib/command.js:322:16)
    at ChildProcess.onExit (/home/eugen/Documents/scripts/sort_pictures_by_brightness/node_modules/gm/lib/command.js:305:9)

Глядя на результат, мы можем сказать, что str.end(buff); есть какая-то проблема, так как программа никогда не выводит got strжурнал. Похоже, этой проблемы не существовало до внесения изменений, которые я внес вgetImageScoreметод. Во-первых, я действительно не понимаю, почему загрузка изображения в локальный объект может стать проблемой, которая может привести к неожиданному срабатыванию кода. Во-вторых, изменение способа загрузки изображения не должно изменятьend метод из pngjsбиблиотека. Может ли кто-нибудь объяснить, что здесь происходит на самом деле и как можно исправить эту проблему?

1 ответ

Решение

К счастью, кто-то из Facebook (Юлиан Попеску) сказал мне, что files.forEachне ждет завершения обещаний, поэтому они блокируются. Мне удалось решить эту ситуацию, добавив еще обещаний. Например, одно из обещаний считывает все данные. После чтения всех данных и сохранения их в некоторых глобальных переменных другие обещания будут выполнены в правильном порядке. Если вы действительно хотите увидеть реализацию решения, о котором я говорю, вы можете проверить его на моем GitHub: https://github.com/tomaAlex/darkImageClassifier/blob/master/index.js

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