HTML5 — неожиданные результаты с холстом drawImage

Я просто изучаю, как использовать элемент холста HTML5. Мне удалось нарисовать прямоугольники, вызвать getImageData, манипулировать пикселями, а затем putImageData, чтобы увидеть, как прямоугольники меняют цвет, и т. д.

Теперь я пытаюсь загрузить изображение на холст, я попал в затруднительное положение. После вызова drawImage в контексте холста fillRect рисует только области, в которых нет изображения, например, рисует прямоугольники за изображениями, даже если он вызывается после drawImage. Кроме того, putImageData перестает работать, даже на видимых областях, содержащих прямоугольники, мои манипуляции с пикселями больше не происходят. Если я закомментирую строку с помощью drawImage, она снова сработает.

Что я хочу сделать, так это манипулировать пикселями изображения так же, как я делал с прямоугольниками. Есть ли причина, по которой это не сработает?

Нарисуйте код изображения:

var img = new Image();
img.onload = function () {
     //comment out the following line, everything works, but no image on canvas
     //if it's left in, the image sits over the rectangles, and the pixel
     //manipulation does not occur
     context.drawImage(img, 0, 0, width / 2, height / 2);
}
img.src = path;

Код рисования прямоугольников:

for (var i = 0; i < amount; i++)
{
    x = random(width - size);
    y = random(height - size);
    context.fillStyle = randomColor();
    context.fillRect(x, y, size, size);
}

Манипулировать кодом пикселей:

var imgd = context.getImageData(0, 0, width, height);
var pix = imgd.data;

//loop through and do stuff

context.putImageData(imgd, 0, 0);

person Chris Johnson    schedule 22.09.2011    source источник
comment
Не совсем уверен, но это может быть побочным эффектом междоменной проблемы. Изображение, которое вы используете, размещено в том же домене, что и остальная часть вашего кода?   -  person Jani Hartikainen    schedule 22.09.2011
comment
Спасибо за предложение, но я не думаю, что это может быть проблемой, поскольку файлы находятся в локальной папке.   -  person Chris Johnson    schedule 23.09.2011
comment
Нет, я был неправ. По-видимому, локальные файлы обрабатываются иначе, чем файлы, размещенные на веб-сервере, что вызывало исключение безопасности. Спасибо Яни.   -  person Chris Johnson    schedule 23.09.2011


Ответы (2)


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

  1. Вы где-нибудь меняете globalCompositeOperation?
  2. randomColor() делает цвета слишком прозрачными, чтобы их можно было увидеть?
  3. Есть ли какая-то область отсечения, которую вы не упомянули?
  4. Вы рисуете все в правильном контексте?
  5. Есть ли орфографическая ошибка, которая останавливает выполнение и вызывает ошибку?
  6. Возможно, ваша последовательность событий неверна. Вы можете загружать изображение, затем рисовать прямоугольники, а затем завершать загрузку изображения, чтобы оно выглядело так, как будто прямоугольники были нарисованы за вашим изображением, когда это было просто естественным порядком вещей.
  7. Вызывает ли putImageData ошибку безопасности (проще увидеть в Firefox), потому что на холст было нарисовано изображение из другого домена? Эта ошибка может остановить выполнение всего последующего кода рисования и, следовательно, привести к описанному вами эффекту. Проверьте, не нарушаете ли вы один из эти правила. В частности, рисование изображения на холсте из другого источника, а затем попытка использования getImageData.

Скорее всего, это последний или предпоследний пункт в моем списке, который вас огорчает.

Попробуйте разместить изображение на своем собственном сервере и посмотрите, исчезнет ли оно, или посмотрите на веб-консоль в Firefox, чтобы узнать, жалуется ли оно на ошибку безопасности.

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

person Simon Sarris    schedule 22.09.2011
comment
Большое спасибо за ответ. Ты получил это. 6. Очевидно, img.onload сработает после того, как мои квадраты будут нарисованы! 7. Я получаю сообщение об ошибке безопасности на getImageData. Я посмотрю на правила, которые вы связали. - person Chris Johnson; 23.09.2011

Хорошо, Саймон наставил меня на правильный путь. Похоже, что браузеры обрабатывают файлы из локальной файловой системы иначе, чем файлы с веб-сервера, в частности, файлы изображений помечаются как origin-clean = false. Это вызывало исключение безопасности (NS_ERROR_DOM_SECURITY_ERR 1000), когда я пытался вызвать getImageData в контексте после рисования изображения.

Решение 1 — разместить файлы на веб-сервере.

Решение 2 немного взломано, но для моих целей оно подходит:

try {
    try { 
        var imgd = context.getImageData(0, 0, width, height); 
    } catch (e) { 
    netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
        var imgd = context.getImageData(0, 0, width, height);
    }
} catch (e) {throw new Error("unable to access image data: " + e)}

Если выдается исключение безопасности, браузер запросит у пользователя разрешение на переопределение.

person Chris Johnson    schedule 23.09.2011