javascript Canvas Drawimage работает на iPhone? - PullRequest
0 голосов
/ 04 апреля 2020

У меня есть веб-страница, которая загружает изображение со входа и выполняет изменение размера и поворот, чтобы оно всегда было портретным и отображало его на экране. Это работает в настольных браузерах и на android, но не на моих друзьях iPhone.

function showImage(){
var input = document.getElementById("card");
    var filesToUpload = input.files;
    var file = filesToUpload[0];

    var img = document.createElement("img");
    var reader = new FileReader();

    reader.onload = function (e) {
        img.src = e.target.result
    }

    reader.onloadend = function () {
        var canvas = document.createElement("canvas");

        var width = img.width;
        var height = img.height;

        var ctx = canvas.getContext("2d");

        canvas.width = width;
        canvas.height = height;

        ctx.drawImage(img, 0, 0, width, height);

        var imgloc = document.getElementById("cardloc");

        imgloc.appendChild(canvas);

    }
    reader.readAsDataURL(file);}


<input id="card" name="card" type="file" accept="image/*" capture/>
<button type=button id="chooseButton" name="chooseButton" onclick="showImage()">
    Choose A card
</button>
<div id="cardloc"></div>

Это урезанная версия кода без изменения размера и поворота, чтобы продемонстрировать проблему. При работе вы можете видеть, что img.sr c заполняется закодированным изображением, а также canvas.toDataURL () также возвращает закодированное изображение. На iphone img.sr c заполняется, а canvas.toDataURL () нет, всего 6 символов длиной, что не означает, что изображение загружено.

У меня нет идей, кто-нибудь может помочь?

Ответы [ 2 ]

0 голосов
/ 05 апреля 2020

Спасибо за помощь.

Я знал, что звонки были асинхронными. Я просто не заметил, что у img есть загрузка.

Загрузка img происходит после загрузки читателя, и на android это не было проблемой, но с iPhone это было.

Так что мне просто нужно было изменить файл reader.onloaded на img.onload, и все в порядке.

Большое спасибо

0 голосов
/ 05 апреля 2020

Конечно, это так (хотя у меня нет iPhone под рукой).

Проблема здесь в том, что загрузка Image является асинхронной задачей (она выполняется параллельно с JavaScript выполнением). ), даже если источником является data: URL, и вы не можете нарисовать изображение, которое еще не загружено на холст.

Теперь, почему это работает в некоторых браузерах? Потому что вы фактически выполняете чертежную часть тоже асинхронно , но в несвязанном событии.

Базовая структура немного сложна, но в основном FileReader всегда запускает два разных события, когда завершает чтение BLOB-объекта : onerror и onloaded или onload и onloadend , onloadend срабатывает сразу после предыдущего.

Здесь вы устанавливаете src вашего <img> в событии onload, в этот момент браузер начнет загрузку изображения. Поскольку он основан на URL-адресе data: он не имеет большого значения (без сетевого запроса), поэтому, когда запускается второе событие ( onloadend ), оно может фактически уже загрузить изображение и, таким образом, может быть в состоянии нарисовать его на холсте.
Тем не менее, это на самом деле неудача, что он работает.

Правильный способ справиться с этим, это ждать onload вашего изображения event.

reader.onload = function (e) {
  img.onload = function () {

    var canvas = document.createElement("canvas");

    var width = img.width;
    var height = img.height;

    var ctx = canvas.getContext("2d");

    canvas.width = width;
    canvas.height = height;

    ctx.drawImage(img, 0, 0, width, height);

    var imgloc = document.getElementById("cardloc");

    imgloc.appendChild(canvas);

  };
  img.src = e.target.result
}
reader.readAsDataURL(file);

Но вам даже не нужен FileReader, вам лучше использовать blob: URL , который является просто указателем на файл на диске и, таким образом, избегает напрасной траты памяти, а также избегает одного уровня ада обратного вызова:

img.onload = function () {

  var canvas = document.createElement("canvas");

  var width = img.width;
  var height = img.height;

  var ctx = canvas.getContext("2d");

  canvas.width = width;
  canvas.height = height;

  ctx.drawImage(img, 0, 0, width, height);

  var imgloc = document.getElementById("cardloc");

  imgloc.appendChild(canvas);

}
img.src = URL.createObjectURL(file);

Ps: так как вы сказали, что также делаете обрезку, если после этого исправления у вас все еще есть проблемы с Safari, тогда я приглашаю вас прочитать это Q / A о фактической ошибке в этом браузере (что я не могу быть уверен, что вы столкнулись с тем, что вы нам здесь дали).

...