0

Мне нужно перевести черно-белое изображения в вектор, состоящий из 1 и 0 Написал функцию, которая принимает на вход путь к файлу и возвращает массив из 1 и 0.

function readImg(file) {
    ctx.clearRect(0, 0, draw.width, draw.height);
    var img = new Image(),
        convert = [];
    img.onload = function() {
        ctx.drawImage(img, 0, 0);
        var imgdata = ctx.getImageData(0, 0, draw.width, draw.height).data;
        for (var i = 0; i < img.width * img.height; i++) {
            if (imgdata[i*4] > 0)
                convert.push(0);
            else
                convert.push(1);
        }
    }
    img.src = file;
    return convert;
}

Но вот проблема, если я пытаюсь дальше работать с этим массивом, то его как бы не существует. К примеру:

var temp = readImg("img.png");
console.log(temp.length) //Выведет "0"

Получается, что массив convert возвращается пустым и не успевает заполнится, т.к. функция img.onload еще не выполнилась.

UPD: Прочитал про Promise, попытался прикрутить его к моему коду

function readImg(file) {
    return new Promise(function(resolve, reject) {
        ctx.clearRect(0, 0, draw.width, draw.height);
        var img = new Image(),
            convert = [];
        img.onload = function() {
            ctx.drawImage(img, 0, 0);
            var imgdata = ctx.getImageData(0, 0, draw.width, draw.height).data;
            for (var i = 0; i < img.width * img.height; i++) {
                if (imgdata[i*4] > 0)
                    convert.push(0);
                else
                    convert.push(1);
            }
            resolve(convert);
        }
        img.src = file;
    });
}

Теперь использую эту функцию так

readImg("img.png").then(function (result) {
    console.log(result);
});

Результат выводит правильный, но как мне этот result присвоить другой переменной и использовать дальше? Я хочу использовать это так:

data = [];
for (var i = 0; i < 3; i++) {
    data[i] = [];
    readImg(i + 1 + ".png").then(function (result) {
        data[i][0] = result; //ошибка Uncaught (in promise) TypeError: Cannot set property '0' of undefined
    });
}
RealPeha
  • 411

2 Answers2

1

Проблема. Когда функция выполняется внутри Promise значение внешней переменной i будет другим и его напрямую использовать нельзя. Я передал его как параметр.

Только у меня здесь одна и та же картинка для примера.

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var draw = new Object();
draw.width = ctx.canvas.clientWidth;
draw.height = ctx.canvas.clientHeight;

function readImg(file,num) { return new Promise(function(resolve, reject) { ctx.clearRect(0, 0, draw.width, draw.height); var img = new Image(), convert = []; var myresult = new Object(); myresult.num=num; img.crossOrigin = "Anonymous"; img.onload = function() { ctx.drawImage(img, 0, 0); var imgdata = ctx.getImageData(0, 0, draw.width, draw.height).data; for (var i = 0; i < img.width * img.height; i++) { if (imgdata[i*4] > 0) convert.push(0); else convert.push(1); } myresult.convert=convert; resolve(myresult); } img.src = file; }); }

data = []; for (var i = 0; i < 3; i++) { readImg("https://i.imgur.com/K38QcUh.png",i).then(function (myresult) { local_i=myresult.num; data[local_i] = []; data[local_i].push(myresult.convert); // или data[local_i]=myresult.convert; alert(data[local_i]); }); }

<canvas id="canvas" width="5" height="5" class="playable-canvas"></canvas>
coder675
  • 2,147
  • Спасибо за пример. Это немного приблизило меня к правильному решению, но не до конца. Если я работаю как-то с переменной data дальше, то есть в самом конце вне циклов и функция я пытаюсь её вывести(например) её все еще не существует. Вывод console.log(data.length) в самом конце даст 0. – RealPeha Apr 21 '18 at 16:41
  • Конечно. Чтобы работать с data дальше нужно ждать пока обработаются изображения. – coder675 Apr 21 '18 at 17:59
  • Я понимаю, но как это сделать? Я же не буду засовывать весь код, который в дальнейшем работает с data в функцию-обработчик resolve – RealPeha Apr 21 '18 at 18:03
1

Ну тогда проще сделать так. Вызываем загрузку изображений одной функцией передавая ей список файлов для загрузки. После загрузки первого изображения вызывается загрузка второго и тд. После последнего запускается функция nextcode туда и пишите остальной код.

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var data = [];
var draw = new Object();
draw.width = ctx.canvas.clientWidth;
draw.height = ctx.canvas.clientHeight;

function readImgList(imglist) { ctx.clearRect(0, 0, draw.width, draw.height); var img = new Image(); img.crossOrigin = "Anonymous"; //это нужно только для примера тк изображение загружается с другого домена var k=0; img.onload = function() { ctx.drawImage(img, 0, 0); var imgdata = ctx.getImageData(0, 0, draw.width, draw.height).data; data[k]=[]; for (var i = 0; i < img.width * img.height; i++) { if (imgdata[i*4] > 0) data[k].push(0); else data[k].push(1); } if (k+1<imglist.length) { k=k+1; img.src=imglist[k]; } else { nextcode(); } } img.src = imglist[0]; }

var imglist = []; imglist[0] = "https://i.imgur.com/K38QcUh.png"; imglist[1] = "https://i.imgur.com/K38QcUh.png"; imglist[2] = "https://i.imgur.com/K38QcUh.png"; readImgList(imglist);

function nextcode() { console.log(data); //и сюда пишете весь ваш остальной код }

<canvas id="canvas" width="5" height="5" class="playable-canvas"></canvas>
coder675
  • 2,147