2012-09-22 7 views
13

IOS6 è stato rilasciato ed è stato testato il caricamento delle foto.Caricamento foto IOS6 e Safari - File API + Canvas + jQuery Ajax Caricamento e ridimensionamento dei file in modo asincrono

Funziona bene, ma con immagini più grandi su 3G è LENTO come previsto.

Grazie a File API e Canvas, è possibile ridimensionare le immagini utilizzando JavaScript. Spero che se ridimensioni le immagini prima che tenti di caricarle, verranno caricate più velocemente, prestandosi a una rapida esperienza utente. Con i processori smartphone che migliorano esponenzialmente più velocemente delle velocità della rete, credo che questa soluzione sia vincente.

Nicolas ha offerto una soluzione eccellente per il ridimensionamento delle immagini:

Image resize before upload

Tuttavia, sto avendo il momento più difficile attuazione con l'Ajax di jQuery. Qualsiasi consiglio o aiuto è apprezzato, in quanto questo codice sarà probabilmente estremamente utile per lo sviluppo di applicazioni Web mobili post-IOS6.

var fileType = file.type, 
    reader = new FileReader(); 

reader.onloadend = function() { 
    var image = new Image(); 
    image.src = reader.result; 

    image.onload = function() { 

     //Detect image size 
     var maxWidth = 960, 
      maxHeight = 960, 
      imageWidth = image.width, 
      imageHeight = image.height; 
     if (imageWidth > imageHeight) { 
      if (imageWidth > maxWidth) { 
       imageHeight *= maxWidth/imageWidth; 
       imageWidth = maxWidth; 
      } 
     } else { 
      if (imageHeight > maxHeight) { 
       imageWidth *= maxHeight/imageHeight; 
       imageHeight = maxHeight; 
      } 
     } 

     //Create canvas with new image 
     var canvas = document.createElement('canvas'); 
     canvas.width = imageWidth; 
     canvas.height = imageHeight; 
     var ctx = canvas.getContext("2d"); 
     ctx.drawImage(this, 0, 0, imageWidth, imageHeight); 

     // The resized file ready for upload 
     var finalFile = canvas.toDataURL(fileType); 

     if (formdata) { 

      formdata.append("images[]", finalFile); 

      $.ajax({ 
       url: "upload.php", 
       type: "POST", 
       data: formdata, 
       dataType: 'json', 
       processData: false, 
       contentType: false, 
       success: function (res) { 
        //successful image upload 
       } 
      }); 

     } 
    } 
} 
reader.readAsDataURL(file); 
+0

Avete trovato una soluzione a questo? Ho scoperto che è più problematico ridimensionare immagini di grandi dimensioni direttamente dalla fotocamera o quelle che sono state riprese dalla fotocamera in passato. – NimmoNet

risposta

31

Ho appena sviluppato un plugin jQuery per lato client canvas ridimensionamento immagine. Gestisce anche l'orientamento e l'immagine iOS6 schiacciata.

Si può provare: http://gokercebeci.com/dev/canvasresize

Usage:

$.canvasResize(file, { 
       width : 300, 
       height : 0, 
       crop : false, 
       quality : 80, 
       callback: function(dataURL, width, height){ 

         // your code 

       } 
}); 
+1

questo è fantastico. +10 se potessi. Ci sto lavorando da settimane – TaylorMac

+0

http://camronjs.herokuapp.com ridimensiona canvas, websocket e ajax upload safari mobile e browser. – chrisallick

7

Ho lavorato con la funzione di caricamento dalla seconda versione beta di iOS6. Il seguente codice funziona per me:

mettere questo nella testa della pagina HTML -

<script>window.onload = function() { 
var canvas = document.createElement('canvas'); 
var ctx = canvas.getContext("2d"); 

var fileSelect = document.getElementById("fileSelect"), 
    input = document.getElementById("input"); 

    input.addEventListener("change", handleFiles); 

    //hides ugly default file input button 
    fileSelect.addEventListener("click", function (e) { 
     if (input) { 
      input.click(); 
     } 
     e.preventDefault(); 
    }, false); 

function handleFiles(e) { 
    var reader = new FileReader; 
    reader.onload = function (event) { 
     var img = new Image(); 
     img.src = reader.result; 
     img.onload = function() { 
      var maxWidth = 320, 
       maxHeight = 350, 
       imageWidth = img.width, 
       imageHeight = img.height; 

      if (imageWidth > imageHeight) { 
       if (imageWidth > maxWidth) { 
        imageHeight *= maxWidth/imageWidth; 
        imageWidth = maxWidth; 
       } 
      } else { 
       if (imageHeight > maxHeight) { 
        imageWidth *= maxHeight/imageHeight; 
        imageHeight = maxHeight; 
       } 
      } 
      canvas.width = imageWidth; 
      canvas.height = imageHeight; 

      ctx.drawImage(this, 0, 0, imageWidth, imageHeight); 

      // The resized file ready for upload 
      var finalFile = canvas.toDataURL("image/png"); 

      var postData = 'canvasData=' + finalFile; 
      var ajax = new XMLHttpRequest(); 
      ajax.open('POST', 'save.php', true); 
      ajax.setRequestHeader('Content-Type', 'canvas/upload'); 

      ajax.onreadystatechange = function() { 
       if (ajax.readyState == 4) { 
        //just to visually confirm it worked... 
        window.open(canvas.toDataURL("image/png"), "mywindow"); 
       } 
      } 
      ajax.send(postData); 
     } 
    } 
    reader.readAsDataURL(e.target.files[0]); 
} 
} 
</script> 

