Метод из библиотеки png js странно действует в Node.js - PullRequest
2 голосов
/ 10 июля 2020

Я упорядочиваю изображения по значению score , вычисленному с помощью метода 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)

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

1 Ответ

1 голос
/ 13 июля 2020

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...