Загружать несколько изображений холста через цикл javascript

Я пытаюсь создать сценарий загрузки, который изменяет размер клиентской части нескольких изображений до того, как файл saveimage.php обработает их. Причина этого в том, что они будут загружены в другом месте, где может быть очень медленный интернет.

Мне удалось найти здесь фрагменты кода, которые помогли мне собрать все вместе. Я всего лишь новичок, поэтому, наверное, это очень грязно!

В настоящее время он проверяет, когда файлы вводятся в поле «file_input». Затем он просматривает количество файлов и просматривает их до тех пор, пока каждый файл не будет помещен в холст и не будет загружен, пока он там.

Однако проблема заключается в следующем: когда я не добавляю предупреждение для каждого файла, цикл идет слишком быстро и обрабатывает только 1 или 2 из 10 изображений. Поскольку сценарий загрузки будет работать быстрее, чем холст может быть обновлен с новым изображением.

Это моя текущая страница, упрощенная до ядра:

<!DOCTYPE html> <html> <head> <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script> </head> <body> <form> <input id="file_input" type='file' multiple /> </form> <div id="preview"> <canvas id="canvas"></canvas> </div> <script> var input = document.getElementById('file_input'); input.addEventListener('change', handleFiles); function handleFiles(e) { var files = input.files; alert(files.length +" files are being uploaded!"); // display amount of files for testing purpose for (var i = 0; i < files.length; ++i) { alert("Upload file number: "+i); // display file # for testing purpose, when this is removed the script will go too fast var MAX_HEIGHT = 1000; var ctx = document.getElementById('canvas').getContext('2d'); var img = new Image; img.onload = function(){ if(img.height > MAX_HEIGHT) { img.width *= MAX_HEIGHT / img.height; img.height = MAX_HEIGHT; } var ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, canvas.width, canvas.height); preview.style.width = img.width + "px"; preview.style.height = img.height + "px"; canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height); // the canvas should contain an image now and this will send it through saveimage.php var myDrawing = document.getElementById("canvas"); var drawingString = myDrawing.toDataURL("image/jpeg", 0.5); var postData = "canvasData="+drawingString; var ajax = new XMLHttpRequest(); ajax.open("POST",'saveimage.php',true); ajax.setRequestHeader('Content-Type', 'canvas/upload'); ajax.onreadystatechange=function() { if (ajax.readyState == 4); } ajax.send(postData); }; img.src = URL.createObjectURL(e.target.files[i]); } } </script> </body> </html> 

И это мой saveimage.php, который хорошо работает, но только для полного обзора:

 <?php if (isset($GLOBALS["HTTP_RAW_POST_DATA"])) { $rawImage=$GLOBALS['HTTP_RAW_POST_DATA']; $removeHeaders=substr($rawImage, strpos($rawImage, ",")+1); $decode=base64_decode($removeHeaders); // check if the file already exists and keep adding +1 intil it's unique $i = 1; while(file_exists('uploads/image'.$i.'.jpg')) { $i++; } $fopen = fopen( 'uploads/image'.$i.'.jpg', 'wb' ); fwrite( $fopen, $decode); fclose( $fopen ); } ?> 

Немного дополнительной информации:

  • Я добавил холст, потому что, насколько я понимаю, это единственный способ изменить размер клиентской части изображений. В финальном скрипте он будет скрыт.
  • Если холст может быть пропущен, и данные, отправленные на saveimage.php, немедленно, то это тоже решит проблему.
  • Как я уже сказал, я не очень разбираюсь в javascript, поэтому, если есть гораздо более простой способ достичь этой цели. Пожалуйста, дайте мне знать!

Заранее спасибо!

JavaScript загружает изображение асинхронно. Это означает, что после того, как ему назначено новое изображение .src, он начнет загрузку изображения, но одновременно продолжит обработку javascript после .src, пока изображение занимает время для загрузки.

Вы используете одну и ту же переменную изображения ( var img ) внутри цикла for. Поэтому каждый раз через цикл вы переписываете предыдущий img до того, как предыдущее изображение было полностью загружено.

Вот загрузчик изображений, который полностью загружает все изображения, а затем вызывает функцию start (), где вы можете выполнить обработку:

 // image loader // put the paths to your images in imageURLs[] var imageURLs=[]; imageURLs.push("myImage1.png"); imageURLs.push("myImage2.png"); // etc, etc. // the loaded images will be placed in imgs[] var imgs=[]; var imagesOK=0; loadAllImages(start); function loadAllImages(callback){ for (var i=0; i<imageURLs.length; i++) { var img = new Image(); imgs.push(img); img.onload = function(){ imagesOK++; if (imagesOK>=imageURLs.length ) { callback(); } }; img.onerror=function(){alert("image load failed");} img.crossOrigin="anonymous"; img.src = imageURLs[i]; } } function start(){ // the imgs[] array now holds fully loaded images // the imgs[] are in the same order as imageURLs[] } 

В обратном вызове onload используйте this ключевое слово (вместо img ) для текущего изображения, img может / будет перезаписываться в цикле for до срабатывания обратного вызова.
img.height --> this.height т. д.
Также есть причина, по которой вы используете настраиваемый тип контента вместо application/x-www-form-urlencoded ?
Данные с кодировкой в ​​Url намного легче работать.

Некоторое время я боролся с той же проблемой, но я, наконец, объединил другое решение, используя бит кода от других, которые решили эту проблему, и это работает. Это может быть не идеально, и я бы приветствовал любые предложения по улучшению. Понятие состоит в том, что у вас есть две функции Javascript, которые являются идентификаторами Resize0 и Resize1, и они называют друг друга до тех пор, пока все фотографии не будут изменены, тогда функция, которая изменит размер последнего изображения, отправит форму. Две функции передают параметры между собой, чтобы один из них знал, когда отправлять форму. Два из этих параметров: Number_Of_Images и текущий Image_Number. Вы также можете загрузить рабочую веб-страницу примера с http://www.wantitconsulting.co.nz/ExampleResizeUpload.zip . Вам нужно будет создать папку в базовом каталоге вашего тестового веб-сайта для изображений, в которые нужно войти. Имя папки – TestResizeUpload. На стороне сервера используется php.

У меня была одна и та же проблема, но мне удалось это сделать, сначала отобразив все изображения в скрытом теге «img», взяв в качестве ссылки этот пост « HTML5 для отображения загруженного изображения до того, как он будет загружен? », И после этого я активировать функцию с помощью дополнительной кнопки, которая использует последние созданные изображения и нарисовать их все в отдельном холсте, которые также были созданы одновременно с изображениями, где загружаются, код будет таким, как это

html:

 <form> <input type="file" id="files" name="files[]" multiple /> <button type="button" id="run">Run</button> </form> <div id="preview"> <output id="list"></output><br> <output id="list2"></output><br> <div id="status"></div> </div> 

Сценарий:

 document.getElementById('files').addEventListener('change', handleFileSelect,false); document.getElementById('run').addEventListener('click', read); function handleFileSelect(evt) { var files = evt.target.files; // FileList object // Loop through the FileList and render image files as thumbnails. for (var i = 0, f; f = files[i]; i++) { // Only process image files. if (!f.type.match('image.*')) { continue; } var reader = new FileReader(); // Closure to capture the file information. reader.onload = (function(theFile) { return function(e) { // Render thumbnail. var span = document.createElement('span'); span.innerHTML = ['<img class="thumb" name="forms" src="', e.target.result, '" title="', escape(theFile.name), '"/ hidden>'].join(''); document.getElementById('list').insertBefore(span, null); var span = document.createElement('span'); span.innerHTML = ['<canvas></canvas>'].join(''); document.getElementById('list2').insertBefore(span, null); }; })(f); // Read in the image file as a data URL. reader.readAsDataURL(f); } } function read() { imgs = document.getElementsByName('forms'); canvas = document.getElementsByTagName("canvas"); for (var i = 0; i < imgs.length; ++i) { ctx[i] = canvas[i].getContext("2d"); ctx[i].clearRect(0, 0, canvas[i].width, canvas[i].height); preview.style.width = imgs[i].width + "px"; preview.style.height = imgs[i].height + "px"; canvas[i].width = imgs[i].width; canvas[i].height = imgs[i].height; ctx[i].drawImage(imgs[i], 0, 0, imgs[i].width, imgs[i].height); // do all you need with each new canvas canvas } }