Ecco il codice HTML -

<div style="width:320px;position:absolute;z-index:9;top:387px;"> 
<button style="width:60px;" id="fileSelect">upload</button> 
<input type="file" id="input" name="input" accept="image/*" style="display:none;"></div> 

Ecco il PHP -

<?php 
if (isset($GLOBALS["HTTP_RAW_POST_DATA"])) 
{ 
    // Get the data 
    $imageData=$GLOBALS['HTTP_RAW_POST_DATA']; 

    // Remove the headers (data:,) part. 
    // A real application should use them according to needs such as to check image type 
    $filteredData=substr($imageData, strpos($imageData, ",")+1); 

    // Need to decode before saving since the data we received is already base64 encoded 
    $unencodedData=base64_decode($filteredData); 

    // Save file. This example uses a hard coded filename for testing, 
    // but a real application can specify filename in POST variable 
    $fp = fopen('users/user_photo.png', 'wb'); 
    fwrite($fp, $unencodedData); 
    fclose($fp); 
} 
?> 

L'unico problema con cui ho combattuto è quello di caricare le immagini dalla fotocamera senza essere ruotate di 90 gradi.

Spero che questo aiuti, fammi sapere se hai qualche problema con il codice (è il mio primo post).

+0

Fantastico. Lavorerò con il codice e vedrò se riesco a trovare una soluzione per la rotazione di 90 gradi. Qualcun altro ha una soluzione per questo? – TaylorMac

+2

Hai trovato questa soluzione per funzionare su iPhone IO6 con le foto scattate dalla fotocamera. Ho trovato che qualsiasi immagine che viene ridimensionata usando questo metodo funziona, ma l'immagine è schiacciata e non come previsto. – NimmoNet

+0

Dai un'occhiata a questa implementazione. Funziona bene su Chrome su un normale sistema operativo ma su iOS quando ridimensiono l'immagine fa qualcosa di strano http://jsfiddle.net/Untd8/ – NimmoNet

1

Dato che abbiamo a che fare con le immagini di grandi dimensioni e problemi di memoria su un browser mobile, volevo vedere se una soluzione leggera possibile essere trovato che evita la creazione di una tela duplicata e l'esecuzione di altre operazioni di immagine solo per il rilevamento e il ridimensionamento.

Sembra che se Mobile Safari esegue uno schiacciamento verticale di un'immagine troppo grande, il rapporto di quanto lo fa rimane uguale.

Così adesso prima ancora di rendere l'immagine sulla tela, io uso una regola molto veloce empirica per cui ho semplicemente verificare se il browser è un iDevice cellulare navigator.userAgent.match(/(iPod|iPhone|iPad)/) ...E l'altezza o larghezza dell'immagine è maggiore di 2000 pixel, nel qual caso so che sarà schiacciato. In tal caso, in canvasContext.drawImage(), specifica l'altezza dell'immagine per essere 4x più alta di quello che avrebbe dovuto essere normalmente per un obiettivo di ridimensionamento di una data immagine. Basandomi su ciò che ho visto, Mobile Safari schiaccia l'immagine di un fattore di 4.

THEN Rendo l'immagine, e la renderò non distorta la prima volta, schiacciando un'immagine pre-tesa indietro in quello che poi diventa una proporzione X: Y normale. Senza ulteriori elementi canvas o contesti o rendering di test o iterazioni di pixel che utilizza una soluzione al 100% sopra menzionata.

Sono sicuro che potrebbero esserci alcuni casi limite e il limite per le dimensioni dell'immagine potrebbe non essere esatto, ma per la mia app volevo una soluzione che fosse VELOCE.

Problemi correlati