Но здесь мы опять сталкиваемся с деталями реализации песочницы в браузере. Когда картинка грузится с URL с другого домена, если ответ сервера не содержит заголовок, разрешающий использование ресурса с других доменов (см. главу 17), холст будет содержать информацию, которая будет видна пользователю, но не видна скрипту.
Мы могли запросить картинку с приватной информацией (график изменений банковского счёта). Если бы скрипт мог получить к ней доступ, он мог бы шпионить за пользователем.
Для предотвращения таких утечек информации, когда картинка, невидимая скрипту, будет загружена на холст, браузеры пометят его как «испорчен». Пиксельные данные, включая URL с данными, нельзя будет получить с «испорченного» холста. На него можно писать, но с него нельзя читать.
Поэтому нам нужна обработка >try/catch
в функции >update
для ссылки сохранения. Когда холст «портится», вызов >toDataURL
выбросит исключение, являющееся экземпляром >SecurityError
. В этом случае мы перенаправляем ссылку на ещё один вид URL с протоколом javascript:. Такие ссылки просто выполняют скрипт, стоящий после двоеточия, и наша ссылка покажет предупреждение, сообщающее о проблеме.
Последние два элемента управления используются для загрузки картинок с локального диска и с URL. Нам потребуется вспомогательная функция, которая пробует загрузить картинку с URL и заменить ею содержимое холста.
>function loadImageURL(cx, url) {
> var image = document.createElement("img");
> image.addEventListener("load", function() {
> var color = cx.fillStyle, size = cx.lineWidth;
> cx.canvas.width = image.width;
> cx.canvas.height = image.height;
> cx.drawImage(image, 0, 0);
> cx.fillStyle = color;
> cx.strokeStyle = color;
> cx.lineWidth = size;
> });
> image.src = url;
>}
Нам надо поменять размер холста, чтобы он соответствовал картинке. Почему-то при смене размера холста его контекст забывает все настройки (>fillStyle
и >lineWidth
), в связи с чем функция сохраняет их и загружает обратно после обновления размера холста.
Элемент управления для загрузки локального файла использует технику >FileReader
из главы 18. Кроме используемого здесь метода >readAsText
у таких объектов есть метод под названием >readAsDataURL
– а это то, что нам нужно. Мы загружаем файл, который пользователь выбирает, как URL с данными, и передаём его в >loadImageURL
для вывода на холст.
>controls.openFile = function(cx) {
> var input = elt("input", {type: "file"});
> input.addEventListener("change", function() {
> if (input.files.length == 0) return;